VirtualBox

Changeset 88376 in vbox for trunk/src/VBox/Devices/Audio


Ignore:
Timestamp:
Apr 6, 2021 8:35:18 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143623
Message:

DrvHostAudioDSound.cpp: Ripped out the extra ~600ms buffering. When asked to DRAIN the backend, try switch the buffer to non-looping mode so that it will stop when it's done (may need to clear the rest, not sure). Don't RESUME disabled streams - this worked because we used to fill the buffer with silence upon disabling a stream (no longer true with new draining code). bugref:9890

File:
1 edited

Legend:

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

    r88371 r88376  
    125125    bool                fEnabled;
    126126    bool                afPadding[2];
    127     /** Size (in bytes) of the DirectSound buffer.
    128      *  @note This in *not* the size of the circular buffer above! */
     127    /** Size (in bytes) of the DirectSound buffer. */
    129128    DWORD               cbBufSize;
    130129    /** The stream's critical section for synchronizing access. */
    131130    RTCRITSECT          CritSect;
    132     /** The internal playback / capturing buffer. */
    133     PRTCIRCBUF          pCircBuf;
    134131    union
    135132    {
     
    149146             *  This is a secondary buffer and is used as a streaming buffer. */
    150147            LPDIRECTSOUNDBUFFER8        pDSB;
    151             /** Current write offset (in bytes) within the DSB. */
     148            /** Current write offset (in bytes) within the DSB.
     149             * @note This is needed as the current write position as kept by direct sound
     150             *       will move ahead if we're too late. */
    152151            DWORD                       offWritePos;
    153152            /** Offset of last play cursor within the DSB when checked for pending. */
     
    282281 * Retrieves the number of free bytes available for writing to a DirectSound output stream.
    283282 *
    284  * @return  IPRT status code. VERR_NOT_AVAILABLE if unable to determine or the buffer was not recoverable.
     283 * @return  VBox status code. VERR_NOT_AVAILABLE if unable to determine or the
     284 *          buffer was not recoverable.
    285285 * @param   pThis               Host audio driver instance.
    286286 * @param   pStreamDS           DirectSound output stream to retrieve number for.
    287287 * @param   pdwFree             Where to return the free amount on success.
    288  */
    289 static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree)
     288 * @param   poffPlayCursor      Where to return the play cursor offset.
     289 */
     290static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree, DWORD *poffPlayCursor)
    290291{
    291292    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
    292293    AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER);
    293294    AssertPtrReturn(pdwFree,   VERR_INVALID_POINTER);
     295    AssertPtr(poffPlayCursor);
    294296
    295297    Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT); /* Paranoia. */
     
    307309    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
    308310    {
    309         DWORD cbPlayCursor, cbWriteCursor;
    310         hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayCursor, &cbWriteCursor);
     311        DWORD offPlayCursor  = 0;
     312        DWORD offWriteCursor = 0;
     313        hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);
    311314        if (SUCCEEDED(hr))
    312315        {
    313             int32_t cbDiff = cbWriteCursor - cbPlayCursor;
     316            int32_t cbDiff = offWriteCursor - offPlayCursor;
    314317            if (cbDiff < 0)
    315318                cbDiff += pStreamDS->cbBufSize;
    316319
    317             int32_t cbFree = cbPlayCursor - pStreamDS->Out.offWritePos;
     320            int32_t cbFree = offPlayCursor - pStreamDS->Out.offWritePos;
    318321            if (cbFree < 0)
    319322                cbFree += pStreamDS->cbBufSize;
     
    321324            if (cbFree > (int32_t)pStreamDS->cbBufSize - cbDiff)
    322325            {
    323                 pStreamDS->Out.offWritePos = cbWriteCursor;
     326                /** @todo count/log these. */
     327                pStreamDS->Out.offWritePos = offWriteCursor;
    324328                cbFree = pStreamDS->cbBufSize - cbDiff;
    325329            }
    326330
    327             /* When starting to use a DirectSound buffer, cbPlayCursor and cbWriteCursor
     331            /* When starting to use a DirectSound buffer, offPlayCursor and offWriteCursor
    328332             * both point at position 0, so we won't be able to detect how many bytes
    329333             * are writable that way.
     
    333337                cbFree = pStreamDS->cbBufSize;
    334338
    335             DSLOGREL(("DSound: cbPlayCursor=%RU32, cbWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",
    336                       cbPlayCursor, cbWriteCursor, pStreamDS->Out.offWritePos, cbFree));
     339            DSLOGREL(("DSound: offPlayCursor=%RU32, offWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",
     340                      offPlayCursor, offWriteCursor, pStreamDS->Out.offWritePos, cbFree));
    337341
    338342            *pdwFree = cbFree;
    339 
     343            *poffPlayCursor = offPlayCursor;
    340344            return VINF_SUCCESS;
    341345        }
     
    354358    LogFunc(("Failed with %Rhrc\n", hr));
    355359
     360    *poffPlayCursor = pStreamDS->cbBufSize;
    356361    return VERR_NOT_AVAILABLE;
    357362}
     
    571576
    572577    HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
    573     if (FAILED(hr))
    574         return hr;
    575 
    576     DSLOG(("DSound: Closing playback stream\n"));
    577 
    578     if (pStreamDS->pCircBuf)
    579         Assert(RTCircBufUsed(pStreamDS->pCircBuf) == 0);
    580 
    581578    if (SUCCEEDED(hr))
    582579    {
     580        DSLOG(("DSound: Closing playback stream\n"));
    583581        RTCritSectEnter(&pThis->CritSect);
    584 
    585         if (pStreamDS->pCircBuf)
    586         {
    587             RTCircBufDestroy(pStreamDS->pCircBuf);
    588             pStreamDS->pCircBuf = NULL;
    589         }
    590582
    591583        if (pStreamDS->Out.pDSB)
     
    755747        pStreamDS->cbBufSize = bc.dwBufferBytes;
    756748
    757         rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Use "double buffering" */);
    758         AssertRC(rc);
    759 
    760749        pThis->pDSStrmOut = pStreamDS;
    761750
    762751        const uint32_t cfBufSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
    763752
    764         pCfgAcq->Backend.cFramesBufferSize = cfBufSize;
    765         pCfgAcq->Backend.cFramesPeriod     = cfBufSize / 4;
    766         pCfgAcq->Backend.cFramesPreBuffering     = pCfgAcq->Backend.cFramesPeriod * 2;
     753        pCfgAcq->Backend.cFramesBufferSize    = cfBufSize;
     754        pCfgAcq->Backend.cFramesPeriod        = cfBufSize / 4;
     755        pCfgAcq->Backend.cFramesPreBuffering  = pCfgAcq->Backend.cFramesPeriod * 2;
    767756
    768757    } while (0);
     
    796785        /* Make sure to get the last playback position and current write position from DirectSound again.
    797786         * Those positions in theory could have changed, re-fetch them to be sure. */
    798         hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB,
    799                                                    &pStreamDS->Out.offPlayCursorLastPlayed, &pStreamDS->Out.offWritePos);
    800         if (FAILED(hr))
     787        DWORD offPlay  = 0;
     788        DWORD offWrite = 0;
     789        hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlay, &offWrite);
     790        if (SUCCEEDED(hr))
     791        {
     792            pStreamDS->Out.offPlayCursorLastPlayed = offPlay;
     793            pStreamDS->Out.offWritePos             = offWrite;
     794        }
     795        else
    801796            DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr));
    802797    }
    803 }
    804 
    805 /**
    806  * Transfers audio data from the internal buffer to the DirectSound playback instance.
    807  * Due to internal accounting and querying DirectSound, this function knows how much it can transfer at once.
    808  *
    809  * @return  IPRT status code.
    810  * @param   pThis               Host audio driver instance.
    811  * @param   pStreamDS           Stream to transfer playback data for.
    812  */
    813 static int dsoundPlayTransfer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    814 {
    815     if (!pStreamDS->fEnabled)
    816     {
    817         Log2Func(("Stream disabled, skipping\n"));
    818         return VINF_SUCCESS;
    819     }
    820 
    821     uint32_t cbTransferred = 0;
    822 
    823     PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
    824     AssertPtr(pCircBuf);
    825 
    826     LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;
    827     AssertPtr(pDSB);
    828 
    829     int rc = VINF_SUCCESS;
    830 
    831     DWORD offPlayCursor, offWriteCursor;
    832     HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);
    833     if (FAILED(hr))
    834     {
    835         rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
    836         return rc;
    837     }
    838 
    839     DWORD cbFree, cbRemaining;
    840     if (pStreamDS->Out.fFirstTransfer)
    841     {
    842         cbRemaining = 0;
    843         cbFree      = pStreamDS->cbBufSize;
    844     }
    845     else
    846     {
    847         cbFree      = dsoundRingDistance(offPlayCursor, pStreamDS->Out.offWritePos, pStreamDS->cbBufSize);
    848         cbRemaining = dsoundRingDistance(pStreamDS->Out.offWritePos, offPlayCursor, pStreamDS->cbBufSize);
    849     }
    850 
    851     uint32_t cbAvail      = (uint32_t)RTCircBufUsed(pCircBuf);
    852     uint32_t cbToTransfer = RT_MIN(cbFree, cbAvail);
    853 
    854 #ifdef LOG_ENABLED
    855     if (!pStreamDS->Dbg.tsLastTransferredMs)
    856         pStreamDS->Dbg.tsLastTransferredMs = RTTimeMilliTS();
    857     Log3Func(("offPlay=%RU32, offWrite=%RU32, tsLastTransferredMs=%RU64ms, cbAvail=%RU32, cbFree=%RU32 -> cbToTransfer=%RU32 "
    858               "(fFirst=%RTbool, fDrain=%RTbool)\n",
    859               offPlayCursor, offWriteCursor, RTTimeMilliTS() - pStreamDS->Dbg.tsLastTransferredMs, cbAvail, cbFree, cbToTransfer,
    860               pStreamDS->Out.fFirstTransfer, pStreamDS->Out.fDrain));
    861     pStreamDS->Dbg.tsLastTransferredMs = RTTimeMilliTS();
    862 #endif
    863 
    864     while (cbToTransfer)
    865     {
    866         DWORD cb1 = 0;
    867         DWORD cb2 = 0;
    868 
    869         void  *pvBuf;
    870         size_t cbBuf;
    871         RTCircBufAcquireReadBlock(pCircBuf, cbToTransfer, &pvBuf, &cbBuf);
    872 
    873         if (cbBuf)
    874         {
    875             PVOID pv1, pv2;
    876             hr = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, (DWORD)cbBuf,
    877                                      &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
    878             if (FAILED(hr))
    879             {
    880                 rc = VERR_ACCESS_DENIED;
    881                 break;
    882             }
    883 
    884             AssertPtr(pv1);
    885             Assert(cb1);
    886 
    887             memcpy(pv1, pvBuf, cb1);
    888 
    889             if (pv2 && cb2) /* Buffer wrap-around? Write second part. */
    890                 memcpy(pv2, (uint8_t *)pvBuf + cb1, cb2);
    891 
    892             directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
    893 
    894             pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;
    895 
    896             Assert(cbToTransfer >= cbBuf);
    897             cbToTransfer -= (uint32_t)cbBuf;
    898 
    899             cbTransferred += cb1 + cb2;
    900         }
    901 
    902         RTCircBufReleaseReadBlock(pCircBuf, cb1 + cb2);
    903     }
    904 
    905     pStreamDS->Out.cbTransferred += cbTransferred;
    906 
    907     if (   pStreamDS->Out.fFirstTransfer
    908         && pStreamDS->Out.cbTransferred >= PDMAudioPropsFramesToBytes(&pStreamDS->Cfg.Props, pStreamDS->Cfg.Backend.cFramesPreBuffering))
    909     {
    910         hr = directSoundPlayStart(pThis, pStreamDS);
    911         if (SUCCEEDED(hr))
    912         {
    913             pStreamDS->Out.fFirstTransfer = false;
    914         }
    915         else
    916             rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
    917     }
    918 
    919     cbAvail = (uint32_t)RTCircBufUsed(pCircBuf);
    920     if (   !cbAvail
    921         && cbTransferred)
    922     {
    923         pStreamDS->Out.cbLastTransferred   = cbTransferred;
    924         pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();
    925 
    926         LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64\n",
    927                      pStreamDS->Out.cbLastTransferred, pStreamDS->Out.tsLastTransferredMs));
    928     }
    929 
    930     LogFlowFunc(("cbTransferred=%RU32, cbAvail=%RU32, rc=%Rrc\n", cbTransferred, cbAvail, rc));
    931     return rc;
    932798}
    933799
     
    980846        {
    981847            hr = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
    982             if (FAILED(hr))
     848            if (FAILED(hr)) /** @todo shouldn't this be a SUCCEEDED? */
    983849                hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
    984850        }
     
    1034900    LogFunc(("Resetting %s\n",
    1035901             pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback"));
    1036 
    1037     if (pStreamDS->pCircBuf)
    1038         RTCircBufReset(pStreamDS->pCircBuf);
    1039902
    1040903    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
     
    1061924    else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
    1062925    {
     926        /* If draining was enagaged, make sure dsound has stopped playing. */
     927        if (pStreamDS->Out.fDrain && pStreamDS->Out.pDSB)
     928            pStreamDS->Out.pDSB->Stop();
     929
    1063930        pStreamDS->Out.fFirstTransfer = true;
    1064931        pStreamDS->Out.fDrain         = false;
     
    1122989            || hr != DSERR_BUFFERLOST)
    1123990            break;
    1124         else
    1125         {
    1126             LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
    1127             directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
    1128         }
     991        LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
     992        directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
    1129993    }
    1130994
     
    11931057
    11941058/**
    1195  * Transfers audio data from the DirectSound capture instance to the internal buffer.
    1196  * Due to internal accounting and querying DirectSound, this function knows how much it can transfer at once.
    1197  *
    1198  * @return  IPRT status code.
    1199  * @param   pThis               Host audio driver instance.
    1200  * @param   pStreamDS           Stream to capture audio data for.
    1201  */
    1202 static int dsoundCaptureTransfer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    1203 {
    1204     RT_NOREF(pThis);
    1205 
    1206     LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pStreamDS->In.pDSCB;
    1207     AssertPtr(pDSCB);
    1208 
    1209     DWORD offCaptureCursor;
    1210     HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &offCaptureCursor);
    1211     if (FAILED(hr))
    1212     {
    1213         AssertFailed();
    1214         return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
    1215     }
    1216 
    1217     DWORD cbUsed = dsoundRingDistance(offCaptureCursor, pStreamDS->In.offReadPos, pStreamDS->cbBufSize);
    1218 
    1219     PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
    1220     AssertPtr(pCircBuf);
    1221 
    1222     uint32_t cbFree = (uint32_t)RTCircBufFree(pCircBuf);
    1223     if (   !cbFree
    1224         && pStreamDS->In.cOverruns < 32) /** @todo Make this configurable. */
    1225     {
    1226         DSLOG(("DSound: Warning: Internal buffer full (size is %zu bytes), skipping to record data (overflow #%RU32)\n",
    1227                RTCircBufSize(pCircBuf), pStreamDS->In.cOverruns));
    1228         DSLOG(("DSound: Warning: DSound capture buffer currently uses %RU32/%RU32 bytes\n", cbUsed, pStreamDS->cbBufSize));
    1229         pStreamDS->In.cOverruns++;
    1230     }
    1231 
    1232     DWORD cbToCapture = RT_MIN(cbUsed, cbFree);
    1233 
    1234     Log3Func(("cbUsed=%ld, cbToCapture=%ld\n", cbUsed, cbToCapture));
    1235 
    1236     while (cbToCapture)
    1237     {
    1238         void  *pvBuf;
    1239         size_t cbBuf;
    1240         RTCircBufAcquireWriteBlock(pCircBuf, cbToCapture, &pvBuf, &cbBuf);
    1241 
    1242         if (cbBuf)
    1243         {
    1244             PVOID pv1, pv2;
    1245             DWORD cb1, cb2;
    1246             hr = directSoundCaptureLock(pStreamDS, pStreamDS->In.offReadPos, (DWORD)cbBuf,
    1247                                         &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
    1248             if (FAILED(hr))
    1249                 break;
    1250 
    1251             AssertPtr(pv1);
    1252             Assert(cb1);
    1253 
    1254             memcpy(pvBuf, pv1, cb1);
    1255 
    1256             if (pv2 && cb2) /* Buffer wrap-around? Write second part. */
    1257                 memcpy((uint8_t *)pvBuf + cb1, pv2, cb2);
    1258 
    1259             directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
    1260 
    1261             pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cb1 + cb2) % pStreamDS->cbBufSize;
    1262 
    1263             Assert(cbToCapture >= cbBuf);
    1264             cbToCapture -= (uint32_t)cbBuf;
    1265         }
    1266 
    1267 #ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
    1268         if (cbBuf)
    1269         {
    1270             RTFILE fh;
    1271             int rc2 = RTFileOpen(&fh, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "dsoundCapture.pcm",
    1272                                  RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
    1273             if (RT_SUCCESS(rc2))
    1274             {
    1275                 RTFileWrite(fh, pvBuf, cbBuf, NULL);
    1276                 RTFileClose(fh);
    1277             }
    1278         }
    1279 #endif
    1280         RTCircBufReleaseWriteBlock(pCircBuf, cbBuf);
    1281     }
    1282 
    1283     return VINF_SUCCESS;
    1284 }
    1285 
    1286 /**
    12871059 * Destroys a DirectSound capture interface.
    12881060 *
     
    13971169        return hr;
    13981170
    1399     do /* To use breaks. */
     1171    do /* For readability breaks... */
    14001172    {
    14011173        DSCBUFFERDESC bd;
     
    14891261        pStreamDS->In.offReadPos = 0;
    14901262        pStreamDS->cbBufSize     = bc.dwBufferBytes;
    1491 
    1492         rc = RTCircBufCreate(&pStreamDS->pCircBuf, pStreamDS->cbBufSize * 2 /* Use "double buffering" */);
    1493         AssertRC(rc);
    14941263
    14951264        pThis->pDSStrmIn = pStreamDS;
     
    20701839    LogFlowFunc(("pStreamDS=%p, pCfgReq=%p\n", pStreamDS, pCfgReq));
    20711840
    2072     int rc = VINF_SUCCESS;
     1841    int rc;
    20731842
    20741843    /* Try to open playback in case the device is already there. */
     
    20911860    LogFlowFunc(("pStreamDS=%p, cmd=%d\n", pStreamDS, enmStreamCmd));
    20921861
    2093     int rc = VINF_SUCCESS;
    2094 
    20951862    HRESULT hr;
     1863    int     rc = VINF_SUCCESS;
    20961864    switch (enmStreamCmd)
    20971865    {
     
    21041872        case PDMAUDIOSTREAMCMD_RESUME:
    21051873        {
    2106             hr = directSoundPlayStart(pThis, pStreamDS);
    2107             if (FAILED(hr))
    2108                 rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */
     1874            /* Only resume if the stream is enabled.
     1875               Note! This used to always just resume the stream playback regardless of state,
     1876                     and instead rely on DISABLE filling the buffer with silence. */
     1877            if (pStreamDS->fEnabled)
     1878            {
     1879                hr = directSoundPlayStart(pThis, pStreamDS);
     1880                if (FAILED(hr))
     1881                    rc = VERR_NOT_SUPPORTED; /** @todo Fix this. */
     1882            }
    21091883            break;
    21101884        }
     
    21131887        {
    21141888            dsoundStreamEnable(pThis, pStreamDS, false /* fEnable */);
    2115             hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
    2116             if (FAILED(hr))
    2117                 rc = VERR_NOT_SUPPORTED;
     1889
     1890            /* Don't stop draining buffers. They'll stop by themselves. */
     1891            if (pStreamDS->Cfg.enmDir != PDMAUDIODIR_OUT || !pStreamDS->Out.fDrain)
     1892            {
     1893                hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
     1894                if (FAILED(hr))
     1895                    rc = VERR_NOT_SUPPORTED;
     1896            }
    21181897            break;
    21191898        }
     
    21301909        {
    21311910            /* Make sure we transferred everything. */
    2132             pStreamDS->fEnabled = true;
    2133             pStreamDS->Out.fDrain = true;
    2134             rc = dsoundPlayTransfer(pThis, pStreamDS);
    2135             if (   RT_SUCCESS(rc)
    2136                 && pStreamDS->Out.fFirstTransfer)
     1911            pStreamDS->fEnabled = true; /** @todo r=bird: ??? */
     1912
     1913            /*
     1914             * We've started the buffer in looping mode, try switch to non-looping...
     1915             */
     1916            if (pStreamDS->Out.pDSB)
    21371917            {
    2138                 /* If this was the first transfer ever for this stream, make sure to also play the (short) audio data. */
    2139                 DSLOG(("DSound: Started playing output (short sound)\n"));
    2140 
    2141                 pStreamDS->Out.fFirstTransfer    = false;
    2142                 pStreamDS->Out.cbLastTransferred = pStreamDS->Out.cbTransferred; /* All transferred audio data must be played. */
    2143                 pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();
    2144 
    2145                 hr = directSoundPlayStart(pThis, pStreamDS);
    2146                 if (FAILED(hr))
    2147                     rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
     1918                Log2Func(("drain: Switching playback to non-looping mode...\n"));
     1919                HRESULT hrc = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
     1920                if (SUCCEEDED(hrc))
     1921                {
     1922                    hrc = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, 0);
     1923                    if (SUCCEEDED(hrc))
     1924                        pStreamDS->Out.fDrain = true;
     1925                    else
     1926                        Log2Func(("drain: IDirectSoundBuffer8_Play(,,,0) failed: %Rhrc\n", hrc));
     1927                }
     1928                else
     1929                {
     1930                    Log2Func(("drain: IDirectSoundBuffer8_Stop failed: %Rhrc\n", hrc));
     1931                    hrc = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
     1932                    if (SUCCEEDED(hrc))
     1933                    {
     1934                        hrc = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
     1935                        Log2Func(("drain: IDirectSoundBuffer8_Stop failed: %Rhrc\n", hrc));
     1936                    }
     1937                }
    21481938            }
    21491939            break;
     
    21541944            pStreamDS->Out.cbLastTransferred   = 0;
    21551945            pStreamDS->Out.tsLastTransferredMs = 0;
    2156             RTCircBufReset(pStreamDS->pCircBuf);
    21571946            break;
    21581947        }
     
    21701959 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
    21711960 */
    2172 static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, const void *pvBuf,
    2173                                                     uint32_t uBufSize, uint32_t *puWritten)
    2174 {
    2175     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2176     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2177     AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
    2178     AssertReturn(uBufSize,         VERR_INVALID_PARAMETER);
    2179     /* puWritten is optional. */
    2180 
    2181     PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2182     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2183 
    2184     int rc = VINF_SUCCESS;
    2185 
    2186     uint32_t cbWrittenTotal = 0;
    2187 
    2188     uint8_t   *pbBuf    = (uint8_t *)pvBuf;
    2189     PRTCIRCBUF pCircBuf = pStreamDS->pCircBuf;
    2190 
    2191     uint32_t cbToPlay = RT_MIN(uBufSize, (uint32_t)RTCircBufFree(pCircBuf));
    2192     while (cbToPlay)
    2193     {
    2194         void *pvChunk;
    2195         size_t cbChunk;
    2196         RTCircBufAcquireWriteBlock(pCircBuf, cbToPlay, &pvChunk, &cbChunk);
    2197 
    2198         if (cbChunk)
    2199         {
    2200             memcpy(pvChunk, pbBuf, cbChunk);
    2201 
    2202             pbBuf     += cbChunk;
    2203             Assert(cbToPlay >= cbChunk);
    2204             cbToPlay  -= (uint32_t)cbChunk;
    2205 
    2206             cbWrittenTotal += (uint32_t)cbChunk;
    2207         }
    2208 
    2209         RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
    2210     }
    2211 
    2212     Assert(cbWrittenTotal <= uBufSize);
    2213     Assert(cbWrittenTotal == uBufSize);
    2214 
    2215     pStreamDS->Out.cbWritten += cbWrittenTotal;
    2216 
    2217     if (RT_SUCCESS(rc))
    2218     {
    2219         if (puWritten)
    2220             *puWritten = cbWrittenTotal;
    2221     }
     1961static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     1962                                                    const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     1963{
     1964    PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
     1965    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     1966    AssertPtrReturn(pStreamDS, 0);
     1967    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     1968    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
     1969    AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
     1970
     1971    if (pStreamDS->fEnabled)
     1972        AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2);
    22221973    else
    2223         dsoundUpdateStatusInternal(pThis);
    2224 
    2225     return rc;
     1974    {
     1975        Log2Func(("Stream disabled, skipping\n"));
     1976        return VINF_SUCCESS;
     1977    }
     1978
     1979/** @todo Any condition under which we should call dsoundUpdateStatusInternal(pThis) here?
     1980 * The old code thought it did so in case of failure, only it couldn't ever fails, so it never did. */
     1981
     1982    /*
     1983     * Transfer loop.
     1984     */
     1985    uint32_t cbWritten = 0;
     1986    while (cbBuf > 0)
     1987    {
     1988        /*
     1989         * Figure out how much we can possibly write.
     1990         */
     1991        DWORD offPlayCursor = 0;
     1992        DWORD cbWritable    = 0;
     1993        int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbWritable, &offPlayCursor);
     1994        AssertRCReturn(rc, rc);
     1995        if (cbWritable < pStreamDS->Cfg.Props.cbFrame)
     1996            break;
     1997
     1998        uint32_t const cbToWrite = RT_MIN(cbWritable, cbBuf);
     1999        Log3Func(("offPlay=%#x offWritePos=%#x -> cbWritable=%#x cbToWrite=%#x%s%s\n", offPlayCursor, pStreamDS->Out.offWritePos,
     2000                  cbWritable, cbToWrite, pStreamDS->Out.fFirstTransfer ? " first" : "", pStreamDS->Out.fDrain ? " drain" : ""));
     2001
     2002        /*
     2003         * Lock that amount of buffer.
     2004         */
     2005        PVOID pv1 = NULL;
     2006        DWORD cb1 = 0;
     2007        PVOID pv2 = NULL;
     2008        DWORD cb2 = 0;
     2009        HRESULT hrc = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbToWrite,
     2010                                          &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/);
     2011        AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2012        //AssertMsg(cb1 + cb2 == cbToWrite, ("%#x + %#x vs %#x\n", cb1, cb2, cbToWrite));
     2013
     2014        /*
     2015         * Copy over the data.
     2016         */
     2017        memcpy(pv1, pvBuf, cb1);
     2018        pvBuf      = (uint8_t *)pvBuf + cb1;
     2019        cbBuf     -= cb1;
     2020        cbWritten += cb1;
     2021
     2022        if (pv2)
     2023        {
     2024            memcpy(pv2, pvBuf, cb2);
     2025            pvBuf      = (uint8_t *)pvBuf + cb2;
     2026            cbBuf     -= cb2;
     2027            cbWritten += cb2;
     2028        }
     2029
     2030        /*
     2031         * Unlock and update the write position.
     2032         */
     2033        directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2); /** @todo r=bird: pThis + pDSB parameters here for Unlock, but only pThis for Lock. Why? */
     2034        pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;
     2035
     2036        /*
     2037         * If this was the first chunk, kick off playing.
     2038         */
     2039        if (!pStreamDS->Out.fFirstTransfer)
     2040        { /* likely */ }
     2041        else
     2042        {
     2043            *pcbWritten = cbWritten;
     2044            hrc = directSoundPlayStart(pThis, pStreamDS);
     2045            AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2046            pStreamDS->Out.fFirstTransfer = false;
     2047        }
     2048    }
     2049
     2050    /*
     2051     * Done.
     2052     */
     2053    *pcbWritten = cbWritten;
     2054
     2055    pStreamDS->Out.cbTransferred += cbWritten;
     2056    if (cbWritten)
     2057    {
     2058        uint64_t const msPrev = pStreamDS->Out.tsLastTransferredMs;
     2059        pStreamDS->Out.cbLastTransferred   = cbWritten;
     2060        pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();
     2061        LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64 cMsDelta=%RU64\n",
     2062                     cbWritten, pStreamDS->Out.tsLastTransferredMs, msPrev ? pStreamDS->Out.tsLastTransferredMs - msPrev : 0));
     2063    }
     2064    return VINF_SUCCESS;
    22262065}
    22272066
     
    23342173 */
    23352174static DECLCALLBACK(int) drvHostDSoundHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    2336                                                        void *pvBuf, uint32_t uBufSize, uint32_t *puRead)
    2337 {
    2338 
    2339     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2340     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2341     AssertPtrReturn(pvBuf,      VERR_INVALID_POINTER);
    2342     AssertReturn(uBufSize,         VERR_INVALID_PARAMETER);
    2343 
    2344     PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2345     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2346 
    2347     int rc = VINF_SUCCESS;
    2348 
    2349     uint32_t cbReadTotal = 0;
    2350 
    2351     uint32_t cbToRead = RT_MIN((uint32_t)RTCircBufUsed(pStreamDS->pCircBuf), uBufSize);
    2352     while (cbToRead)
    2353     {
    2354         void   *pvChunk;
    2355         size_t  cbChunk;
    2356         RTCircBufAcquireReadBlock(pStreamDS->pCircBuf, cbToRead, &pvChunk, &cbChunk);
    2357 
    2358         if (cbChunk)
    2359         {
    2360             memcpy((uint8_t *)pvBuf + cbReadTotal, pvChunk, cbChunk);
    2361             cbReadTotal += (uint32_t)cbChunk;
    2362             Assert(cbToRead >= cbChunk);
    2363             cbToRead    -= (uint32_t)cbChunk;
    2364         }
    2365 
    2366         RTCircBufReleaseReadBlock(pStreamDS->pCircBuf, cbChunk);
    2367     }
    2368 
    2369     if (RT_SUCCESS(rc))
    2370     {
    2371         if (puRead)
    2372             *puRead = cbReadTotal;
    2373     }
     2175                                                       void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     2176{
     2177    /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);*/ RT_NOREF(pInterface);
     2178    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2179    AssertPtrReturn(pStreamDS, 0);
     2180    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     2181    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
     2182    AssertPtrReturn(pcbRead, VERR_INVALID_POINTER);
     2183
     2184#if 0 /** @todo r=bird: shouldn't we do the same check as for output streams? */
     2185    if (pStreamDS->fEnabled)
     2186        AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2);
    23742187    else
    2375         dsoundUpdateStatusInternal(pThis);
    2376 
    2377     return rc;
     2188    {
     2189        Log2Func(("Stream disabled, skipping\n"));
     2190        return VINF_SUCCESS;
     2191    }
     2192#endif
     2193
     2194    /*
     2195     * Read loop.
     2196     */
     2197    uint32_t cbRead = 0;
     2198    while (cbBuf > 0)
     2199    {
     2200        /*
     2201         * Figure out how much we can read.
     2202         */
     2203        DWORD   offCaptureCursor = 0;
     2204        DWORD   offReadCursor    = 0;
     2205        HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor);
     2206        AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2207        //AssertMsg(offReadCursor == pStreamDS->In.offReadPos, ("%#x %#x\n", offReadCursor, pStreamDS->In.offReadPos));
     2208
     2209        uint32_t const cbReadable = dsoundRingDistance(offCaptureCursor, pStreamDS->In.offReadPos, pStreamDS->cbBufSize);
     2210
     2211        if (cbReadable >= pStreamDS->Cfg.Props.cbFrame)
     2212        { /* likely */ }
     2213        else
     2214        {
     2215            if (cbRead > 0)
     2216            { /* likely */ }
     2217            else if (pStreamDS->In.cOverruns < 32)
     2218            {
     2219                pStreamDS->In.cOverruns++;
     2220                DSLOG(("DSound: Warning: Buffer full (size is %zu bytes), skipping to record data (overflow #%RU32)\n",
     2221                       pStreamDS->cbBufSize, pStreamDS->In.cOverruns));
     2222            }
     2223            break;
     2224        }
     2225
     2226        uint32_t const cbToRead = RT_MIN(cbReadable, cbBuf);
     2227        Log3Func(("offCapture=%#x offRead=%#x/%#x -> cbWritable=%#x cbToWrite=%#x\n",
     2228                  offCaptureCursor, offReadCursor, pStreamDS->In.offReadPos, cbReadable, cbToRead));
     2229
     2230        /*
     2231         * Lock that amount of buffer.
     2232         */
     2233        PVOID pv1 = NULL;
     2234        DWORD cb1 = 0;
     2235        PVOID pv2 = NULL;
     2236        DWORD cb2 = 0;
     2237        hrc = directSoundCaptureLock(pStreamDS, pStreamDS->In.offReadPos, cbToRead, &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/);
     2238        AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2239        AssertMsg(cb1 + cb2 == cbToRead, ("%#x + %#x vs %#x\n", cb1, cb2, cbToRead));
     2240
     2241        /*
     2242         * Copy over the data.
     2243         */
     2244        memcpy(pvBuf, pv1, cb1);
     2245        pvBuf   = (uint8_t *)pvBuf + cb1;
     2246        cbBuf  -= cb1;
     2247        cbRead += cb1;
     2248
     2249        if (pv2)
     2250        {
     2251            memcpy(pvBuf, pv2, cb2);
     2252            pvBuf   = (uint8_t *)pvBuf + cb2;
     2253            cbBuf  -= cb2;
     2254            cbRead += cb2;
     2255        }
     2256
     2257        /*
     2258         * Unlock and update the write position.
     2259         */
     2260        directSoundCaptureUnlock(pStreamDS->In.pDSCB, pv1, pv2, cb1, cb2); /** @todo r=bird: pDSB parameter here for Unlock, but pStreamDS for Lock. Why? */
     2261        pStreamDS->In.offReadPos = (pStreamDS->In.offReadPos + cb1 + cb2) % pStreamDS->cbBufSize;
     2262    }
     2263
     2264    /*
     2265     * Done.
     2266     */
     2267    if (pcbRead)
     2268        *pcbRead = cbRead;
     2269
     2270#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
     2271    if (cbRead)
     2272    {
     2273        RTFILE hFile;
     2274        int rc2 = RTFileOpen(&hFile, VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "dsoundCapture.pcm",
     2275                             RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
     2276        if (RT_SUCCESS(rc2))
     2277        {
     2278            RTFileWrite(hFile, (uint8_t *)pvBuf - cbRead, cbRead, NULL);
     2279            RTFileClose(hFile);
     2280        }
     2281    }
     2282#endif
     2283    return VINF_SUCCESS;
    23782284}
    23792285
     
    26062512static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    26072513{
     2514    /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
     2515    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2516    AssertPtrReturn(pStreamDS, 0);
     2517    Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN);
     2518
     2519    if (pStreamDS->fEnabled)
     2520    {
     2521        /* This is the same calculation as for StreamGetPending. */
     2522        AssertPtr(pStreamDS->In.pDSCB);
     2523        DWORD   offCaptureCursor = 0;
     2524        DWORD   offReadCursor    = 0;
     2525        HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor);
     2526        if (SUCCEEDED(hrc))
     2527        {
     2528            uint32_t cbPending = dsoundRingDistance(offCaptureCursor, offReadCursor, pStreamDS->cbBufSize);
     2529            Log3Func(("cbPending=%RU32\n", cbPending));
     2530            return cbPending;
     2531        }
     2532        AssertMsgFailed(("hrc=%Rhrc\n", hrc));
     2533    }
     2534
     2535    return 0;
     2536}
     2537
     2538/**
     2539 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
     2540 */
     2541static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2542{
     2543    PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
     2544    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2545    AssertPtrReturn(pStreamDS, 0);
     2546
     2547    DWORD           cbFree    = 0;
     2548    DWORD           offIgn    = 0;
     2549    int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree, &offIgn);
     2550    AssertRCReturn(rc, 0);
     2551
     2552    return cbFree;
     2553}
     2554
     2555#if 0 /* This isn't working as the write cursor is more a function of time than what we do.
     2556         Previously we only reported the pre-buffering status anyway, so no harm. */
     2557/**
     2558 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
     2559 */
     2560static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2561{
     2562    /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
     2563    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2564    AssertPtrReturn(pStreamDS, 0);
     2565
     2566    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
     2567    {
     2568        /* This is a similar calculation as for StreamGetReadable, only for an output buffer. */
     2569        AssertPtr(pStreamDS->In.pDSCB);
     2570        DWORD   offPlayCursor  = 0;
     2571        DWORD   offWriteCursor = 0;
     2572        HRESULT hrc = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor);
     2573        if (SUCCEEDED(hrc))
     2574        {
     2575            uint32_t cbPending = dsoundRingDistance(offWriteCursor, offPlayCursor, pStreamDS->cbBufSize);
     2576            Log3Func(("cbPending=%RU32\n", cbPending));
     2577            return cbPending;
     2578        }
     2579        AssertMsgFailed(("hrc=%Rhrc\n", hrc));
     2580    }
     2581    /* else: For input streams we never have any pending data. */
     2582
     2583    return 0;
     2584}
     2585#endif
     2586
     2587/**
     2588 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
     2589 */
     2590static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2591{
    26082592    RT_NOREF(pInterface);
    26092593    AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);
     
    26112595    PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
    26122596
    2613     if (   pStreamDS->fEnabled
    2614         && pStreamDS->pCircBuf)
    2615     {
    2616         return (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);
    2617     }
    2618 
    2619     return 0;
    2620 }
    2621 
    2622 /**
    2623  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
    2624  */
    2625 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2626 {
    2627     AssertPtrReturn(pInterface, PDMAUDIOSTREAMSTS_FLAGS_NONE);
    2628     AssertPtrReturn(pStream,    PDMAUDIOSTREAMSTS_FLAGS_NONE);
    2629 
    2630     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2631 
    2632     if (pStreamDS->fEnabled)
    2633         return (uint32_t)RTCircBufFree(pStreamDS->pCircBuf);
    2634 
    2635     return 0;
    2636 }
    2637 
    2638 /**
    2639  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
    2640  */
    2641 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2642 {
    2643     RT_NOREF(pInterface);
    2644     AssertPtrReturn(pStream, 0);
    2645 
    2646     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2647 
    2648     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
    2649     {
    2650         uint32_t cbPending = 0;
    2651 
    2652         /* Any uncommitted data left? */
    2653         if (pStreamDS->pCircBuf)
    2654             cbPending = (uint32_t)RTCircBufUsed(pStreamDS->pCircBuf);
    2655 
    2656         /* Check if we have committed data which still needs to be played by
    2657          * by DirectSound's streaming buffer. */
    2658         if (!cbPending)
    2659         {
    2660             const uint64_t diffLastTransferredMs  = RTTimeMilliTS() - pStreamDS->Out.tsLastTransferredMs;
    2661             const uint64_t uLastTranserredChunkMs = PDMAudioPropsBytesToMilli(&pStreamDS->Cfg.Props, pStreamDS->Out.cbLastTransferred);
    2662             if (   uLastTranserredChunkMs
    2663                 && diffLastTransferredMs < uLastTranserredChunkMs)
    2664                 cbPending = 1;
    2665 
    2666             Log3Func(("diffLastTransferredMs=%RU64ms, uLastTranserredChunkMs=%RU64ms (%RU32 bytes) -> cbPending=%RU32\n",
    2667                       diffLastTransferredMs, uLastTranserredChunkMs, pStreamDS->Out.cbLastTransferred, cbPending));
    2668         }
    2669         else
    2670             Log3Func(("cbPending=%RU32\n", cbPending));
    2671 
    2672         return cbPending;
    2673     }
    2674     /* Note: For input streams we never have pending data left. */
    2675 
    2676     return 0;
    2677 }
    2678 
    2679 /**
    2680  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
    2681  */
    2682 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2683 {
    2684     RT_NOREF(pInterface);
    2685     AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);
    2686 
    2687     PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
    2688 
    26892597    PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED;
    26902598
     
    27002608static DECLCALLBACK(int) drvHostDSoundHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    27012609{
    2702     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2703     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2704 
    2705     PDRVHOSTDSOUND pThis    = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2706     PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
    2707 
    2708     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
    2709     {
    2710         return dsoundCaptureTransfer(pThis, pStreamDS);
    2711     }
    2712     else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
    2713     {
    2714         return dsoundPlayTransfer(pThis, pStreamDS);
    2715     }
    2716 
     2610    RT_NOREF(pInterface, pStream);
    27172611    return VINF_SUCCESS;
    27182612}
     
    28132707    pThis->IHostAudio.pfnStreamCapture      = drvHostDSoundHA_StreamCapture;
    28142708    pThis->IHostAudio.pfnGetDevices         = drvHostDSoundHA_GetDevices;
    2815     pThis->IHostAudio.pfnStreamGetPending   = drvHostDSoundHA_StreamGetPending;
     2709    pThis->IHostAudio.pfnStreamGetPending   = NULL;
    28162710    pThis->IHostAudio.pfnStreamPlayBegin    = NULL;
    28172711    pThis->IHostAudio.pfnStreamPlayEnd      = NULL;
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