VirtualBox

Changeset 73421 in vbox for trunk/src


Ignore:
Timestamp:
Aug 1, 2018 12:46:06 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
124043
Message:

Audio: (Pre-)Buffering fixes; use nanoseconds to have a higher resolution when it comes to calculating the transfer sizes.

Location:
trunk/src/VBox/Devices/Audio
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/AudioMixer.cpp

    r73408 r73421  
    922922        return 0;
    923923
     924    const uint64_t deltaLastReadWriteNs = RTTimeNanoTS() - pSink->tsLastReadWrittenNs;
     925
    924926    uint32_t cbWritable = 0;
    925927
     
    931933#else
    932934        /* Return how much data we expect since the last write. */
    933         cbWritable = DrvAudioHlpMilliToBytes(RTTimeMilliTS() - pSink->tsLastReadWrittenMs, &pSink->PCMProps);
     935        cbWritable = DrvAudioHlpNanoToBytes(deltaLastReadWriteNs, &pSink->PCMProps);
     936        cbWritable = DrvAudioHlpBytesAlign(cbWritable, &pSink->PCMProps);
    934937#endif
    935938    }
    936939
    937     Log3Func(("[%s] cbWritable=%RU32\n", pSink->pszName, cbWritable));
     940    Log3Func(("Mixer: [%s] cbWritable=%RU32 (%RU64ms)\n", pSink->pszName, cbWritable, deltaLastReadWriteNs / RT_NS_1MS_64));
    938941
    939942    int rc2 = RTCritSectLeave(&pSink->CritSect);
     
    11581161
    11591162            /* Update our last read time stamp. */
    1160             pSink->tsLastReadWrittenMs = RTTimeMilliTS();
     1163            pSink->tsLastReadWrittenNs = RTTimeNanoTS();
    11611164
    11621165#ifdef VBOX_AUDIO_MIXER_DEBUG
     
    17391742
    17401743            cbWritten += (uint32_t)cbChunk;
     1744            Assert(cbWritten <= cbBuf);
    17411745
    17421746            Assert(cbToWrite >= cbChunk);
     
    17451749
    17461750        if (cbWritten < cbBuf)
     1751        {
    17471752            LogFunc(("[%s] Warning: Only written %RU32/%RU32 bytes for stream '%s'\n",
    17481753                     pSink->pszName, cbWritten, cbBuf, pMixStream->pszName));
    1749 
    1750         if (!pMixStream->tsLastReadWrittenMs)
    1751             pMixStream->tsLastReadWrittenMs = RTTimeMilliTS();
    1752 
    1753         pMixStream->tsLastReadWrittenMs = RTTimeMilliTS();
    1754 
    1755         const uint32_t cbWritableStream = pMixStream->pConn->pfnStreamGetWritable(pMixStream->pConn, pMixStream->pStream);
    1756         cbToWrite = RT_MIN(cbWritableStream, (uint32_t)RTCircBufUsed(pCircBuf));
     1754            LogRel2(("Audio: Buffer overrun for mixer sink '%s', stream '%s'\n", pSink->pszName, pMixStream->pszName));
     1755#ifdef DEBUG_andy
     1756            AssertFailed();
     1757#endif
     1758        }
     1759
     1760        if (cbWritten) /* Update the mixer stream's last written time stamp. */
     1761            pMixStream->tsLastReadWrittenNs = RTTimeNanoTS();
     1762
     1763        cbToWrite = RT_MIN(pMixStream->pConn->pfnStreamGetWritable(pMixStream->pConn, pMixStream->pStream),
     1764                           (uint32_t)RTCircBufUsed(pCircBuf));
     1765        cbToWrite = DrvAudioHlpBytesAlign(cbToWrite, &pSink->PCMProps);
    17571766
    17581767        int rc2 = VINF_SUCCESS;
     
    17741783            if (   !cbWritten
    17751784                || cbWritten < cbChunk)
     1785            {
     1786#ifdef DEBUG_andy
     1787                AssertFailed();
     1788#endif
    17761789                break;
     1790            }
    17771791
    17781792            if (RT_FAILURE(rc2))
     
    17901804    }
    17911805
    1792     /* Update our last written time stamp. */
    1793     pSink->tsLastReadWrittenMs = RTTimeMilliTS();
     1806    /* Update the sink's last written time stamp. */
     1807    pSink->tsLastReadWrittenNs = RTTimeNanoTS();
    17941808
    17951809    if (pcbWritten)
  • trunk/src/VBox/Devices/Audio/AudioMixer.h

    r73403 r73421  
    7272    /** Pointer to PDM audio stream this mixer stream handles. */
    7373    PPDMAUDIOSTREAM         pStream;
    74     /** Last read (recording) / written (playback) timestamp (in ms). */
    75     uint64_t                tsLastReadWrittenMs;
     74    /** Last read (recording) / written (playback) timestamp (in ns). */
     75    uint64_t                tsLastReadWrittenNs;
    7676    /** The stream's circular buffer for temporarily
    7777     *  holding (raw) device audio data. */
     
    203203    /** Timestamp since last update (in ms). */
    204204    uint64_t                tsLastUpdatedMs;
    205     /** Last read (recording) / written (playback) timestamp (in ms). */
    206     uint64_t                tsLastReadWrittenMs;
     205    /** Last read (recording) / written (playback) timestamp (in ns). */
     206    uint64_t                tsLastReadWrittenNs;
    207207#ifdef VBOX_AUDIO_MIXER_DEBUG
    208208    struct
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r73408 r73421  
    666666     */
    667667
     668    /* Check if the backend did return sane values and correct if necessary.
     669     * Should never happen with our own backends, but you never know ... */
     670    if (CfgHostAcq.Backend.cfBufferSize < CfgHostAcq.Backend.cfPreBuf)
     671    {
     672        LogRel2(("Audio: Warning: Pre-buffering size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), "
     673                 "setting pre-buffering size to %RU32 frames\n",
     674                 CfgHostAcq.Backend.cfPreBuf, pHstStream->szName, CfgHostAcq.Backend.cfBufferSize, CfgHostAcq.Backend.cfBufferSize));
     675        CfgHostAcq.Backend.cfPreBuf = CfgHostAcq.Backend.cfBufferSize;
     676    }
     677
     678    if (CfgHostAcq.Backend.cfPeriod > CfgHostAcq.Backend.cfBufferSize)
     679    {
     680        LogRel2(("Audio: Warning: Period size (%RU32 frames) of stream '%s' does not match buffer size (%RU32 frames), setting to %RU32 frames\n",
     681                 CfgHostAcq.Backend.cfPeriod, pHstStream->szName, CfgHostAcq.Backend.cfBufferSize, CfgHostAcq.Backend.cfBufferSize));
     682        CfgHostAcq.Backend.cfPeriod = CfgHostAcq.Backend.cfBufferSize;
     683    }
     684
     685    uint32_t msBufferSize = DrvAudioHlpFramesToMilli(CfgHostAcq.Backend.cfBufferSize, &pCfgHost->Props);
     686
     687    LogRel2(("Audio: Buffer size of stream '%s' is %RU32ms (%RU32 frames)\n",
     688             pHstStream->szName, msBufferSize, CfgHostAcq.Backend.cfBufferSize));
     689
    668690    /* If no own pre-buffer is set, let the backend choose. */
    669691    uint32_t msPreBuf = DrvAudioHlpFramesToMilli(CfgHostAcq.Backend.cfPreBuf, &pCfgHost->Props);
     
    676698    LogRel2(("Audio: Period size of stream '%s' is %RU32ms (%RU32 frames)\n",
    677699             pHstStream->szName, msPeriod, CfgHostAcq.Backend.cfPeriod));
    678 
    679     /* Check if the backend did return sane values and correct if necessary. */
    680     if (CfgHostAcq.Backend.cfBufferSize < CfgHostAcq.Backend.cfPeriod)
    681     {
    682         LogRel2(("Audio: Warning: Backend of stream '%s' did not set a valid buffer size (%RU32 frames), setting to %RU32 frames",
    683                  pHstStream->szName, CfgHostAcq.Backend.cfBufferSize, CfgHostAcq.Backend.cfPeriod));
    684         AssertFailed(); /* Should never happen. */
    685     }
    686 
    687     uint32_t msBufferSize = DrvAudioHlpFramesToMilli(CfgHostAcq.Backend.cfBufferSize, &pCfgHost->Props);
    688 
    689     LogRel2(("Audio: Buffer size of stream '%s' is %RU32ms (%RU32 frames)\n",
    690              pHstStream->szName, msBufferSize, CfgHostAcq.Backend.cfBufferSize));
    691700
    692701    /* Set set host buffer size multiplicator. */
     
    974983        AssertPtr(pGstStream);
    975984
     985        AssertMsg(DrvAudioHlpBytesIsAligned(cbBuf, &pGstStream->Cfg.Props),
     986                  ("Writing audio data (%RU32 bytes) to stream '%s' is not properly aligned\n", cbBuf, pGstStream->szName));
     987
    976988#ifdef LOG_ENABLED
    977989        pszGstSts = dbgAudioStreamStatusToStr(pGstStream->fStatus);
     
    9911003
    9921004        const uint32_t cbFree = AudioMixBufFreeBytes(&pHstStream->MixBuf);
    993         if (cbFree < cbBuf) /* No space left on host side? Bail out. */
    994             LogRel2(("Audio: Lost audio frames (%RU32) due to full host stream '%s', expect stuttering audio output\n",
    995                      DrvAudioHlpBytesToFrames(cbBuf - cbFree, &pHstStream->Cfg.Props), pHstStream->szName));
     1005        if (cbFree < cbBuf)
     1006            LogRel2(("Audio: Lost audio output (%RU64ms, %RU32 free but needs %RU32) due to full host stream buffer '%s'\n",
     1007                     DrvAudioHlpBytesToMilli(cbBuf - cbFree, &pHstStream->Cfg.Props), cbFree, cbBuf, pHstStream->szName));
    9961008
    9971009        uint32_t cbToWrite = RT_MIN(cbBuf, cbFree);
     
    10011013        if (!cbToWrite)
    10021014            break;
    1003 
    1004         uint64_t tsDeltaWrittenMs = RTTimeMilliTS() - pHstStream->tsLastReadWrittenMs;
    1005 
    1006         Log3Func(("[%s] fThresholdReached=%RTbool, tsDeltaWrittenMs=%RU64\n",
    1007                   pHstStream->szName, pHstStream->fThresholdReached, tsDeltaWrittenMs));
    1008 
    1009         if (   pHstStream->fThresholdReached
    1010             && tsDeltaWrittenMs < pGstStream->Cfg.Device.uSchedulingHintMs)
    1011         {
    1012             break;
    1013         }
    10141015
    10151016        /* We use the guest side mixing buffer as an intermediate buffer to do some
     
    10431044            else
    10441045            {
    1045                 Log3Func(("[%s] Buffer: Last written %RU64ms, writing %RU32 frames (%RU64ms), now filled with %RU64ms -- %RU8%%\n",
    1046                           pHstStream->szName, tsDeltaWrittenMs, cfGstWritten, DrvAudioHlpFramesToMilli(cfGstWritten, &pHstStream->Cfg.Props),
     1046                Log3Func(("[%s] Buffer: Writing %RU32 frames (%RU64ms), now filled with %RU64ms -- %RU8%%\n",
     1047                          pHstStream->szName, cfGstWritten, DrvAudioHlpFramesToMilli(cfGstWritten, &pHstStream->Cfg.Props),
    10471048                          DrvAudioHlpFramesToMilli(AudioMixBufUsed(&pHstStream->MixBuf), &pHstStream->Cfg.Props),
    10481049                          AudioMixBufUsed(&pHstStream->MixBuf) * 100 / AudioMixBufSize(&pHstStream->MixBuf)));
    10491050
    1050                 pHstStream->tsLastReadWrittenMs = RTTimeMilliTS();
     1051                pHstStream->tsLastReadWrittenNs = RTTimeNanoTS();
    10511052
    10521053                /* Keep going. */
     
    10571058
    10581059            cbWrittenTotal = AUDIOMIXBUF_F2B(&pGstStream->MixBuf, cfGstWritten);
     1060#ifdef DEBUG
     1061            if (pHstStream->fThresholdReached)
     1062                pHstStream->Out.Dbg.cbJitterWrittenPlayed += cbWrittenTotal;
     1063#endif
    10591064
    10601065#ifdef VBOX_WITH_STATISTICS
     
    13001305
    13011306    /* Update timestamps. */
    1302     pGstStream->tsLastIteratedMs = RTTimeMilliTS();
     1307    pGstStream->tsLastIteratedNs = RTTimeNanoTS();
    13031308
    13041309    if (RT_FAILURE(rc))
     
    13751380
    13761381    AssertPtr(pThis->pHostDrvAudio->pfnStreamGetWritable);
    1377     uint32_t cbWritable = pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pHstStream->pvBackend);
    1378     if (cbWritable)
    1379     {
    1380         if (cfToPlay > AUDIOMIXBUF_B2F(&pHstStream->MixBuf, cbWritable)) /* More frames available than we can write? Limit. */
    1381             cfToPlay = AUDIOMIXBUF_B2F(&pHstStream->MixBuf, cbWritable);
     1382    uint32_t cfWritable = AUDIOMIXBUF_B2F(&pHstStream->MixBuf,
     1383                                          pThis->pHostDrvAudio->pfnStreamGetWritable(pThis->pHostDrvAudio, pHstStream->pvBackend));
     1384
     1385    Log3Func(("[%s] cfToPlay=%RU32 (%RU64ms), cfWritable=%RU32 (%RU64ms)\n", pHstStream->szName,
     1386              cfToPlay, DrvAudioHlpFramesToMilli(cfToPlay, &pHstStream->Cfg.Props),
     1387              cfWritable, DrvAudioHlpFramesToMilli(cfWritable, &pHstStream->Cfg.Props)));
     1388
     1389    if (cfWritable)
     1390    {
     1391        if (cfToPlay > cfWritable) /* More frames available than we can write? Limit. */
     1392            cfToPlay = cfWritable;
    13821393
    13831394        if (cfToPlay)
     
    13851396            uint8_t auBuf[256]; /** @todo Get rid of this here. */
    13861397
    1387             uint32_t cbLeft  = AUDIOMIXBUF_F2B(&pHstStream->MixBuf, cfToPlay);
     1398            uint32_t cfLeft  = cfToPlay;
    13881399            uint32_t cbChunk = sizeof(auBuf);
    13891400
    1390             while (cbLeft)
     1401            while (cfLeft)
    13911402            {
    13921403                uint32_t cfRead = 0;
    1393                 rc = AudioMixBufAcquireReadBlock(&pHstStream->MixBuf, auBuf, RT_MIN(cbChunk, cbLeft), &cfRead);
     1404                rc = AudioMixBufAcquireReadBlock(&pHstStream->MixBuf, auBuf, RT_MIN(cbChunk, AUDIOMIXBUF_F2B(&pHstStream->MixBuf, cfLeft)), &cfRead);
    13941405                if (RT_FAILURE(rc))
    13951406                    break;
     
    14091420
    14101421                    if (cbRead != cbPlayed)
    1411                         LogRel2(("Audio: Host stream '%s' played wrong amount (%RU32 bytes read but played %RU32 (%RI32), writable was %RU32)\n",
    1412                                  pHstStream->szName, cbRead, cbPlayed, cbRead - cbPlayed, cbWritable));
     1422                        LogRel2(("Audio: Host stream '%s' played wrong amount (%RU32 bytes read but played %RU32)\n",
     1423                                 pHstStream->szName, cbRead, cbPlayed));
    14131424
    14141425                    cfPlayed       = AUDIOMIXBUF_B2F(&pHstStream->MixBuf, cbPlayed);
    14151426                    cfPlayedTotal += cfPlayed;
    14161427
    1417                     Assert(cbLeft >= cbPlayed);
    1418                     cbLeft        -= cbPlayed;
     1428                    Assert(cfLeft >= cfPlayed);
     1429                    cfLeft        -= cfPlayed;
    14191430                }
    14201431
     
    15761587#ifdef LOG_ENABLED
    15771588    char *pszStreamSts = dbgAudioStreamStatusToStr(stsHstStream);
    1578     Log3Func(("[%s] Start: stsHstStream=%s\n", pHstStream->szName, pszStreamSts));
     1589    Log3Func(("[%s] Buffer: Start stsHstStream=%s\n", pHstStream->szName, pszStreamSts));
    15791590    RTStrFree(pszStreamSts);
    15801591#endif /* LOG_ENABLED */
     
    15911602        const uint8_t  uLivePercent = (100 * cfLive) / AudioMixBufSize(&pHstStream->MixBuf);
    15921603
    1593         if (!pHstStream->tsLastPlayedCapturedMs)
    1594             pHstStream->tsLastPlayedCapturedMs = RTTimeMilliTS();
    1595         uint64_t tsDeltaPlayedCapturedMs = RTTimeMilliTS() - pHstStream->tsLastPlayedCapturedMs;
    1596         pHstStream->tsLastPlayedCapturedMs = RTTimeMilliTS();
    1597 
    1598 #ifdef LOG_ENABLED
    1599         Log3Func(("[%s] Buffer: Last played %RU64ms, filled with %RU64ms (%RU8%%) total, "
     1604        const uint64_t tsDeltaPlayedCapturedNs = RTTimeNanoTS() - pHstStream->tsLastPlayedCapturedNs;
     1605
     1606        pHstStream->tsLastPlayedCapturedNs = RTTimeNanoTS();
     1607
     1608        Log3Func(("[%s] Buffer: Last played %RU64ns (%RU64ms), filled with %RU64ms (%RU8%%) total, "
    16001609                  "(cfLive=%RU32, fThresholdReached=%RTbool)\n",
    1601                   pHstStream->szName, tsDeltaPlayedCapturedMs, DrvAudioHlpFramesToMilli(cfLive, &pHstStream->Cfg.Props),
     1610                  pHstStream->szName, tsDeltaPlayedCapturedNs, tsDeltaPlayedCapturedNs / RT_NS_1MS_64,
     1611                  DrvAudioHlpFramesToMilli(cfLive, &pHstStream->Cfg.Props),
    16021612                  uLivePercent, cfLive, pHstStream->fThresholdReached));
    1603 #endif
     1613
    16041614        bool fDoPlay      = pHstStream->fThresholdReached;
    16051615        bool fJustStarted = false;
     
    16121622                fDoPlay = true;
    16131623            }
    1614 
    16151624            /* Some audio files are shorter than the pre-buffering level (e.g. the "click" Explorer sounds on some Windows guests),
    16161625             * so make sure that we also play those by checking if the stream already is pending disable mode, even if we didn't
     
    16181627             *
    16191628             * To reproduce, use "Windows Navigation Start.wav" on Windows 7 (2824 samples). */
    1620             if (   cfLive
    1621                 && pHstStream->fStatus & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE)
     1629            else if (   cfLive
     1630                     && pHstStream->fStatus & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE)
    16221631            {
    16231632                LogRel2(("Audio: Stream '%s' buffering complete (short sound)\n", pHstStream->szName));
     
    16381647        if (fDoPlay)
    16391648        {
    1640             if (pHstStream->tsLastPlayedCapturedMs < 2)
    1641                 break;
    1642 
    1643             uint32_t cfToPlay;
     1649            uint32_t cfToPlay = 0;
    16441650            if (fJustStarted)
    1645                 cfToPlay = pHstStream->Cfg.Backend.cfPeriod;
    1646             else
    1647                 cfToPlay = DrvAudioHlpMilliToFrames(tsDeltaPlayedCapturedMs, &pHstStream->Cfg.Props);
    1648 
    1649             Log3Func(("[%s] Buffer: fJustStarted=%RTbool, cfLive=%RU32, cfToPlay=%RU32\n",
     1651                cfToPlay = pHstStream->Cfg.Backend.cfPeriod; /* cfPeriod can be 0. */
     1652
     1653            if (!cfToPlay)
     1654            {
     1655                cfToPlay = DrvAudioHlpNanoToFrames(tsDeltaPlayedCapturedNs, &pHstStream->Cfg.Props);
     1656                if (pHstStream->Cfg.Device.uSchedulingHintMs)
     1657                    cfToPlay = RT_MIN(cfToPlay, DrvAudioHlpMilliToFrames(pHstStream->Cfg.Device.uSchedulingHintMs, &pHstStream->Cfg.Props));
     1658            }
     1659
     1660            LogRelFunc(("[%s] Buffer: fJustStarted=%RTbool, cfLive=%RU32, cfToPlay=%RU32\n",
    16501661                      pHstStream->szName, fJustStarted, cfLive, cfToPlay));
    16511662
     
    16531664             * If we're in pending disabled mode, try to play (drain) the remaining audio data. */
    16541665            if (   !(pHstStream->fStatus & PDMAUDIOSTREAMSTS_FLAG_PENDING_DISABLE)
    1655                 && !fJustStarted
    1656                 && cfLive < cfToPlay)
     1666                && !fJustStarted)
    16571667            {
    1658                 pHstStream->fThresholdReached = false;
    1659                 LogRel2(("Audio: Stream '%s' buffer underrun (total %RU8%%, which is %RU8%% of a period), buffering ...\n",
    1660                          pHstStream->szName, uLivePercent, (100 * cfLive) / pHstStream->Cfg.Backend.cfPeriod));
    1661                 break;
     1668                if (cfLive < cfToPlay)
     1669                {
     1670                    pHstStream->fThresholdReached = false;
     1671                    Log3Func(("[%s] Buffer: Underrun (cfLive=%RU32, cfToPlay=%RU32)\n", pHstStream->szName, cfLive, cfToPlay));
     1672                    LogRel2(("Audio: Stream '%s' buffer underrun (total %RU8%%, which is %RU8%% of a period), buffering ...\n",
     1673                             pHstStream->szName, uLivePercent, (100 * cfLive) / pHstStream->Cfg.Backend.cfPeriod));
     1674                    break;
     1675                }
    16621676            }
    16631677
     
    16651679                cfToPlay = cfLive;
    16661680
    1667             Log3Func(("[%s] Buffer: Playing %RU32 frames (%RU64ms since last playback)\n",
    1668                       pHstStream->szName, cfToPlay, tsDeltaPlayedCapturedMs));
    1669 
     1681            if (!cfToPlay)
     1682                break;
     1683#ifdef DEBUG
     1684            if (!fJustStarted)
     1685                pHstStream->Out.Dbg.cbJitterWrittenPlayed -= AUDIOMIXBUF_F2B(&pHstStream->MixBuf, cfToPlay);
     1686            Log3Func(("[%s] Buffer: Playing %RU32 frames (%RU64ms), now filled with %RU64ms -- %RU8%% (cbJitterWrittenPlayed=%RI64)\n",
     1687                      pHstStream->szName, cfToPlay, DrvAudioHlpFramesToMilli(cfToPlay, &pHstStream->Cfg.Props),
     1688                      DrvAudioHlpFramesToMilli(AudioMixBufUsed(&pHstStream->MixBuf), &pHstStream->Cfg.Props),
     1689                      AudioMixBufUsed(&pHstStream->MixBuf) * 100 / AudioMixBufSize(&pHstStream->MixBuf),
     1690                      pHstStream->Out.Dbg.cbJitterWrittenPlayed));
     1691#endif
    16701692            if (pThis->pHostDrvAudio->pfnStreamPlayBegin)
    16711693                pThis->pHostDrvAudio->pfnStreamPlayBegin(pThis->pHostDrvAudio, pHstStream->pvBackend);
     
    17021724    uint32_t cfLive = AudioMixBufLive(&pHstStream->MixBuf);
    17031725    pszStreamSts  = dbgAudioStreamStatusToStr(stsHstStream);
    1704     Log3Func(("[%s] End: stsHstStream=%s, cfLive=%RU32, cfPlayedTotal=%RU32, rc=%Rrc\n",
     1726    Log3Func(("[%s] Buffer: End stsHstStream=%s, cfLive=%RU32, cfPlayedTotal=%RU32, rc=%Rrc\n",
    17051727              pHstStream->szName, pszStreamSts, cfLive, cfPlayedTotal, rc));
    17061728    RTStrFree(pszStreamSts);
     
    30363058
    30373059    /* As the host side sets the overall pace, return the writable bytes from that side. */
    3038     uint32_t cbWritable = AudioMixBufFreeBytes(&pHstStream->MixBuf);
    3039 
    3040     Log3Func(("[%s] cbWritable=%RU32\n", pHstStream->szName, cbWritable));
     3060    const uint64_t deltaLastReadWriteNs = RTTimeNanoTS() - pHstStream->tsLastReadWrittenNs;
     3061
     3062    uint32_t cbWritable = DrvAudioHlpNanoToBytes(deltaLastReadWriteNs, &pHstStream->Cfg.Props);
     3063    cbWritable = DrvAudioHlpBytesAlign(cbWritable, &pHstStream->Cfg.Props);
     3064
     3065    Log3Func(("Audio: [%s] cbWritable=%RU32 (%RU64ms)\n", pHstStream->szName, cbWritable, deltaLastReadWriteNs / RT_NS_1MS_64));
    30413066
    30423067    rc2 = RTCritSectLeave(&pThis->CritSect);
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette