VirtualBox

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


Ignore:
Timestamp:
Apr 14, 2021 8:03:28 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143781
Message:

DrvHostAudioDSound: Moving functions around. bugref:9890

File:
1 edited

Legend:

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

    r88452 r88514  
    4848/*
    4949 * IDirectSound* interface uses HRESULT status codes and the driver callbacks use
    50  * the IPRT status codes. To minimize HRESULT->IPRT conversion most internal functions
     50 * the VBox status codes.  To minimize HRESULT->VBox conversion most internal functions
    5151 * in the driver return HRESULT and conversion is done in the driver callbacks.
    5252 *
    5353 * Naming convention:
    54  * 'dsound*' functions return IPRT status code;
     54 * 'dsound*' functions return VBox status code;
    5555 * 'directSound*' - return HRESULT.
    5656 */
     
    5959 * Optional release logging, which a user can turn on with the
    6060 * 'VBoxManage debugvm' command.
    61  * Debug logging still uses the common Log* macros from IPRT.
     61 * Debug logging still uses the common Log* macros from VBox.
    6262 * Messages which always should go to the release log use LogRel.
    6363 */
     
    260260}
    261261
    262 static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
    263 {
    264     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    265     AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
    266 
    267     RT_BZERO(pFmt, sizeof(WAVEFORMATEX));
    268 
    269     pFmt->wFormatTag      = WAVE_FORMAT_PCM;
    270     pFmt->nChannels       = PDMAudioPropsChannels(&pCfg->Props);
    271     pFmt->wBitsPerSample  = PDMAudioPropsSampleBits(&pCfg->Props);
    272     pFmt->nSamplesPerSec  = PDMAudioPropsHz(&pCfg->Props);
    273     pFmt->nBlockAlign     = PDMAudioPropsFrameSize(&pCfg->Props);
    274     pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(&pCfg->Props, PDMAudioPropsHz(&pCfg->Props));
    275     pFmt->cbSize          = 0; /* No extra data specified. */
    276 
    277     return VINF_SUCCESS;
    278 }
    279 
    280 /**
    281  * Retrieves the number of free bytes available for writing to a DirectSound output stream.
    282  *
    283  * @return  VBox status code. VERR_NOT_AVAILABLE if unable to determine or the
    284  *          buffer was not recoverable.
    285  * @param   pThis               Host audio driver instance.
    286  * @param   pStreamDS           DirectSound output stream to retrieve number for.
    287  * @param   pdwFree             Where to return the free amount on success.
    288  * @param   poffPlayCursor      Where to return the play cursor offset.
    289  */
    290 static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree, DWORD *poffPlayCursor)
    291 {
    292     AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
    293     AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER);
    294     AssertPtrReturn(pdwFree,   VERR_INVALID_POINTER);
    295     AssertPtr(poffPlayCursor);
    296 
    297     Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT); /* Paranoia. */
    298 
    299     LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;
    300     if (!pDSB)
    301     {
    302         AssertPtr(pDSB);
    303         return VERR_INVALID_POINTER;
    304     }
    305 
    306     HRESULT hr = S_OK;
    307 
    308     /* Get the current play position which is used for calculating the free space in the buffer. */
    309     for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
    310     {
    311         DWORD offPlayCursor  = 0;
    312         DWORD offWriteCursor = 0;
    313         hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);
    314         if (SUCCEEDED(hr))
    315         {
    316             int32_t cbDiff = offWriteCursor - offPlayCursor;
    317             if (cbDiff < 0)
    318                 cbDiff += pStreamDS->cbBufSize;
    319 
    320             int32_t cbFree = offPlayCursor - pStreamDS->Out.offWritePos;
    321             if (cbFree < 0)
    322                 cbFree += pStreamDS->cbBufSize;
    323 
    324             if (cbFree > (int32_t)pStreamDS->cbBufSize - cbDiff)
    325             {
    326                 /** @todo count/log these. */
    327                 pStreamDS->Out.offWritePos = offWriteCursor;
    328                 cbFree = pStreamDS->cbBufSize - cbDiff;
    329             }
    330 
    331             /* When starting to use a DirectSound buffer, offPlayCursor and offWriteCursor
    332              * both point at position 0, so we won't be able to detect how many bytes
    333              * are writable that way.
    334              *
    335              * So use our per-stream written indicator to see if we just started a stream. */
    336             if (pStreamDS->Out.cbWritten == 0)
    337                 cbFree = pStreamDS->cbBufSize;
    338 
    339             DSLOGREL(("DSound: offPlayCursor=%RU32, offWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",
    340                       offPlayCursor, offWriteCursor, pStreamDS->Out.offWritePos, cbFree));
    341 
    342             *pdwFree = cbFree;
    343             *poffPlayCursor = offPlayCursor;
    344             return VINF_SUCCESS;
    345         }
    346 
    347         if (hr != DSERR_BUFFERLOST) /** @todo MSDN doesn't state this error for GetCurrentPosition(). */
    348             break;
    349 
    350         LogFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
    351 
    352         directSoundPlayRestore(pThis, pDSB);
    353     }
    354 
    355     if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
    356         DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
    357 
    358     LogFunc(("Failed with %Rhrc\n", hr));
    359 
    360     *poffPlayCursor = pStreamDS->cbBufSize;
    361     return VERR_NOT_AVAILABLE;
    362 }
    363262
    364263static char *dsoundGUIDToUtf8StrA(LPCGUID pGUID)
     
    380279    return RTStrDup("{Default device}");
    381280}
     281
    382282
    383283static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
     
    393293}
    394294
     295
    395296static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
    396297                                     PVOID pv1, PVOID pv2,
     
    404305}
    405306
    406 static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
    407                                         PVOID pv1, PVOID pv2,
    408                                         DWORD cb1, DWORD cb2)
    409 {
    410     HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
    411     if (FAILED(hr))
    412         DSLOGREL(("DSound: Unlocking capture buffer failed with %Rhrc\n", hr));
    413     return hr;
    414 }
    415307
    416308static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
     
    461353}
    462354
     355
     356static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
     357                                        PVOID pv1, PVOID pv2,
     358                                        DWORD cb1, DWORD cb2)
     359{
     360    HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
     361    if (FAILED(hr))
     362        DSLOGREL(("DSound: Unlocking capture buffer failed with %Rhrc\n", hr));
     363    return hr;
     364}
     365
     366
    463367static HRESULT directSoundCaptureLock(PDSOUNDSTREAM pStreamDS,
    464368                                      DWORD dwOffset, DWORD dwBytes,
     
    497401}
    498402
     403
    499404/*
    500405 * DirectSound playback
     
    516421    }
    517422}
     423
    518424
    519425/**
     
    568474}
    569475
    570 static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    571 {
    572     AssertPtrReturn(pThis,     E_POINTER);
    573     AssertPtrReturn(pStreamDS, E_POINTER);
    574 
    575     LogFlowFuncEnter();
    576 
    577     HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
    578     if (SUCCEEDED(hr))
    579     {
    580         DSLOG(("DSound: Closing playback stream\n"));
    581         RTCritSectEnter(&pThis->CritSect);
    582 
    583         if (pStreamDS->Out.pDSB)
    584         {
    585             IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB);
    586             pStreamDS->Out.pDSB = NULL;
    587         }
    588 
    589         pThis->pDSStrmOut = NULL;
    590 
    591         RTCritSectLeave(&pThis->CritSect);
    592     }
    593 
    594     if (FAILED(hr))
    595         DSLOGREL(("DSound: Stopping playback stream %p failed with %Rhrc\n", pStreamDS, hr));
    596 
    597     return hr;
    598 }
    599 
    600 static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
    601                                    PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    602 {
    603     AssertPtrReturn(pThis,     E_POINTER);
    604     AssertPtrReturn(pStreamDS, E_POINTER);
    605     AssertPtrReturn(pCfgReq,   E_POINTER);
    606     AssertPtrReturn(pCfgAcq,   E_POINTER);
    607 
    608 /** @todo r=bird: I cannot see any code populating pCfgAcq... */
    609 
    610     LogFlowFuncEnter();
    611 
    612     Assert(pStreamDS->Out.pDSB == NULL);
    613 
    614     DSLOG(("DSound: Opening playback stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz,
    615            PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned));
    616 
    617     WAVEFORMATEX wfx;
    618     int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
    619     if (RT_FAILURE(rc))
    620         return E_INVALIDARG;
    621 
    622     DSLOG(("DSound: Requested playback format:\n"
    623            "  wFormatTag      = %RI16\n"
    624            "  nChannels       = %RI16\n"
    625            "  nSamplesPerSec  = %RU32\n"
    626            "  nAvgBytesPerSec = %RU32\n"
    627            "  nBlockAlign     = %RI16\n"
    628            "  wBitsPerSample  = %RI16\n"
    629            "  cbSize          = %RI16\n",
    630            wfx.wFormatTag,
    631            wfx.nChannels,
    632            wfx.nSamplesPerSec,
    633            wfx.nAvgBytesPerSec,
    634            wfx.nBlockAlign,
    635            wfx.wBitsPerSample,
    636            wfx.cbSize));
    637 
    638     /** @todo r=bird: Why is this called every time?  It triggers a device
    639      * enumeration. Andy claimed on IRC that enumeration was only done once...
    640      * It's generally a 'ing waste of time here too, as we dont really use any of
    641      * the information we gather there. */
    642     dsoundUpdateStatusInternal(pThis);
    643 
    644     HRESULT hr = directSoundPlayInterfaceCreate(pThis->Cfg.pGuidPlay, &pThis->pDS);
    645     if (FAILED(hr))
    646         return hr;
    647 
    648     do /* To use breaks. */
    649     {
    650         LPDIRECTSOUNDBUFFER pDSB = NULL;
    651 
    652         DSBUFFERDESC bd;
    653         RT_ZERO(bd);
    654         bd.dwSize      = sizeof(bd);
    655         bd.lpwfxFormat = &wfx;
    656 
    657         /*
    658          * As we reuse our (secondary) buffer for playing out data as it comes in,
    659          * we're using this buffer as a so-called streaming buffer.
    660          *
    661          * See https://msdn.microsoft.com/en-us/library/windows/desktop/ee419014(v=vs.85).aspx
    662          *
    663          * However, as we do not want to use memory on the sound device directly
    664          * (as most modern audio hardware on the host doesn't have this anyway),
    665          * we're *not* going to use DSBCAPS_STATIC for that.
    666          *
    667          * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill
    668          * of copying own buffer data to our secondary's Direct Sound buffer.
    669          */
    670         bd.dwFlags       = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
    671         bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
    672 
    673         DSLOG(("DSound: Requested playback buffer is %RU64ms (%ld bytes)\n",
    674                PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes));
    675 
    676         hr = IDirectSound8_CreateSoundBuffer(pThis->pDS, &bd, &pDSB, NULL);
    677         if (FAILED(hr))
    678         {
    679             DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr));
    680             break;
    681         }
    682 
    683         /* "Upgrade" to IDirectSoundBuffer8 interface. */
    684         hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (PVOID *)&pStreamDS->Out.pDSB);
    685         IDirectSoundBuffer_Release(pDSB);
    686         if (FAILED(hr))
    687         {
    688             DSLOGREL(("DSound: Querying playback sound buffer interface failed with %Rhrc\n", hr));
    689             break;
    690         }
    691 
    692         /*
    693          * Query the actual parameters set for this stream.
    694          * Those might be different than the initially requested parameters.
    695          */
    696         RT_ZERO(wfx);
    697         hr = IDirectSoundBuffer8_GetFormat(pStreamDS->Out.pDSB, &wfx, sizeof(wfx), NULL);
    698         if (FAILED(hr))
    699         {
    700             DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr));
    701             break;
    702         }
    703 
    704         DSBCAPS bc;
    705         RT_ZERO(bc);
    706         bc.dwSize = sizeof(bc);
    707 
    708         hr = IDirectSoundBuffer8_GetCaps(pStreamDS->Out.pDSB, &bc);
    709         if (FAILED(hr))
    710         {
    711             DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr));
    712             break;
    713         }
    714 
    715         DSLOG(("DSound: Acquired playback buffer is %RU64ms (%ld bytes)\n",
    716                PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes));
    717 
    718         DSLOG(("DSound: Acquired playback format:\n"
    719                "  dwBufferBytes   = %RI32\n"
    720                "  dwFlags         = 0x%x\n"
    721                "  wFormatTag      = %RI16\n"
    722                "  nChannels       = %RI16\n"
    723                "  nSamplesPerSec  = %RU32\n"
    724                "  nAvgBytesPerSec = %RU32\n"
    725                "  nBlockAlign     = %RI16\n"
    726                "  wBitsPerSample  = %RI16\n"
    727                "  cbSize          = %RI16\n",
    728                bc.dwBufferBytes,
    729                bc.dwFlags,
    730                wfx.wFormatTag,
    731                wfx.nChannels,
    732                wfx.nSamplesPerSec,
    733                wfx.nAvgBytesPerSec,
    734                wfx.nBlockAlign,
    735                wfx.wBitsPerSample,
    736                wfx.cbSize));
    737 
    738         if (bc.dwBufferBytes & pStreamDS->uAlign)
    739             DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
    740                       bc.dwBufferBytes, pStreamDS->uAlign + 1));
    741 
    742         /*
    743          * Initial state.
    744          * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
    745          * playback buffer position.
    746          */
    747         pStreamDS->cbBufSize = bc.dwBufferBytes;
    748 
    749         pThis->pDSStrmOut = pStreamDS;
    750 
    751         const uint32_t cfBufSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
    752 
    753         pCfgAcq->Backend.cFramesBufferSize    = cfBufSize;
    754         pCfgAcq->Backend.cFramesPeriod        = cfBufSize / 4;
    755         pCfgAcq->Backend.cFramesPreBuffering  = pCfgAcq->Backend.cFramesPeriod * 2;
    756 
    757     } while (0);
    758 
    759     if (FAILED(hr))
    760         directSoundPlayClose(pThis, pStreamDS);
    761 
    762     return hr;
    763 }
    764 
    765 static void dsoundPlayClearBuffer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    766 {
    767     AssertPtrReturnVoid(pStreamDS);
    768 
    769     PPDMAUDIOPCMPROPS pProps = &pStreamDS->Cfg.Props;
    770 
    771     HRESULT hr = IDirectSoundBuffer_SetCurrentPosition(pStreamDS->Out.pDSB, 0 /* Position */);
    772     if (FAILED(hr))
    773         DSLOGREL(("DSound: Setting current position to 0 when clearing buffer failed with %Rhrc\n", hr));
    774 
    775     PVOID pv1;
    776     hr = directSoundPlayLock(pThis, pStreamDS,
    777                              0 /* dwOffset */, pStreamDS->cbBufSize,
    778                              &pv1, NULL, 0, 0, DSBLOCK_ENTIREBUFFER);
    779     if (SUCCEEDED(hr))
    780     {
    781         PDMAudioPropsClearBuffer(pProps, pv1, pStreamDS->cbBufSize, PDMAUDIOPCMPROPS_B2F(pProps, pStreamDS->cbBufSize));
    782 
    783         directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, NULL, 0, 0);
    784 
    785         /* Make sure to get the last playback position and current write position from DirectSound again.
    786          * Those positions in theory could have changed, re-fetch them to be sure. */
    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
    796             DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr));
    797     }
    798 }
    799476
    800477static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
     
    828505    else
    829506        DSLOGREL(("DSound: Retrieving playback status failed with %Rhrc\n", hr));
    830 
    831     return hr;
    832 }
    833 
    834 static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
    835 {
    836     AssertPtrReturn(pThis,     E_POINTER);
    837     AssertPtrReturn(pStreamDS, E_POINTER);
    838 
    839     HRESULT hr = S_OK;
    840 
    841     if (pStreamDS->Out.pDSB)
    842     {
    843         DSLOG(("DSound: Stopping playback\n"));
    844         hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
    845         if (FAILED(hr))
    846         {
    847             hr = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
    848             if (FAILED(hr)) /** @todo shouldn't this be a SUCCEEDED? */
    849                 hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
    850         }
    851     }
    852 
    853     if (SUCCEEDED(hr))
    854     {
    855         if (fFlush)
    856             dsoundStreamReset(pThis, pStreamDS);
    857     }
    858 
    859     if (FAILED(hr))
    860         DSLOGREL(("DSound: %s playback failed with %Rhrc\n", fFlush ? "Stopping" : "Pausing", hr));
    861 
    862     return hr;
    863 }
    864 
    865 /**
    866  * Enables or disables a stream.
    867  *
    868  * @return  IPRT status code.
    869  * @param   pThis               Host audio driver instance.
    870  * @param   pStreamDS           Stream to enable / disable.
    871  * @param   fEnable             Whether to enable or disable the stream.
    872  */
    873 static int dsoundStreamEnable(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fEnable)
    874 {
    875     RT_NOREF(pThis);
    876 
    877     LogFunc(("%s %s\n",
    878              fEnable ? "Enabling" : "Disabling",
    879              pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback"));
    880 
    881     if (fEnable)
    882         dsoundStreamReset(pThis, pStreamDS);
    883 
    884     pStreamDS->fEnabled = fEnable;
    885 
    886     return VINF_SUCCESS;
    887 }
    888 
    889 
    890 /**
    891  * Resets the state of a DirectSound stream.
    892  *
    893  * @param   pThis               Host audio driver instance.
    894  * @param   pStreamDS           Stream to reset state for.
    895  */
    896 static void dsoundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    897 {
    898     RT_NOREF(pThis);
    899 
    900     LogFunc(("Resetting %s\n",
    901              pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback"));
    902 
    903     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
    904     {
    905         pStreamDS->In.offReadPos = 0;
    906         pStreamDS->In.cOverruns  = 0;
    907 
    908         /* Also reset the DirectSound Capture Buffer (DSCB) by clearing all data to make sure
    909          * not stale audio data is left. */
    910         if (pStreamDS->In.pDSCB)
    911         {
    912             PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2;
    913             HRESULT hr = directSoundCaptureLock(pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2,
    914                                                 0 /* Flags */);
    915             if (SUCCEEDED(hr))
    916             {
    917                 PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1));
    918                 if (pv2 && cb2)
    919                     PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2));
    920                 directSoundCaptureUnlock(pStreamDS->In.pDSCB, pv1, pv2, cb1, cb2);
    921             }
    922         }
    923     }
    924     else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
    925     {
    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 
    930         pStreamDS->Out.fFirstTransfer = true;
    931         pStreamDS->Out.fDrain         = false;
    932         pStreamDS->Out.cUnderruns     = 0;
    933 
    934         pStreamDS->Out.cbLastTransferred   = 0;
    935         pStreamDS->Out.tsLastTransferredMs = 0;
    936 
    937         pStreamDS->Out.cbTransferred = 0;
    938         pStreamDS->Out.cbWritten = 0;
    939 
    940         pStreamDS->Out.offWritePos = 0;
    941         pStreamDS->Out.offPlayCursorLastPending = 0;
    942         pStreamDS->Out.offPlayCursorLastPlayed = 0;
    943 
    944         /* Also reset the DirectSound Buffer (DSB) by setting the position to 0 and clear all data to make sure
    945          * not stale audio data is left. */
    946         if (pStreamDS->Out.pDSB)
    947         {
    948             HRESULT hr = IDirectSoundBuffer8_SetCurrentPosition(pStreamDS->Out.pDSB, 0);
    949             if (SUCCEEDED(hr))
    950             {
    951                 PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2;
    952                 hr = directSoundPlayLock(pThis, pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2,
    953                                          0 /* Flags */);
    954                 if (SUCCEEDED(hr))
    955                 {
    956                     PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1));
    957                     if (pv2 && cb2)
    958                         PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2));
    959                     directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2);
    960                 }
    961             }
    962         }
    963     }
    964 
    965 #ifdef LOG_ENABLED
    966     pStreamDS->Dbg.tsLastTransferredMs = 0;
    967 #endif
    968 }
    969 
    970 
    971 /**
    972  * Starts playing a DirectSound stream.
    973  *
    974  * @return  HRESULT
    975  * @param   pThis               Host audio driver instance.
    976  * @param   pStreamDS           Stream to start playing.
    977  */
    978 static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    979 {
    980     HRESULT hr = S_OK;
    981 
    982     DWORD fFlags = DSCBSTART_LOOPING;
    983 
    984     for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
    985     {
    986         DSLOG(("DSound: Starting playback\n"));
    987         hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, fFlags);
    988         if (   SUCCEEDED(hr)
    989             || hr != DSERR_BUFFERLOST)
    990             break;
    991         LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
    992         directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
    993     }
    994507
    995508    return hr;
     
    1056569#endif
    1057570
     571
    1058572/**
    1059573 * Destroys a DirectSound capture interface.
     
    1071585    }
    1072586}
     587
    1073588
    1074589/**
     
    1115630}
    1116631
    1117 static HRESULT directSoundCaptureClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    1118 {
    1119     AssertPtrReturn(pThis,     E_POINTER);
    1120     AssertPtrReturn(pStreamDS, E_POINTER);
    1121 
     632
     633/**
     634 * Updates this host driver's internal status, according to the global, overall input/output
     635 * state and all connected (native) audio streams.
     636 *
     637 * @todo r=bird: This is a 'ing waste of 'ing time!  We're doing this everytime
     638 *       an 'ing stream is created and we doesn't 'ing use the information here
     639 *       for any darn thing!  Given the reported slowness of enumeration and
     640 *       issues with the 'ing code the only appropriate response is:
     641 *       AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARG!!!!!!!
     642 *
     643 * @param   pThis               Host audio driver instance.
     644 */
     645static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
     646{
     647#if 0 /** @todo r=bird: This isn't doing *ANYTHING* useful. So, I've just disabled it.  */
     648    AssertPtrReturnVoid(pThis);
    1122649    LogFlowFuncEnter();
    1123650
    1124     HRESULT hr = directSoundCaptureStop(pThis, pStreamDS, true /* fFlush */);
    1125     if (FAILED(hr))
    1126         return hr;
    1127 
    1128     if (   pStreamDS
    1129         && pStreamDS->In.pDSCB)
    1130     {
    1131         DSLOG(("DSound: Closing capturing stream\n"));
    1132 
    1133         IDirectSoundCaptureBuffer8_Release(pStreamDS->In.pDSCB);
    1134         pStreamDS->In.pDSCB = NULL;
    1135     }
    1136 
    1137     LogFlowFunc(("Returning %Rhrc\n", hr));
    1138     return hr;
    1139 }
    1140 
    1141 static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
    1142                                       PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    1143 {
    1144     AssertPtrReturn(pThis,     E_POINTER);
    1145     AssertPtrReturn(pStreamDS, E_POINTER);
    1146     AssertPtrReturn(pCfgReq,   E_POINTER);
    1147     AssertPtrReturn(pCfgAcq,   E_POINTER);
    1148 
    1149     /** @todo r=bird: I cannot see any code populating pCfgAcq... */
    1150 
    1151     LogFlowFuncEnter();
    1152 
    1153     Assert(pStreamDS->In.pDSCB == NULL);
    1154 
    1155     DSLOG(("DSound: Opening capturing stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz,
    1156            PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned));
    1157 
    1158     WAVEFORMATEX wfx;
    1159     int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
    1160     if (RT_FAILURE(rc))
    1161         return E_INVALIDARG;
    1162 
    1163     /** @todo r=bird: Why is this called every time?  It triggers a device
    1164      * enumeration. Andy claimed on IRC that enumeration was only done once... */
    1165     dsoundUpdateStatusInternal(pThis);
    1166 
    1167     HRESULT hr = directSoundCaptureInterfaceCreate(pThis->Cfg.pGuidCapture, &pThis->pDSC);
    1168     if (FAILED(hr))
    1169         return hr;
    1170 
    1171     do /* For readability breaks... */
    1172     {
    1173         DSCBUFFERDESC bd;
    1174         RT_ZERO(bd);
    1175 
    1176         bd.dwSize        = sizeof(bd);
    1177         bd.lpwfxFormat   = &wfx;
    1178         bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
    1179 
    1180         DSLOG(("DSound: Requested capture buffer is %RU64ms (%ld bytes)\n",
    1181                PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes));
    1182 
    1183         LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
    1184         hr = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &bd, &pDSCB, NULL);
    1185         if (FAILED(hr))
    1186         {
    1187             if (hr == E_ACCESSDENIED)
    1188             {
    1189                 DSLOGREL(("DSound: Capturing input from host not possible, access denied\n"));
    1190             }
    1191             else
    1192                 DSLOGREL(("DSound: Creating capture buffer failed with %Rhrc\n", hr));
    1193             break;
    1194         }
    1195 
    1196         hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pStreamDS->In.pDSCB);
    1197         IDirectSoundCaptureBuffer_Release(pDSCB);
    1198         if (FAILED(hr))
    1199         {
    1200             DSLOGREL(("DSound: Querying interface for capture buffer failed with %Rhrc\n", hr));
    1201             break;
    1202         }
    1203 
    1204         /*
    1205          * Query the actual parameters.
    1206          */
    1207         DWORD offByteReadPos = 0;
    1208         hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pStreamDS->In.pDSCB, NULL, &offByteReadPos);
    1209         if (FAILED(hr))
    1210         {
    1211             offByteReadPos = 0;
    1212             DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
    1213         }
    1214 
    1215         RT_ZERO(wfx);
    1216         hr = IDirectSoundCaptureBuffer8_GetFormat(pStreamDS->In.pDSCB, &wfx, sizeof(wfx), NULL);
    1217         if (FAILED(hr))
    1218         {
    1219             DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr));
    1220             break;
    1221         }
    1222 
    1223         DSCBCAPS bc;
    1224         RT_ZERO(bc);
    1225         bc.dwSize = sizeof(bc);
    1226         hr = IDirectSoundCaptureBuffer8_GetCaps(pStreamDS->In.pDSCB, &bc);
    1227         if (FAILED(hr))
    1228         {
    1229             DSLOGREL(("DSound: Getting capture capabilities failed with %Rhrc\n", hr));
    1230             break;
    1231         }
    1232 
    1233         DSLOG(("DSound: Acquired capture buffer is %RU64ms (%ld bytes)\n",
    1234                PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes));
    1235 
    1236         DSLOG(("DSound: Capture format:\n"
    1237                "  dwBufferBytes   = %RI32\n"
    1238                "  dwFlags         = 0x%x\n"
    1239                "  wFormatTag      = %RI16\n"
    1240                "  nChannels       = %RI16\n"
    1241                "  nSamplesPerSec  = %RU32\n"
    1242                "  nAvgBytesPerSec = %RU32\n"
    1243                "  nBlockAlign     = %RI16\n"
    1244                "  wBitsPerSample  = %RI16\n"
    1245                "  cbSize          = %RI16\n",
    1246                bc.dwBufferBytes,
    1247                bc.dwFlags,
    1248                wfx.wFormatTag,
    1249                wfx.nChannels,
    1250                wfx.nSamplesPerSec,
    1251                wfx.nAvgBytesPerSec,
    1252                wfx.nBlockAlign,
    1253                wfx.wBitsPerSample,
    1254                wfx.cbSize));
    1255 
    1256         if (bc.dwBufferBytes & pStreamDS->uAlign)
    1257             DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
    1258                       bc.dwBufferBytes, pStreamDS->uAlign + 1));
    1259 
    1260         /* Initial state: reading at the initial capture position, no error. */
    1261         pStreamDS->In.offReadPos = 0;
    1262         pStreamDS->cbBufSize     = bc.dwBufferBytes;
    1263 
    1264         pThis->pDSStrmIn = pStreamDS;
    1265 
    1266         pCfgAcq->Backend.cFramesBufferSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
    1267 
    1268     } while (0);
    1269 
    1270     if (FAILED(hr))
    1271         directSoundCaptureClose(pThis, pStreamDS);
    1272 
    1273     LogFlowFunc(("Returning %Rhrc\n", hr));
    1274     return hr;
    1275 }
    1276 
    1277 static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
    1278 {
    1279     AssertPtrReturn(pThis,     E_POINTER);
    1280     AssertPtrReturn(pStreamDS, E_POINTER);
    1281 
     651    PDMAudioHostEnumDelete(&pThis->DeviceEnum);
     652    int rc = dsoundDevicesEnumerate(pThis, &pThis->DeviceEnum);
     653    if (RT_SUCCESS(rc))
     654    {
     655#if 0
     656        if (   pThis->fEnabledOut != RT_BOOL(cbCtx.cDevOut)
     657            || pThis->fEnabledIn  != RT_BOOL(cbCtx.cDevIn))
     658        {
     659            /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
     660             *        let the connector know that something has changed within the host backend. */
     661        }
     662#endif
     663        pThis->fEnabledIn  = PDMAudioHostEnumCountMatching(&pThis->DeviceEnum, PDMAUDIODIR_IN)  != 0;
     664        pThis->fEnabledOut = PDMAudioHostEnumCountMatching(&pThis->DeviceEnum, PDMAUDIODIR_OUT) != 0;
     665    }
     666
     667    LogFlowFuncLeaveRC(rc);
     668#else
    1282669    RT_NOREF(pThis);
    1283 
    1284     HRESULT hr = S_OK;
    1285 
    1286     if (pStreamDS->In.pDSCB)
    1287     {
    1288         DSLOG(("DSound: Stopping capture\n"));
    1289         hr = IDirectSoundCaptureBuffer_Stop(pStreamDS->In.pDSCB);
    1290     }
    1291 
    1292     if (SUCCEEDED(hr))
    1293     {
    1294         if (fFlush)
    1295              dsoundStreamReset(pThis, pStreamDS);
    1296     }
    1297 
    1298     if (FAILED(hr))
    1299         DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
    1300 
    1301     return hr;
    1302 }
    1303 
    1304 static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    1305 {
    1306     AssertPtrReturn(pThis,     E_POINTER);
    1307     AssertPtrReturn(pStreamDS, E_POINTER);
    1308 
    1309     HRESULT hr;
    1310     if (pStreamDS->In.pDSCB)
    1311     {
    1312         DWORD dwStatus;
    1313         hr = IDirectSoundCaptureBuffer8_GetStatus(pStreamDS->In.pDSCB, &dwStatus);
    1314         if (FAILED(hr))
    1315         {
    1316             DSLOGREL(("DSound: Retrieving capture status failed with %Rhrc\n", hr));
    1317         }
    1318         else
    1319         {
    1320             if (dwStatus & DSCBSTATUS_CAPTURING)
    1321             {
    1322                 DSLOG(("DSound: Already capturing\n"));
    1323             }
    1324             else
    1325             {
    1326                 const DWORD fFlags = DSCBSTART_LOOPING;
    1327 
    1328                 DSLOG(("DSound: Starting to capture\n"));
    1329                 hr = IDirectSoundCaptureBuffer8_Start(pStreamDS->In.pDSCB, fFlags);
    1330                 if (FAILED(hr))
    1331                     DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
    1332             }
    1333         }
    1334     }
    1335     else
    1336         hr = E_UNEXPECTED;
    1337 
    1338     LogFlowFunc(("Returning %Rhrc\n", hr));
    1339     return hr;
    1340 }
     670#endif
     671}
     672
     673
     674/*********************************************************************************************************************************
     675*   PDMIHOSTAUDIO                                                                                                                *
     676*********************************************************************************************************************************/
     677
     678/**
     679 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
     680 */
     681static DECLCALLBACK(int) drvHostDSoundHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
     682{
     683    RT_NOREF(pInterface);
     684    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
     685    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
     686
     687    RT_BZERO(pBackendCfg, sizeof(PPDMAUDIOBACKENDCFG));
     688
     689    pBackendCfg->cbStreamOut = sizeof(DSOUNDSTREAM);
     690    pBackendCfg->cbStreamIn  = sizeof(DSOUNDSTREAM);
     691
     692    RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "DirectSound");
     693
     694    pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
     695    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
     696
     697    return VINF_SUCCESS;
     698}
     699
    1341700
    1342701/**
     
    1399758}
    1400759
     760
    1401761/**
    1402762 * Callback for the capture device enumeration.
     
    1455815}
    1456816
    1457 /**
    1458  * Qqueries information for a given (DirectSound) device.
     817
     818/**
     819 * Queries information for a given (DirectSound) device.
    1459820 *
    1460821 * @returns VBox status code.
     
    16571018}
    16581019
     1020
    16591021/**
    16601022 * Does a (Re-)enumeration of the host's playback + capturing devices.
    16611023 *
    1662  * @return  IPRT status code.
     1024 * @return  VBox status code.
    16631025 * @param   pThis               Host audio driver instance.
    16641026 * @param   pDevEnm             Where to store the enumerated devices.
     
    17941156}
    17951157
    1796 /**
    1797  * Updates this host driver's internal status, according to the global, overall input/output
    1798  * state and all connected (native) audio streams.
    1799  *
    1800  * @todo r=bird: This is a 'ing waste of 'ing time!  We're doing this everytime
    1801  *       an 'ing stream is created and we doesn't 'ing use the information here
    1802  *       for any darn thing!  Given the reported slowness of enumeration and
    1803  *       issues with eh 'ing code the only appropriate response is:
    1804  *       AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARG!!!!!!!
     1158
     1159/**
     1160 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
     1161 */
     1162static DECLCALLBACK(int) drvHostDSoundHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)
     1163{
     1164    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
     1165    AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
     1166
     1167    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1168
     1169    int rc = RTCritSectEnter(&pThis->CritSect);
     1170    if (RT_SUCCESS(rc))
     1171    {
     1172        PDMAudioHostEnumInit(pDeviceEnum);
     1173        rc = dsoundDevicesEnumerate(pThis, pDeviceEnum);
     1174        if (RT_FAILURE(rc))
     1175            PDMAudioHostEnumDelete(pDeviceEnum);
     1176
     1177        int rc2 = RTCritSectLeave(&pThis->CritSect);
     1178        AssertRC(rc2);
     1179    }
     1180
     1181    LogFlowFunc(("Returning %Rrc\n", rc));
     1182    return rc;
     1183}
     1184
     1185
     1186/**
     1187 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
     1188 */
     1189static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDSoundHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
     1190{
     1191    RT_NOREF(enmDir);
     1192    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
     1193
     1194    return PDMAUDIOBACKENDSTS_RUNNING;
     1195}
     1196
     1197
     1198static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
     1199{
     1200    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
     1201    AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
     1202
     1203    RT_BZERO(pFmt, sizeof(WAVEFORMATEX));
     1204
     1205    pFmt->wFormatTag      = WAVE_FORMAT_PCM;
     1206    pFmt->nChannels       = PDMAudioPropsChannels(&pCfg->Props);
     1207    pFmt->wBitsPerSample  = PDMAudioPropsSampleBits(&pCfg->Props);
     1208    pFmt->nSamplesPerSec  = PDMAudioPropsHz(&pCfg->Props);
     1209    pFmt->nBlockAlign     = PDMAudioPropsFrameSize(&pCfg->Props);
     1210    pFmt->nAvgBytesPerSec = PDMAudioPropsFramesToBytes(&pCfg->Props, PDMAudioPropsHz(&pCfg->Props));
     1211    pFmt->cbSize          = 0; /* No extra data specified. */
     1212
     1213    return VINF_SUCCESS;
     1214}
     1215
     1216
     1217/**
     1218 * Resets the state of a DirectSound stream.
    18051219 *
    18061220 * @param   pThis               Host audio driver instance.
    1807  */
    1808 static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
    1809 {
    1810 #if 0 /** @todo r=bird: This isn't doing *ANYTHING* useful. So, I've just disabled it.  */
    1811     AssertPtrReturnVoid(pThis);
     1221 * @param   pStreamDS           Stream to reset state for.
     1222 */
     1223static void dsoundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1224{
     1225    RT_NOREF(pThis);
     1226
     1227    LogFunc(("Resetting %s\n",
     1228             pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback"));
     1229
     1230    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
     1231    {
     1232        pStreamDS->In.offReadPos = 0;
     1233        pStreamDS->In.cOverruns  = 0;
     1234
     1235        /* Also reset the DirectSound Capture Buffer (DSCB) by clearing all data to make sure
     1236         * not stale audio data is left. */
     1237        if (pStreamDS->In.pDSCB)
     1238        {
     1239            PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2;
     1240            HRESULT hr = directSoundCaptureLock(pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2,
     1241                                                0 /* Flags */);
     1242            if (SUCCEEDED(hr))
     1243            {
     1244                PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1));
     1245                if (pv2 && cb2)
     1246                    PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2));
     1247                directSoundCaptureUnlock(pStreamDS->In.pDSCB, pv1, pv2, cb1, cb2);
     1248            }
     1249        }
     1250    }
     1251    else if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
     1252    {
     1253        /* If draining was enagaged, make sure dsound has stopped playing. */
     1254        if (pStreamDS->Out.fDrain && pStreamDS->Out.pDSB)
     1255            pStreamDS->Out.pDSB->Stop();
     1256
     1257        pStreamDS->Out.fFirstTransfer = true;
     1258        pStreamDS->Out.fDrain         = false;
     1259        pStreamDS->Out.cUnderruns     = 0;
     1260
     1261        pStreamDS->Out.cbLastTransferred   = 0;
     1262        pStreamDS->Out.tsLastTransferredMs = 0;
     1263
     1264        pStreamDS->Out.cbTransferred = 0;
     1265        pStreamDS->Out.cbWritten = 0;
     1266
     1267        pStreamDS->Out.offWritePos = 0;
     1268        pStreamDS->Out.offPlayCursorLastPending = 0;
     1269        pStreamDS->Out.offPlayCursorLastPlayed = 0;
     1270
     1271        /* Also reset the DirectSound Buffer (DSB) by setting the position to 0 and clear all data to make sure
     1272         * not stale audio data is left. */
     1273        if (pStreamDS->Out.pDSB)
     1274        {
     1275            HRESULT hr = IDirectSoundBuffer8_SetCurrentPosition(pStreamDS->Out.pDSB, 0);
     1276            if (SUCCEEDED(hr))
     1277            {
     1278                PVOID pv1; PVOID pv2; DWORD cb1; DWORD cb2;
     1279                hr = directSoundPlayLock(pThis, pStreamDS, 0 /* Offset */, pStreamDS->cbBufSize, &pv1, &pv2, &cb1, &cb2,
     1280                                         0 /* Flags */);
     1281                if (SUCCEEDED(hr))
     1282                {
     1283                    PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv1, cb1, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb1));
     1284                    if (pv2 && cb2)
     1285                        PDMAudioPropsClearBuffer(&pStreamDS->Cfg.Props, pv2, cb2, PDMAUDIOPCMPROPS_B2F(&pStreamDS->Cfg.Props, cb2));
     1286                    directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2);
     1287                }
     1288            }
     1289        }
     1290    }
     1291
     1292#ifdef LOG_ENABLED
     1293    pStreamDS->Dbg.tsLastTransferredMs = 0;
     1294#endif
     1295}
     1296
     1297
     1298static HRESULT directSoundCaptureClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1299{
     1300    AssertPtrReturn(pThis,     E_POINTER);
     1301    AssertPtrReturn(pStreamDS, E_POINTER);
     1302
    18121303    LogFlowFuncEnter();
    18131304
    1814     PDMAudioHostEnumDelete(&pThis->DeviceEnum);
    1815     int rc = dsoundDevicesEnumerate(pThis, &pThis->DeviceEnum);
    1816     if (RT_SUCCESS(rc))
    1817     {
    1818 #if 0
    1819         if (   pThis->fEnabledOut != RT_BOOL(cbCtx.cDevOut)
    1820             || pThis->fEnabledIn  != RT_BOOL(cbCtx.cDevIn))
    1821         {
    1822             /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
    1823              *        let the connector know that something has changed within the host backend. */
    1824         }
    1825 #endif
    1826         pThis->fEnabledIn  = PDMAudioHostEnumCountMatching(&pThis->DeviceEnum, PDMAUDIODIR_IN)  != 0;
    1827         pThis->fEnabledOut = PDMAudioHostEnumCountMatching(&pThis->DeviceEnum, PDMAUDIODIR_OUT) != 0;
    1828     }
    1829 
    1830     LogFlowFuncLeaveRC(rc);
    1831 #else
    1832     RT_NOREF(pThis);
    1833 #endif
    1834 }
     1305    HRESULT hr = directSoundCaptureStop(pThis, pStreamDS, true /* fFlush */);
     1306    if (FAILED(hr))
     1307        return hr;
     1308
     1309    if (   pStreamDS
     1310        && pStreamDS->In.pDSCB)
     1311    {
     1312        DSLOG(("DSound: Closing capturing stream\n"));
     1313
     1314        IDirectSoundCaptureBuffer8_Release(pStreamDS->In.pDSCB);
     1315        pStreamDS->In.pDSCB = NULL;
     1316    }
     1317
     1318    LogFlowFunc(("Returning %Rhrc\n", hr));
     1319    return hr;
     1320}
     1321
     1322
     1323static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
     1324                                      PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1325{
     1326    AssertPtrReturn(pThis,     E_POINTER);
     1327    AssertPtrReturn(pStreamDS, E_POINTER);
     1328    AssertPtrReturn(pCfgReq,   E_POINTER);
     1329    AssertPtrReturn(pCfgAcq,   E_POINTER);
     1330
     1331    /** @todo r=bird: I cannot see any code populating pCfgAcq... */
     1332
     1333    LogFlowFuncEnter();
     1334
     1335    Assert(pStreamDS->In.pDSCB == NULL);
     1336
     1337    DSLOG(("DSound: Opening capturing stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz,
     1338           PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned));
     1339
     1340    WAVEFORMATEX wfx;
     1341    int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
     1342    if (RT_FAILURE(rc))
     1343        return E_INVALIDARG;
     1344
     1345    /** @todo r=bird: Why is this called every time?  It triggers a device
     1346     * enumeration. Andy claimed on IRC that enumeration was only done once... */
     1347    dsoundUpdateStatusInternal(pThis);
     1348
     1349    HRESULT hr = directSoundCaptureInterfaceCreate(pThis->Cfg.pGuidCapture, &pThis->pDSC);
     1350    if (FAILED(hr))
     1351        return hr;
     1352
     1353    do /* For readability breaks... */
     1354    {
     1355        DSCBUFFERDESC bd;
     1356        RT_ZERO(bd);
     1357
     1358        bd.dwSize        = sizeof(bd);
     1359        bd.lpwfxFormat   = &wfx;
     1360        bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
     1361
     1362        DSLOG(("DSound: Requested capture buffer is %RU64ms (%ld bytes)\n",
     1363               PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes));
     1364
     1365        LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
     1366        hr = IDirectSoundCapture_CreateCaptureBuffer(pThis->pDSC, &bd, &pDSCB, NULL);
     1367        if (FAILED(hr))
     1368        {
     1369            if (hr == E_ACCESSDENIED)
     1370            {
     1371                DSLOGREL(("DSound: Capturing input from host not possible, access denied\n"));
     1372            }
     1373            else
     1374                DSLOGREL(("DSound: Creating capture buffer failed with %Rhrc\n", hr));
     1375            break;
     1376        }
     1377
     1378        hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pStreamDS->In.pDSCB);
     1379        IDirectSoundCaptureBuffer_Release(pDSCB);
     1380        if (FAILED(hr))
     1381        {
     1382            DSLOGREL(("DSound: Querying interface for capture buffer failed with %Rhrc\n", hr));
     1383            break;
     1384        }
     1385
     1386        /*
     1387         * Query the actual parameters.
     1388         */
     1389        DWORD offByteReadPos = 0;
     1390        hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pStreamDS->In.pDSCB, NULL, &offByteReadPos);
     1391        if (FAILED(hr))
     1392        {
     1393            offByteReadPos = 0;
     1394            DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
     1395        }
     1396
     1397        RT_ZERO(wfx);
     1398        hr = IDirectSoundCaptureBuffer8_GetFormat(pStreamDS->In.pDSCB, &wfx, sizeof(wfx), NULL);
     1399        if (FAILED(hr))
     1400        {
     1401            DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr));
     1402            break;
     1403        }
     1404
     1405        DSCBCAPS bc;
     1406        RT_ZERO(bc);
     1407        bc.dwSize = sizeof(bc);
     1408        hr = IDirectSoundCaptureBuffer8_GetCaps(pStreamDS->In.pDSCB, &bc);
     1409        if (FAILED(hr))
     1410        {
     1411            DSLOGREL(("DSound: Getting capture capabilities failed with %Rhrc\n", hr));
     1412            break;
     1413        }
     1414
     1415        DSLOG(("DSound: Acquired capture buffer is %RU64ms (%ld bytes)\n",
     1416               PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes));
     1417
     1418        DSLOG(("DSound: Capture format:\n"
     1419               "  dwBufferBytes   = %RI32\n"
     1420               "  dwFlags         = 0x%x\n"
     1421               "  wFormatTag      = %RI16\n"
     1422               "  nChannels       = %RI16\n"
     1423               "  nSamplesPerSec  = %RU32\n"
     1424               "  nAvgBytesPerSec = %RU32\n"
     1425               "  nBlockAlign     = %RI16\n"
     1426               "  wBitsPerSample  = %RI16\n"
     1427               "  cbSize          = %RI16\n",
     1428               bc.dwBufferBytes,
     1429               bc.dwFlags,
     1430               wfx.wFormatTag,
     1431               wfx.nChannels,
     1432               wfx.nSamplesPerSec,
     1433               wfx.nAvgBytesPerSec,
     1434               wfx.nBlockAlign,
     1435               wfx.wBitsPerSample,
     1436               wfx.cbSize));
     1437
     1438        if (bc.dwBufferBytes & pStreamDS->uAlign)
     1439            DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
     1440                      bc.dwBufferBytes, pStreamDS->uAlign + 1));
     1441
     1442        /* Initial state: reading at the initial capture position, no error. */
     1443        pStreamDS->In.offReadPos = 0;
     1444        pStreamDS->cbBufSize     = bc.dwBufferBytes;
     1445
     1446        pThis->pDSStrmIn = pStreamDS;
     1447
     1448        pCfgAcq->Backend.cFramesBufferSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
     1449
     1450    } while (0);
     1451
     1452    if (FAILED(hr))
     1453        directSoundCaptureClose(pThis, pStreamDS);
     1454
     1455    LogFlowFunc(("Returning %Rhrc\n", hr));
     1456    return hr;
     1457}
     1458
     1459
     1460static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1461{
     1462    AssertPtrReturn(pThis,     E_POINTER);
     1463    AssertPtrReturn(pStreamDS, E_POINTER);
     1464
     1465    LogFlowFuncEnter();
     1466
     1467    HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
     1468    if (SUCCEEDED(hr))
     1469    {
     1470        DSLOG(("DSound: Closing playback stream\n"));
     1471        RTCritSectEnter(&pThis->CritSect);
     1472
     1473        if (pStreamDS->Out.pDSB)
     1474        {
     1475            IDirectSoundBuffer8_Release(pStreamDS->Out.pDSB);
     1476            pStreamDS->Out.pDSB = NULL;
     1477        }
     1478
     1479        pThis->pDSStrmOut = NULL;
     1480
     1481        RTCritSectLeave(&pThis->CritSect);
     1482    }
     1483
     1484    if (FAILED(hr))
     1485        DSLOGREL(("DSound: Stopping playback stream %p failed with %Rhrc\n", pStreamDS, hr));
     1486
     1487    return hr;
     1488}
     1489
     1490
     1491static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
     1492                                   PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1493{
     1494    AssertPtrReturn(pThis,     E_POINTER);
     1495    AssertPtrReturn(pStreamDS, E_POINTER);
     1496    AssertPtrReturn(pCfgReq,   E_POINTER);
     1497    AssertPtrReturn(pCfgAcq,   E_POINTER);
     1498
     1499/** @todo r=bird: I cannot see any code populating pCfgAcq... */
     1500
     1501    LogFlowFuncEnter();
     1502
     1503    Assert(pStreamDS->Out.pDSB == NULL);
     1504
     1505    DSLOG(("DSound: Opening playback stream (uHz=%RU32, cChannels=%RU8, cBits=%u, fSigned=%RTbool)\n", pCfgReq->Props.uHz,
     1506           PDMAudioPropsChannels(&pCfgReq->Props), PDMAudioPropsSampleBits(&pCfgReq->Props), pCfgReq->Props.fSigned));
     1507
     1508    WAVEFORMATEX wfx;
     1509    int rc = dsoundWaveFmtFromCfg(pCfgReq, &wfx);
     1510    if (RT_FAILURE(rc))
     1511        return E_INVALIDARG;
     1512
     1513    DSLOG(("DSound: Requested playback format:\n"
     1514           "  wFormatTag      = %RI16\n"
     1515           "  nChannels       = %RI16\n"
     1516           "  nSamplesPerSec  = %RU32\n"
     1517           "  nAvgBytesPerSec = %RU32\n"
     1518           "  nBlockAlign     = %RI16\n"
     1519           "  wBitsPerSample  = %RI16\n"
     1520           "  cbSize          = %RI16\n",
     1521           wfx.wFormatTag,
     1522           wfx.nChannels,
     1523           wfx.nSamplesPerSec,
     1524           wfx.nAvgBytesPerSec,
     1525           wfx.nBlockAlign,
     1526           wfx.wBitsPerSample,
     1527           wfx.cbSize));
     1528
     1529    /** @todo r=bird: Why is this called every time?  It triggers a device
     1530     * enumeration. Andy claimed on IRC that enumeration was only done once...
     1531     * It's generally a 'ing waste of time here too, as we dont really use any of
     1532     * the information we gather there. */
     1533    dsoundUpdateStatusInternal(pThis);
     1534
     1535    HRESULT hr = directSoundPlayInterfaceCreate(pThis->Cfg.pGuidPlay, &pThis->pDS);
     1536    if (FAILED(hr))
     1537        return hr;
     1538
     1539    do /* To use breaks. */
     1540    {
     1541        LPDIRECTSOUNDBUFFER pDSB = NULL;
     1542
     1543        DSBUFFERDESC bd;
     1544        RT_ZERO(bd);
     1545        bd.dwSize      = sizeof(bd);
     1546        bd.lpwfxFormat = &wfx;
     1547
     1548        /*
     1549         * As we reuse our (secondary) buffer for playing out data as it comes in,
     1550         * we're using this buffer as a so-called streaming buffer.
     1551         *
     1552         * See https://msdn.microsoft.com/en-us/library/windows/desktop/ee419014(v=vs.85).aspx
     1553         *
     1554         * However, as we do not want to use memory on the sound device directly
     1555         * (as most modern audio hardware on the host doesn't have this anyway),
     1556         * we're *not* going to use DSBCAPS_STATIC for that.
     1557         *
     1558         * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill
     1559         * of copying own buffer data to our secondary's Direct Sound buffer.
     1560         */
     1561        bd.dwFlags       = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
     1562        bd.dwBufferBytes = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize);
     1563
     1564        DSLOG(("DSound: Requested playback buffer is %RU64ms (%ld bytes)\n",
     1565               PDMAudioPropsBytesToMilli(&pCfgReq->Props, bd.dwBufferBytes), bd.dwBufferBytes));
     1566
     1567        hr = IDirectSound8_CreateSoundBuffer(pThis->pDS, &bd, &pDSB, NULL);
     1568        if (FAILED(hr))
     1569        {
     1570            DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr));
     1571            break;
     1572        }
     1573
     1574        /* "Upgrade" to IDirectSoundBuffer8 interface. */
     1575        hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (PVOID *)&pStreamDS->Out.pDSB);
     1576        IDirectSoundBuffer_Release(pDSB);
     1577        if (FAILED(hr))
     1578        {
     1579            DSLOGREL(("DSound: Querying playback sound buffer interface failed with %Rhrc\n", hr));
     1580            break;
     1581        }
     1582
     1583        /*
     1584         * Query the actual parameters set for this stream.
     1585         * Those might be different than the initially requested parameters.
     1586         */
     1587        RT_ZERO(wfx);
     1588        hr = IDirectSoundBuffer8_GetFormat(pStreamDS->Out.pDSB, &wfx, sizeof(wfx), NULL);
     1589        if (FAILED(hr))
     1590        {
     1591            DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr));
     1592            break;
     1593        }
     1594
     1595        DSBCAPS bc;
     1596        RT_ZERO(bc);
     1597        bc.dwSize = sizeof(bc);
     1598
     1599        hr = IDirectSoundBuffer8_GetCaps(pStreamDS->Out.pDSB, &bc);
     1600        if (FAILED(hr))
     1601        {
     1602            DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr));
     1603            break;
     1604        }
     1605
     1606        DSLOG(("DSound: Acquired playback buffer is %RU64ms (%ld bytes)\n",
     1607               PDMAudioPropsBytesToMilli(&pCfgReq->Props, bc.dwBufferBytes), bc.dwBufferBytes));
     1608
     1609        DSLOG(("DSound: Acquired playback format:\n"
     1610               "  dwBufferBytes   = %RI32\n"
     1611               "  dwFlags         = 0x%x\n"
     1612               "  wFormatTag      = %RI16\n"
     1613               "  nChannels       = %RI16\n"
     1614               "  nSamplesPerSec  = %RU32\n"
     1615               "  nAvgBytesPerSec = %RU32\n"
     1616               "  nBlockAlign     = %RI16\n"
     1617               "  wBitsPerSample  = %RI16\n"
     1618               "  cbSize          = %RI16\n",
     1619               bc.dwBufferBytes,
     1620               bc.dwFlags,
     1621               wfx.wFormatTag,
     1622               wfx.nChannels,
     1623               wfx.nSamplesPerSec,
     1624               wfx.nAvgBytesPerSec,
     1625               wfx.nBlockAlign,
     1626               wfx.wBitsPerSample,
     1627               wfx.cbSize));
     1628
     1629        if (bc.dwBufferBytes & pStreamDS->uAlign)
     1630            DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
     1631                      bc.dwBufferBytes, pStreamDS->uAlign + 1));
     1632
     1633        /*
     1634         * Initial state.
     1635         * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
     1636         * playback buffer position.
     1637         */
     1638        pStreamDS->cbBufSize = bc.dwBufferBytes;
     1639
     1640        pThis->pDSStrmOut = pStreamDS;
     1641
     1642        const uint32_t cfBufSize = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, pStreamDS->cbBufSize);
     1643
     1644        pCfgAcq->Backend.cFramesBufferSize    = cfBufSize;
     1645        pCfgAcq->Backend.cFramesPeriod        = cfBufSize / 4;
     1646        pCfgAcq->Backend.cFramesPreBuffering  = pCfgAcq->Backend.cFramesPeriod * 2;
     1647
     1648    } while (0);
     1649
     1650    if (FAILED(hr))
     1651        directSoundPlayClose(pThis, pStreamDS);
     1652
     1653    return hr;
     1654}
     1655
     1656
     1657static void dsoundPlayClearBuffer(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1658{
     1659    AssertPtrReturnVoid(pStreamDS);
     1660
     1661    PPDMAUDIOPCMPROPS pProps = &pStreamDS->Cfg.Props;
     1662
     1663    HRESULT hr = IDirectSoundBuffer_SetCurrentPosition(pStreamDS->Out.pDSB, 0 /* Position */);
     1664    if (FAILED(hr))
     1665        DSLOGREL(("DSound: Setting current position to 0 when clearing buffer failed with %Rhrc\n", hr));
     1666
     1667    PVOID pv1;
     1668    hr = directSoundPlayLock(pThis, pStreamDS,
     1669                             0 /* dwOffset */, pStreamDS->cbBufSize,
     1670                             &pv1, NULL, 0, 0, DSBLOCK_ENTIREBUFFER);
     1671    if (SUCCEEDED(hr))
     1672    {
     1673        PDMAudioPropsClearBuffer(pProps, pv1, pStreamDS->cbBufSize, PDMAUDIOPCMPROPS_B2F(pProps, pStreamDS->cbBufSize));
     1674
     1675        directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, NULL, 0, 0);
     1676
     1677        /* Make sure to get the last playback position and current write position from DirectSound again.
     1678         * Those positions in theory could have changed, re-fetch them to be sure. */
     1679        DWORD offPlay  = 0;
     1680        DWORD offWrite = 0;
     1681        hr = IDirectSoundBuffer_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlay, &offWrite);
     1682        if (SUCCEEDED(hr))
     1683        {
     1684            pStreamDS->Out.offPlayCursorLastPlayed = offPlay;
     1685            pStreamDS->Out.offWritePos             = offWrite;
     1686        }
     1687        else
     1688            DSLOGREL(("DSound: Re-fetching current position when clearing buffer failed with %Rhrc\n", hr));
     1689    }
     1690}
     1691
    18351692
    18361693static int dsoundCreateStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
     
    18551712    return rc;
    18561713}
     1714
     1715
     1716static int dsoundCreateStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
     1717                                PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1718{
     1719    LogFunc(("pStreamDS=%p, pCfgReq=%p, enmRecSource=%s\n",
     1720             pStreamDS, pCfgReq, PDMAudioRecSrcGetName(pCfgReq->u.enmSrc)));
     1721
     1722
     1723    /* Try to open capture in case the device is already there. */
     1724    int rc;
     1725    HRESULT hr = directSoundCaptureOpen(pThis, pStreamDS, pCfgReq, pCfgAcq);
     1726    if (SUCCEEDED(hr))
     1727    {
     1728        rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq);
     1729        if (RT_SUCCESS(rc))
     1730            dsoundStreamReset(pThis, pStreamDS);
     1731    }
     1732    else
     1733        rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
     1734
     1735    return rc;
     1736}
     1737
     1738
     1739/**
     1740 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
     1741 */
     1742static DECLCALLBACK(int) drvHostDSoundHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     1743                                                      PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     1744{
     1745    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1746    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     1747    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
     1748    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
     1749
     1750    PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1751    PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
     1752
     1753    int rc;
     1754    if (pCfgReq->enmDir == PDMAUDIODIR_IN)
     1755        rc = dsoundCreateStreamIn(pThis,  pStreamDS, pCfgReq, pCfgAcq);
     1756    else
     1757        rc = dsoundCreateStreamOut(pThis, pStreamDS, pCfgReq, pCfgAcq);
     1758
     1759    if (RT_SUCCESS(rc))
     1760    {
     1761        /** @todo already copied   */
     1762        rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq);
     1763        if (RT_SUCCESS(rc))
     1764            rc = RTCritSectInit(&pStreamDS->CritSect);
     1765    }
     1766
     1767    return rc;
     1768}
     1769
     1770
     1771static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1772{
     1773    LogFlowFuncEnter();
     1774
     1775    HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
     1776    if (SUCCEEDED(hr))
     1777    {
     1778        hr = directSoundPlayClose(pThis, pStreamDS);
     1779        if (FAILED(hr))
     1780            return VERR_GENERAL_FAILURE; /** @todo Fix. */
     1781    }
     1782
     1783    return VINF_SUCCESS;
     1784}
     1785
     1786
     1787static int dsoundDestroyStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1788{
     1789    LogFlowFuncEnter();
     1790
     1791    directSoundCaptureClose(pThis, pStreamDS);
     1792
     1793    return VINF_SUCCESS;
     1794}
     1795
     1796
     1797/**
     1798 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
     1799 */
     1800static DECLCALLBACK(int) drvHostDSoundHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1801{
     1802    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     1803    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     1804
     1805    PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1806    PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
     1807
     1808    int rc;
     1809    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
     1810        rc = dsoundDestroyStreamIn(pThis, pStreamDS);
     1811    else
     1812        rc = dsoundDestroyStreamOut(pThis, pStreamDS);
     1813
     1814    if (RT_SUCCESS(rc))
     1815    {
     1816        if (RTCritSectIsInitialized(&pStreamDS->CritSect))
     1817            rc = RTCritSectDelete(&pStreamDS->CritSect);
     1818    }
     1819
     1820    return rc;
     1821}
     1822
     1823
     1824/**
     1825 * Enables or disables a stream.
     1826 *
     1827 * @return  VBox status code.
     1828 * @param   pThis               Host audio driver instance.
     1829 * @param   pStreamDS           Stream to enable / disable.
     1830 * @param   fEnable             Whether to enable or disable the stream.
     1831 */
     1832static int dsoundStreamEnable(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fEnable)
     1833{
     1834    RT_NOREF(pThis);
     1835
     1836    LogFunc(("%s %s\n",
     1837             fEnable ? "Enabling" : "Disabling",
     1838             pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN ? "capture" : "playback"));
     1839
     1840    if (fEnable)
     1841        dsoundStreamReset(pThis, pStreamDS);
     1842
     1843    pStreamDS->fEnabled = fEnable;
     1844
     1845    return VINF_SUCCESS;
     1846}
     1847
     1848
     1849/**
     1850 * Starts playing a DirectSound stream.
     1851 *
     1852 * @return  HRESULT
     1853 * @param   pThis               Host audio driver instance.
     1854 * @param   pStreamDS           Stream to start playing.
     1855 */
     1856static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     1857{
     1858    HRESULT hr = S_OK;
     1859
     1860    DWORD fFlags = DSCBSTART_LOOPING;
     1861
     1862    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     1863    {
     1864        DSLOG(("DSound: Starting playback\n"));
     1865        hr = IDirectSoundBuffer8_Play(pStreamDS->Out.pDSB, 0, 0, fFlags);
     1866        if (   SUCCEEDED(hr)
     1867            || hr != DSERR_BUFFERLOST)
     1868            break;
     1869        LogFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
     1870        directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
     1871    }
     1872
     1873    return hr;
     1874}
     1875
     1876
     1877static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
     1878{
     1879    AssertPtrReturn(pThis,     E_POINTER);
     1880    AssertPtrReturn(pStreamDS, E_POINTER);
     1881
     1882    HRESULT hr = S_OK;
     1883
     1884    if (pStreamDS->Out.pDSB)
     1885    {
     1886        DSLOG(("DSound: Stopping playback\n"));
     1887        hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
     1888        if (FAILED(hr))
     1889        {
     1890            hr = directSoundPlayRestore(pThis, pStreamDS->Out.pDSB);
     1891            if (FAILED(hr)) /** @todo shouldn't this be a SUCCEEDED? */
     1892                hr = IDirectSoundBuffer8_Stop(pStreamDS->Out.pDSB);
     1893        }
     1894    }
     1895
     1896    if (SUCCEEDED(hr))
     1897    {
     1898        if (fFlush)
     1899            dsoundStreamReset(pThis, pStreamDS);
     1900    }
     1901
     1902    if (FAILED(hr))
     1903        DSLOGREL(("DSound: %s playback failed with %Rhrc\n", fFlush ? "Stopping" : "Pausing", hr));
     1904
     1905    return hr;
     1906}
     1907
    18571908
    18581909static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, PDMAUDIOSTREAMCMD enmStreamCmd)
     
    19492000}
    19502001
    1951 /**
    1952  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
    1953  */
    1954 static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    1955                                                     const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
    1956 {
    1957     PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
    1958     PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
    1959     AssertPtrReturn(pStreamDS, 0);
    1960     AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    1961     AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
    1962     AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
    1963 
    1964     if (pStreamDS->fEnabled)
    1965         AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2);
     2002
     2003static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
     2004{
     2005    AssertPtrReturn(pThis,     E_POINTER);
     2006    AssertPtrReturn(pStreamDS, E_POINTER);
     2007
     2008    HRESULT hr;
     2009    if (pStreamDS->In.pDSCB)
     2010    {
     2011        DWORD dwStatus;
     2012        hr = IDirectSoundCaptureBuffer8_GetStatus(pStreamDS->In.pDSCB, &dwStatus);
     2013        if (FAILED(hr))
     2014        {
     2015            DSLOGREL(("DSound: Retrieving capture status failed with %Rhrc\n", hr));
     2016        }
     2017        else
     2018        {
     2019            if (dwStatus & DSCBSTATUS_CAPTURING)
     2020            {
     2021                DSLOG(("DSound: Already capturing\n"));
     2022            }
     2023            else
     2024            {
     2025                const DWORD fFlags = DSCBSTART_LOOPING;
     2026
     2027                DSLOG(("DSound: Starting to capture\n"));
     2028                hr = IDirectSoundCaptureBuffer8_Start(pStreamDS->In.pDSCB, fFlags);
     2029                if (FAILED(hr))
     2030                    DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
     2031            }
     2032        }
     2033    }
    19662034    else
    1967     {
    1968         Log2Func(("Stream disabled, skipping\n"));
    1969         return VINF_SUCCESS;
    1970     }
    1971 
    1972 /** @todo Any condition under which we should call dsoundUpdateStatusInternal(pThis) here?
    1973  * The old code thought it did so in case of failure, only it couldn't ever fails, so it never did. */
    1974 
    1975     /*
    1976      * Transfer loop.
    1977      */
    1978     uint32_t cbWritten = 0;
    1979     while (cbBuf > 0)
    1980     {
    1981         /*
    1982          * Figure out how much we can possibly write.
    1983          */
    1984         DWORD offPlayCursor = 0;
    1985         DWORD cbWritable    = 0;
    1986         int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbWritable, &offPlayCursor);
    1987         AssertRCReturn(rc, rc);
    1988         if (cbWritable < pStreamDS->Cfg.Props.cbFrame)
    1989             break;
    1990 
    1991         uint32_t const cbToWrite = RT_MIN(cbWritable, cbBuf);
    1992         Log3Func(("offPlay=%#x offWritePos=%#x -> cbWritable=%#x cbToWrite=%#x%s%s\n", offPlayCursor, pStreamDS->Out.offWritePos,
    1993                   cbWritable, cbToWrite, pStreamDS->Out.fFirstTransfer ? " first" : "", pStreamDS->Out.fDrain ? " drain" : ""));
    1994 
    1995         /*
    1996          * Lock that amount of buffer.
    1997          */
    1998         PVOID pv1 = NULL;
    1999         DWORD cb1 = 0;
    2000         PVOID pv2 = NULL;
    2001         DWORD cb2 = 0;
    2002         HRESULT hrc = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbToWrite,
    2003                                           &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/);
    2004         AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
    2005         //AssertMsg(cb1 + cb2 == cbToWrite, ("%#x + %#x vs %#x\n", cb1, cb2, cbToWrite));
    2006 
    2007         /*
    2008          * Copy over the data.
    2009          */
    2010         memcpy(pv1, pvBuf, cb1);
    2011         pvBuf      = (uint8_t *)pvBuf + cb1;
    2012         cbBuf     -= cb1;
    2013         cbWritten += cb1;
    2014 
    2015         if (pv2)
    2016         {
    2017             memcpy(pv2, pvBuf, cb2);
    2018             pvBuf      = (uint8_t *)pvBuf + cb2;
    2019             cbBuf     -= cb2;
    2020             cbWritten += cb2;
    2021         }
    2022 
    2023         /*
    2024          * Unlock and update the write position.
    2025          */
    2026         directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2); /** @todo r=bird: pThis + pDSB parameters here for Unlock, but only pThis for Lock. Why? */
    2027         pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;
    2028 
    2029         /*
    2030          * If this was the first chunk, kick off playing.
    2031          */
    2032         if (!pStreamDS->Out.fFirstTransfer)
    2033         { /* likely */ }
    2034         else
    2035         {
    2036             *pcbWritten = cbWritten;
    2037             hrc = directSoundPlayStart(pThis, pStreamDS);
    2038             AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
    2039             pStreamDS->Out.fFirstTransfer = false;
    2040         }
    2041     }
    2042 
    2043     /*
    2044      * Done.
    2045      */
    2046     *pcbWritten = cbWritten;
    2047 
    2048     pStreamDS->Out.cbTransferred += cbWritten;
    2049     if (cbWritten)
    2050     {
    2051         uint64_t const msPrev = pStreamDS->Out.tsLastTransferredMs;
    2052         pStreamDS->Out.cbLastTransferred   = cbWritten;
    2053         pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();
    2054         LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64 cMsDelta=%RU64\n",
    2055                      cbWritten, pStreamDS->Out.tsLastTransferredMs, msPrev ? pStreamDS->Out.tsLastTransferredMs - msPrev : 0));
    2056     }
    2057     return VINF_SUCCESS;
    2058 }
    2059 
    2060 static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    2061 {
    2062     LogFlowFuncEnter();
    2063 
    2064     HRESULT hr = directSoundPlayStop(pThis, pStreamDS, true /* fFlush */);
     2035        hr = E_UNEXPECTED;
     2036
     2037    LogFlowFunc(("Returning %Rhrc\n", hr));
     2038    return hr;
     2039}
     2040
     2041
     2042static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush)
     2043{
     2044    AssertPtrReturn(pThis,     E_POINTER);
     2045    AssertPtrReturn(pStreamDS, E_POINTER);
     2046
     2047    RT_NOREF(pThis);
     2048
     2049    HRESULT hr = S_OK;
     2050
     2051    if (pStreamDS->In.pDSCB)
     2052    {
     2053        DSLOG(("DSound: Stopping capture\n"));
     2054        hr = IDirectSoundCaptureBuffer_Stop(pStreamDS->In.pDSCB);
     2055    }
     2056
    20652057    if (SUCCEEDED(hr))
    20662058    {
    2067         hr = directSoundPlayClose(pThis, pStreamDS);
    2068         if (FAILED(hr))
    2069             return VERR_GENERAL_FAILURE; /** @todo Fix. */
    2070     }
    2071 
    2072     return VINF_SUCCESS;
    2073 }
    2074 
    2075 static int dsoundCreateStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS,
    2076                                 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2077 {
    2078     LogFunc(("pStreamDS=%p, pCfgReq=%p, enmRecSource=%s\n",
    2079              pStreamDS, pCfgReq, PDMAudioRecSrcGetName(pCfgReq->u.enmSrc)));
    2080 
    2081 
    2082     /* Try to open capture in case the device is already there. */
    2083     int rc;
    2084     HRESULT hr = directSoundCaptureOpen(pThis, pStreamDS, pCfgReq, pCfgAcq);
    2085     if (SUCCEEDED(hr))
    2086     {
    2087         rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq);
    2088         if (RT_SUCCESS(rc))
    2089             dsoundStreamReset(pThis, pStreamDS);
    2090     }
    2091     else
    2092         rc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
    2093 
    2094     return rc;
    2095 }
     2059        if (fFlush)
     2060             dsoundStreamReset(pThis, pStreamDS);
     2061    }
     2062
     2063    if (FAILED(hr))
     2064        DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
     2065
     2066    return hr;
     2067}
     2068
    20962069
    20972070static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, PDMAUDIOSTREAMCMD enmStreamCmd)
     
    21602133}
    21612134
     2135
     2136/**
     2137 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
     2138 */
     2139static DECLCALLBACK(int) drvHostDSoundHA_StreamControl(PPDMIHOSTAUDIO pInterface,
     2140                                                       PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
     2141{
     2142    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     2143    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     2144
     2145    PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     2146    PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
     2147
     2148    int rc;
     2149    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
     2150        rc = dsoundControlStreamIn(pThis,  pStreamDS, enmStreamCmd);
     2151    else
     2152        rc = dsoundControlStreamOut(pThis, pStreamDS, enmStreamCmd);
     2153
     2154    return rc;
     2155}
     2156
     2157
     2158/**
     2159 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
     2160 */
     2161static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2162{
     2163    /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
     2164    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2165    AssertPtrReturn(pStreamDS, 0);
     2166    Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN);
     2167
     2168    if (pStreamDS->fEnabled)
     2169    {
     2170        /* This is the same calculation as for StreamGetPending. */
     2171        AssertPtr(pStreamDS->In.pDSCB);
     2172        DWORD   offCaptureCursor = 0;
     2173        DWORD   offReadCursor    = 0;
     2174        HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor);
     2175        if (SUCCEEDED(hrc))
     2176        {
     2177            uint32_t cbPending = dsoundRingDistance(offCaptureCursor, offReadCursor, pStreamDS->cbBufSize);
     2178            Log3Func(("cbPending=%RU32\n", cbPending));
     2179            return cbPending;
     2180        }
     2181        AssertMsgFailed(("hrc=%Rhrc\n", hrc));
     2182    }
     2183
     2184    return 0;
     2185}
     2186
     2187
     2188/**
     2189 * Retrieves the number of free bytes available for writing to a DirectSound output stream.
     2190 *
     2191 * @return  VBox status code. VERR_NOT_AVAILABLE if unable to determine or the
     2192 *          buffer was not recoverable.
     2193 * @param   pThis               Host audio driver instance.
     2194 * @param   pStreamDS           DirectSound output stream to retrieve number for.
     2195 * @param   pdwFree             Where to return the free amount on success.
     2196 * @param   poffPlayCursor      Where to return the play cursor offset.
     2197 */
     2198static int dsoundGetFreeOut(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, DWORD *pdwFree, DWORD *poffPlayCursor)
     2199{
     2200    AssertPtrReturn(pThis,     VERR_INVALID_POINTER);
     2201    AssertPtrReturn(pStreamDS, VERR_INVALID_POINTER);
     2202    AssertPtrReturn(pdwFree,   VERR_INVALID_POINTER);
     2203    AssertPtr(poffPlayCursor);
     2204
     2205    Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT); /* Paranoia. */
     2206
     2207    LPDIRECTSOUNDBUFFER8 pDSB = pStreamDS->Out.pDSB;
     2208    if (!pDSB)
     2209    {
     2210        AssertPtr(pDSB);
     2211        return VERR_INVALID_POINTER;
     2212    }
     2213
     2214    HRESULT hr = S_OK;
     2215
     2216    /* Get the current play position which is used for calculating the free space in the buffer. */
     2217    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     2218    {
     2219        DWORD offPlayCursor  = 0;
     2220        DWORD offWriteCursor = 0;
     2221        hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &offPlayCursor, &offWriteCursor);
     2222        if (SUCCEEDED(hr))
     2223        {
     2224            int32_t cbDiff = offWriteCursor - offPlayCursor;
     2225            if (cbDiff < 0)
     2226                cbDiff += pStreamDS->cbBufSize;
     2227
     2228            int32_t cbFree = offPlayCursor - pStreamDS->Out.offWritePos;
     2229            if (cbFree < 0)
     2230                cbFree += pStreamDS->cbBufSize;
     2231
     2232            if (cbFree > (int32_t)pStreamDS->cbBufSize - cbDiff)
     2233            {
     2234                /** @todo count/log these. */
     2235                pStreamDS->Out.offWritePos = offWriteCursor;
     2236                cbFree = pStreamDS->cbBufSize - cbDiff;
     2237            }
     2238
     2239            /* When starting to use a DirectSound buffer, offPlayCursor and offWriteCursor
     2240             * both point at position 0, so we won't be able to detect how many bytes
     2241             * are writable that way.
     2242             *
     2243             * So use our per-stream written indicator to see if we just started a stream. */
     2244            if (pStreamDS->Out.cbWritten == 0)
     2245                cbFree = pStreamDS->cbBufSize;
     2246
     2247            DSLOGREL(("DSound: offPlayCursor=%RU32, offWriteCursor=%RU32, offWritePos=%RU32 -> cbFree=%RI32\n",
     2248                      offPlayCursor, offWriteCursor, pStreamDS->Out.offWritePos, cbFree));
     2249
     2250            *pdwFree = cbFree;
     2251            *poffPlayCursor = offPlayCursor;
     2252            return VINF_SUCCESS;
     2253        }
     2254
     2255        if (hr != DSERR_BUFFERLOST) /** @todo MSDN doesn't state this error for GetCurrentPosition(). */
     2256            break;
     2257
     2258        LogFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
     2259
     2260        directSoundPlayRestore(pThis, pDSB);
     2261    }
     2262
     2263    if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
     2264        DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
     2265
     2266    LogFunc(("Failed with %Rhrc\n", hr));
     2267
     2268    *poffPlayCursor = pStreamDS->cbBufSize;
     2269    return VERR_NOT_AVAILABLE;
     2270}
     2271
     2272
     2273/**
     2274 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
     2275 */
     2276static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2277{
     2278    PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
     2279    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2280    AssertPtrReturn(pStreamDS, 0);
     2281
     2282    DWORD           cbFree    = 0;
     2283    DWORD           offIgn    = 0;
     2284    int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree, &offIgn);
     2285    AssertRCReturn(rc, 0);
     2286
     2287    return cbFree;
     2288}
     2289
     2290#if 0 /* This isn't working as the write cursor is more a function of time than what we do.
     2291         Previously we only reported the pre-buffering status anyway, so no harm. */
     2292/**
     2293 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
     2294 */
     2295static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2296{
     2297    /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
     2298    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2299    AssertPtrReturn(pStreamDS, 0);
     2300
     2301    if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
     2302    {
     2303        /* This is a similar calculation as for StreamGetReadable, only for an output buffer. */
     2304        AssertPtr(pStreamDS->In.pDSCB);
     2305        DWORD   offPlayCursor  = 0;
     2306        DWORD   offWriteCursor = 0;
     2307        HRESULT hrc = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor);
     2308        if (SUCCEEDED(hrc))
     2309        {
     2310            uint32_t cbPending = dsoundRingDistance(offWriteCursor, offPlayCursor, pStreamDS->cbBufSize);
     2311            Log3Func(("cbPending=%RU32\n", cbPending));
     2312            return cbPending;
     2313        }
     2314        AssertMsgFailed(("hrc=%Rhrc\n", hrc));
     2315    }
     2316    /* else: For input streams we never have any pending data. */
     2317
     2318    return 0;
     2319}
     2320#endif
     2321
     2322/**
     2323 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
     2324 */
     2325static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     2326{
     2327    RT_NOREF(pInterface);
     2328    AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);
     2329
     2330    PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
     2331
     2332    PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED;
     2333
     2334    if (pStreamDS->fEnabled)
     2335        fStrmStatus |= PDMAUDIOSTREAMSTS_FLAGS_ENABLED;
     2336
     2337    return fStrmStatus;
     2338}
     2339
     2340
     2341/**
     2342 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
     2343 */
     2344static DECLCALLBACK(int) drvHostDSoundHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
     2345                                                    const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     2346{
     2347    PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
     2348    PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
     2349    AssertPtrReturn(pStreamDS, 0);
     2350    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     2351    AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
     2352    AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
     2353
     2354    if (pStreamDS->fEnabled)
     2355        AssertReturn(pStreamDS->cbBufSize, VERR_INTERNAL_ERROR_2);
     2356    else
     2357    {
     2358        Log2Func(("Stream disabled, skipping\n"));
     2359        return VINF_SUCCESS;
     2360    }
     2361
     2362/** @todo Any condition under which we should call dsoundUpdateStatusInternal(pThis) here?
     2363 * The old code thought it did so in case of failure, only it couldn't ever fails, so it never did. */
     2364
     2365    /*
     2366     * Transfer loop.
     2367     */
     2368    uint32_t cbWritten = 0;
     2369    while (cbBuf > 0)
     2370    {
     2371        /*
     2372         * Figure out how much we can possibly write.
     2373         */
     2374        DWORD offPlayCursor = 0;
     2375        DWORD cbWritable    = 0;
     2376        int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbWritable, &offPlayCursor);
     2377        AssertRCReturn(rc, rc);
     2378        if (cbWritable < pStreamDS->Cfg.Props.cbFrame)
     2379            break;
     2380
     2381        uint32_t const cbToWrite = RT_MIN(cbWritable, cbBuf);
     2382        Log3Func(("offPlay=%#x offWritePos=%#x -> cbWritable=%#x cbToWrite=%#x%s%s\n", offPlayCursor, pStreamDS->Out.offWritePos,
     2383                  cbWritable, cbToWrite, pStreamDS->Out.fFirstTransfer ? " first" : "", pStreamDS->Out.fDrain ? " drain" : ""));
     2384
     2385        /*
     2386         * Lock that amount of buffer.
     2387         */
     2388        PVOID pv1 = NULL;
     2389        DWORD cb1 = 0;
     2390        PVOID pv2 = NULL;
     2391        DWORD cb2 = 0;
     2392        HRESULT hrc = directSoundPlayLock(pThis, pStreamDS, pStreamDS->Out.offWritePos, cbToWrite,
     2393                                          &pv1, &pv2, &cb1, &cb2, 0 /*dwFlags*/);
     2394        AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2395        //AssertMsg(cb1 + cb2 == cbToWrite, ("%#x + %#x vs %#x\n", cb1, cb2, cbToWrite));
     2396
     2397        /*
     2398         * Copy over the data.
     2399         */
     2400        memcpy(pv1, pvBuf, cb1);
     2401        pvBuf      = (uint8_t *)pvBuf + cb1;
     2402        cbBuf     -= cb1;
     2403        cbWritten += cb1;
     2404
     2405        if (pv2)
     2406        {
     2407            memcpy(pv2, pvBuf, cb2);
     2408            pvBuf      = (uint8_t *)pvBuf + cb2;
     2409            cbBuf     -= cb2;
     2410            cbWritten += cb2;
     2411        }
     2412
     2413        /*
     2414         * Unlock and update the write position.
     2415         */
     2416        directSoundPlayUnlock(pThis, pStreamDS->Out.pDSB, pv1, pv2, cb1, cb2); /** @todo r=bird: pThis + pDSB parameters here for Unlock, but only pThis for Lock. Why? */
     2417        pStreamDS->Out.offWritePos = (pStreamDS->Out.offWritePos + cb1 + cb2) % pStreamDS->cbBufSize;
     2418
     2419        /*
     2420         * If this was the first chunk, kick off playing.
     2421         */
     2422        if (!pStreamDS->Out.fFirstTransfer)
     2423        { /* likely */ }
     2424        else
     2425        {
     2426            *pcbWritten = cbWritten;
     2427            hrc = directSoundPlayStart(pThis, pStreamDS);
     2428            AssertMsgReturn(SUCCEEDED(hrc), ("%Rhrc\n", hrc), VERR_ACCESS_DENIED); /** @todo translate these status codes already! */
     2429            pStreamDS->Out.fFirstTransfer = false;
     2430        }
     2431    }
     2432
     2433    /*
     2434     * Done.
     2435     */
     2436    *pcbWritten = cbWritten;
     2437
     2438    pStreamDS->Out.cbTransferred += cbWritten;
     2439    if (cbWritten)
     2440    {
     2441        uint64_t const msPrev = pStreamDS->Out.tsLastTransferredMs;
     2442        pStreamDS->Out.cbLastTransferred   = cbWritten;
     2443        pStreamDS->Out.tsLastTransferredMs = RTTimeMilliTS();
     2444        LogFlowFunc(("cbLastTransferred=%RU32, tsLastTransferredMs=%RU64 cMsDelta=%RU64\n",
     2445                     cbWritten, pStreamDS->Out.tsLastTransferredMs, msPrev ? pStreamDS->Out.tsLastTransferredMs - msPrev : 0));
     2446    }
     2447    return VINF_SUCCESS;
     2448}
     2449
     2450
    21622451/**
    21632452 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
     
    22752564}
    22762565
    2277 static int dsoundDestroyStreamIn(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS)
    2278 {
     2566
     2567/*********************************************************************************************************************************
     2568*   PDMDRVINS::IBase Interface                                                                                                   *
     2569*********************************************************************************************************************************/
     2570
     2571/**
     2572 * @callback_method_impl{PDMIBASE,pfnQueryInterface}
     2573 */
     2574static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     2575{
     2576    PPDMDRVINS     pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
     2577    PDRVHOSTDSOUND pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
     2578
     2579    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
     2580    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
     2581    return NULL;
     2582}
     2583
     2584
     2585/*********************************************************************************************************************************
     2586*   PDMDRVREG Interface                                                                                                          *
     2587*********************************************************************************************************************************/
     2588
     2589/**
     2590 * @callback_method_impl{FNPDMDRVDESTRUCT, pfnDestruct}
     2591 */
     2592static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
     2593{
     2594    PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
     2595    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
     2596
    22792597    LogFlowFuncEnter();
    22802598
    2281     directSoundCaptureClose(pThis, pStreamDS);
    2282 
    2283     return VINF_SUCCESS;
    2284 }
    2285 
    2286 /**
    2287  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
    2288  */
    2289 static DECLCALLBACK(int) drvHostDSoundHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
    2290 {
    2291     RT_NOREF(pInterface);
    2292     AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
    2293     AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
    2294 
    2295     RT_BZERO(pBackendCfg, sizeof(PPDMAUDIOBACKENDCFG));
    2296 
    2297     pBackendCfg->cbStreamOut = sizeof(DSOUNDSTREAM);
    2298     pBackendCfg->cbStreamIn  = sizeof(DSOUNDSTREAM);
    2299 
    2300     RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "DirectSound");
    2301 
    2302     pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
    2303     pBackendCfg->cMaxStreamsOut = UINT32_MAX;
    2304 
    2305     return VINF_SUCCESS;
    2306 }
    2307 
    2308 /**
    2309  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
    2310  */
    2311 static DECLCALLBACK(int) drvHostDSoundHA_GetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)
    2312 {
    2313     AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
    2314     AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
    2315 
    2316     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2317 
    2318     int rc = RTCritSectEnter(&pThis->CritSect);
    2319     if (RT_SUCCESS(rc))
    2320     {
    2321         PDMAudioHostEnumInit(pDeviceEnum);
    2322         rc = dsoundDevicesEnumerate(pThis, pDeviceEnum);
    2323         if (RT_FAILURE(rc))
    2324             PDMAudioHostEnumDelete(pDeviceEnum);
    2325 
    2326         int rc2 = RTCritSectLeave(&pThis->CritSect);
    2327         AssertRC(rc2);
    2328     }
    2329 
    2330     LogFlowFunc(("Returning %Rrc\n", rc));
    2331     return rc;
     2599#ifdef VBOX_WITH_AUDIO_MMNOTIFICATION_CLIENT
     2600    if (pThis->m_pNotificationClient)
     2601    {
     2602        pThis->m_pNotificationClient->Unregister();
     2603        pThis->m_pNotificationClient->Release();
     2604
     2605        pThis->m_pNotificationClient = NULL;
     2606    }
     2607#endif
     2608
     2609    PDMAudioHostEnumDelete(&pThis->DeviceEnum);
     2610
     2611    if (pThis->pDrvIns)
     2612        CoUninitialize();
     2613
     2614    int rc2 = RTCritSectDelete(&pThis->CritSect);
     2615    AssertRC(rc2);
     2616
     2617    LogFlowFuncLeave();
    23322618}
    23332619
     
    23532639}
    23542640
     2641
    23552642static void dsoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
    23562643{
     
    23632650}
    23642651
    2365 /**
    2366  * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
    2367  */
    2368 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDSoundHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
    2369 {
    2370     RT_NOREF(enmDir);
    2371     AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
    2372 
    2373     return PDMAUDIOBACKENDSTS_RUNNING;
    2374 }
    2375 
    2376 /**
    2377  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
    2378  */
    2379 static DECLCALLBACK(int) drvHostDSoundHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
    2380                                                       PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
    2381 {
    2382     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2383     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2384     AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
    2385     AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
    2386 
    2387     PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2388     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2389 
    2390     int rc;
    2391     if (pCfgReq->enmDir == PDMAUDIODIR_IN)
    2392         rc = dsoundCreateStreamIn(pThis,  pStreamDS, pCfgReq, pCfgAcq);
    2393     else
    2394         rc = dsoundCreateStreamOut(pThis, pStreamDS, pCfgReq, pCfgAcq);
    2395 
    2396     if (RT_SUCCESS(rc))
    2397     {
    2398         /** @todo already copied   */
    2399         rc = PDMAudioStrmCfgCopy(&pStreamDS->Cfg, pCfgAcq);
    2400         if (RT_SUCCESS(rc))
    2401             rc = RTCritSectInit(&pStreamDS->CritSect);
    2402     }
    2403 
    2404     return rc;
    2405 }
    2406 
    2407 /**
    2408  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
    2409  */
    2410 static DECLCALLBACK(int) drvHostDSoundHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2411 {
    2412     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2413     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2414 
    2415     PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2416     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2417 
    2418     int rc;
    2419     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
    2420         rc = dsoundDestroyStreamIn(pThis, pStreamDS);
    2421     else
    2422         rc = dsoundDestroyStreamOut(pThis, pStreamDS);
    2423 
    2424     if (RT_SUCCESS(rc))
    2425     {
    2426         if (RTCritSectIsInitialized(&pStreamDS->CritSect))
    2427             rc = RTCritSectDelete(&pStreamDS->CritSect);
    2428     }
    2429 
    2430     return rc;
    2431 }
    2432 
    2433 /**
    2434  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
    2435  */
    2436 static DECLCALLBACK(int) drvHostDSoundHA_StreamControl(PPDMIHOSTAUDIO pInterface,
    2437                                                        PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
    2438 {
    2439     AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
    2440     AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
    2441 
    2442     PDRVHOSTDSOUND pThis     = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    2443     PDSOUNDSTREAM  pStreamDS = (PDSOUNDSTREAM)pStream;
    2444 
    2445     int rc;
    2446     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN)
    2447         rc = dsoundControlStreamIn(pThis,  pStreamDS, enmStreamCmd);
    2448     else
    2449         rc = dsoundControlStreamOut(pThis, pStreamDS, enmStreamCmd);
    2450 
    2451     return rc;
    2452 }
    2453 
    2454 /**
    2455  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
    2456  */
    2457 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2458 {
    2459     /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
    2460     PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
    2461     AssertPtrReturn(pStreamDS, 0);
    2462     Assert(pStreamDS->Cfg.enmDir == PDMAUDIODIR_IN);
    2463 
    2464     if (pStreamDS->fEnabled)
    2465     {
    2466         /* This is the same calculation as for StreamGetPending. */
    2467         AssertPtr(pStreamDS->In.pDSCB);
    2468         DWORD   offCaptureCursor = 0;
    2469         DWORD   offReadCursor    = 0;
    2470         HRESULT hrc = IDirectSoundCaptureBuffer_GetCurrentPosition(pStreamDS->In.pDSCB, &offCaptureCursor, &offReadCursor);
    2471         if (SUCCEEDED(hrc))
    2472         {
    2473             uint32_t cbPending = dsoundRingDistance(offCaptureCursor, offReadCursor, pStreamDS->cbBufSize);
    2474             Log3Func(("cbPending=%RU32\n", cbPending));
    2475             return cbPending;
    2476         }
    2477         AssertMsgFailed(("hrc=%Rhrc\n", hrc));
    2478     }
    2479 
    2480     return 0;
    2481 }
    2482 
    2483 /**
    2484  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
    2485  */
    2486 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2487 {
    2488     PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio);
    2489     PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
    2490     AssertPtrReturn(pStreamDS, 0);
    2491 
    2492     DWORD           cbFree    = 0;
    2493     DWORD           offIgn    = 0;
    2494     int rc = dsoundGetFreeOut(pThis, pStreamDS, &cbFree, &offIgn);
    2495     AssertRCReturn(rc, 0);
    2496 
    2497     return cbFree;
    2498 }
    2499 
    2500 #if 0 /* This isn't working as the write cursor is more a function of time than what we do.
    2501          Previously we only reported the pre-buffering status anyway, so no harm. */
    2502 /**
    2503  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
    2504  */
    2505 static DECLCALLBACK(uint32_t) drvHostDSoundHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2506 {
    2507     /*PDRVHOSTDSOUND  pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTDSOUND, IHostAudio); */ RT_NOREF(pInterface);
    2508     PDSOUNDSTREAM   pStreamDS = (PDSOUNDSTREAM)pStream;
    2509     AssertPtrReturn(pStreamDS, 0);
    2510 
    2511     if (pStreamDS->Cfg.enmDir == PDMAUDIODIR_OUT)
    2512     {
    2513         /* This is a similar calculation as for StreamGetReadable, only for an output buffer. */
    2514         AssertPtr(pStreamDS->In.pDSCB);
    2515         DWORD   offPlayCursor  = 0;
    2516         DWORD   offWriteCursor = 0;
    2517         HRESULT hrc = IDirectSoundBuffer8_GetCurrentPosition(pStreamDS->Out.pDSB, &offPlayCursor, &offWriteCursor);
    2518         if (SUCCEEDED(hrc))
    2519         {
    2520             uint32_t cbPending = dsoundRingDistance(offWriteCursor, offPlayCursor, pStreamDS->cbBufSize);
    2521             Log3Func(("cbPending=%RU32\n", cbPending));
    2522             return cbPending;
    2523         }
    2524         AssertMsgFailed(("hrc=%Rhrc\n", hrc));
    2525     }
    2526     /* else: For input streams we never have any pending data. */
    2527 
    2528     return 0;
    2529 }
    2530 #endif
    2531 
    2532 /**
    2533  * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
    2534  */
    2535 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDSoundHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
    2536 {
    2537     RT_NOREF(pInterface);
    2538     AssertPtrReturn(pStream, PDMAUDIOSTREAMSTS_FLAGS_NONE);
    2539 
    2540     PDSOUNDSTREAM pStreamDS = (PDSOUNDSTREAM)pStream;
    2541 
    2542     PDMAUDIOSTREAMSTS fStrmStatus = PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED;
    2543 
    2544     if (pStreamDS->fEnabled)
    2545         fStrmStatus |= PDMAUDIOSTREAMSTS_FLAGS_ENABLED;
    2546 
    2547     return fStrmStatus;
    2548 }
    2549 
    2550 
    2551 /*********************************************************************************************************************************
    2552 *   PDMDRVINS::IBase Interface                                                                                                   *
    2553 *********************************************************************************************************************************/
    2554 
    2555 /**
    2556  * @callback_method_impl{PDMIBASE,pfnQueryInterface}
    2557  */
    2558 static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    2559 {
    2560     PPDMDRVINS     pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
    2561     PDRVHOSTDSOUND pThis   = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
    2562 
    2563     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    2564     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
    2565     return NULL;
    2566 }
    2567 
    2568 
    2569 /*********************************************************************************************************************************
    2570 *   PDMDRVREG Interface                                                                                                          *
    2571 *********************************************************************************************************************************/
    2572 
    2573 /**
    2574  * @callback_method_impl{FNPDMDRVDESTRUCT, pfnDestruct}
    2575  */
    2576 static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
    2577 {
    2578     PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
    2579     PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
    2580 
    2581     LogFlowFuncEnter();
    2582 
    2583 #ifdef VBOX_WITH_AUDIO_MMNOTIFICATION_CLIENT
    2584     if (pThis->m_pNotificationClient)
    2585     {
    2586         pThis->m_pNotificationClient->Unregister();
    2587         pThis->m_pNotificationClient->Release();
    2588 
    2589         pThis->m_pNotificationClient = NULL;
    2590     }
    2591 #endif
    2592 
    2593     PDMAudioHostEnumDelete(&pThis->DeviceEnum);
    2594 
    2595     if (pThis->pDrvIns)
    2596         CoUninitialize();
    2597 
    2598     int rc2 = RTCritSectDelete(&pThis->CritSect);
    2599     AssertRC(rc2);
    2600 
    2601     LogFlowFuncLeave();
    2602 }
    26032652
    26042653/**
     
    26212670    /* IHostAudio */
    26222671    pThis->IHostAudio.pfnGetConfig          = drvHostDSoundHA_GetConfig;
     2672    pThis->IHostAudio.pfnGetDevices         = drvHostDSoundHA_GetDevices;
    26232673    pThis->IHostAudio.pfnGetStatus          = drvHostDSoundHA_GetStatus;
    26242674    pThis->IHostAudio.pfnStreamCreate       = drvHostDSoundHA_StreamCreate;
     
    26272677    pThis->IHostAudio.pfnStreamGetReadable  = drvHostDSoundHA_StreamGetReadable;
    26282678    pThis->IHostAudio.pfnStreamGetWritable  = drvHostDSoundHA_StreamGetWritable;
     2679    pThis->IHostAudio.pfnStreamGetPending   = NULL;
    26292680    pThis->IHostAudio.pfnStreamGetStatus    = drvHostDSoundHA_StreamGetStatus;
    26302681    pThis->IHostAudio.pfnStreamPlay         = drvHostDSoundHA_StreamPlay;
    26312682    pThis->IHostAudio.pfnStreamCapture      = drvHostDSoundHA_StreamCapture;
    2632     pThis->IHostAudio.pfnGetDevices         = drvHostDSoundHA_GetDevices;
    2633     pThis->IHostAudio.pfnStreamGetPending   = NULL;
    26342683
    26352684    /*
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