VirtualBox

Changeset 59890 in vbox for trunk


Ignore:
Timestamp:
Mar 1, 2016 5:11:08 PM (9 years ago)
Author:
vboxsync
Message:

Audio: Added support for handling host input/output configuration changes. This is needed if audio devices on the host become (un)available while a VM is running and the guest does audio work in the meantime.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vmm/pdmaudioifs.h

    r59470 r59890  
    6868typedef struct PDMAUDIOBACKENDCFG
    6969{
    70     uint32_t    cbStreamOut;
    71     uint32_t    cbStreamIn;
    72     uint32_t    cMaxHstStrmsOut;
    73     uint32_t    cMaxHstStrmsIn;
     70    size_t   cbStreamOut;
     71    size_t   cbStreamIn;
     72    uint32_t cMaxHstStrmsOut;
     73    uint32_t cMaxHstStrmsIn;
    7474} PDMAUDIOBACKENDCFG, *PPDMAUDIOBACKENDCFG;
    7575
  • trunk/src/VBox/Devices/Audio/DrvAudio.cpp

    r59470 r59890  
    13991399        rc = rc2;
    14001400
     1401    if (RT_FAILURE(rc))
     1402        LogFlowFuncLeaveRC(rc);
     1403
    14011404    return rc;
    14021405}
     
    14121415    if (RT_FAILURE(rc))
    14131416        return rc;
     1417
     1418    /* Backend output (temporarily) disabled / unavailable? */
     1419    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
     1420    {
     1421        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
     1422        AssertRC(rc);
     1423
     1424        if (!pThis->BackendCfg.cMaxHstStrmsOut)
     1425        {
     1426            int rc2 = RTCritSectLeave(&pThis->CritSect);
     1427            AssertRC(rc2);
     1428
     1429            return VERR_NOT_AVAILABLE;
     1430        }
     1431    }
    14141432
    14151433    /*
     
    14501468
    14511469        uint32_t cSamplesPlayed = 0;
    1452         int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut,
    1453                                                    &cSamplesPlayed);
    1454         if (RT_SUCCESS(rc2))
     1470        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
     1471        if (RT_FAILURE(rc2))
     1472        {
     1473            rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
     1474            AssertRC(rc2);
     1475        }
     1476        else
    14551477            cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
    14561478
     
    14941516        rc = rc2;
    14951517
     1518    if (RT_FAILURE(rc))
     1519        LogFlowFuncLeaveRC(rc);
     1520
    14961521    return rc;
    14971522}
     
    16281653    LogFlowFuncEnter();
    16291654
     1655    AssertPtr(pThis->pHostDrvAudio);
    16301656    int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
    16311657    if (RT_FAILURE(rc))
     
    16351661    }
    16361662
     1663    /* Get the configuration data from backend. */
     1664    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
     1665    if (RT_FAILURE(rc))
     1666    {
     1667        LogFlowFunc(("Getting backend configuration failed with rc=%Rrc\n", rc));
     1668        return rc;
     1669    }
     1670
    16371671    uint32_t cMaxHstStrmsOut = pThis->BackendCfg.cMaxHstStrmsOut;
    1638     uint32_t cbHstStrmsOut   = pThis->BackendCfg.cbStreamOut;
     1672    size_t cbHstStrmsOut     = pThis->BackendCfg.cbStreamOut;
    16391673
    16401674    if (cbHstStrmsOut)
     
    16461680
    16471681    uint32_t cMaxHstStrmsIn = pThis->BackendCfg.cMaxHstStrmsIn;
    1648     uint32_t cbHstStrmIn    = pThis->BackendCfg.cbStreamIn;
     1682    size_t cbHstStrmIn      = pThis->BackendCfg.cbStreamIn;
    16491683
    16501684    if (cbHstStrmIn)
     
    16601694        pThis->cFreeInputStreams = 0;
    16611695
    1662     LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%RU32), cMaxHstStrmsIn=%RU32 (cb=%RU32)\n",
     1696    LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%zu), cMaxHstStrmsIn=%RU32 (cb=%zu)\n",
    16631697                 cMaxHstStrmsOut, cbHstStrmsOut, cMaxHstStrmsIn, cbHstStrmIn));
    16641698
     
    17531787
    17541788    int rc = RTCritSectInit(&pThis->CritSect);
    1755 
    1756     /* Get the configuration data from the selected backend (if available). */
    1757     AssertPtr(pThis->pHostDrvAudio);
    1758     if (   RT_SUCCESS(rc)
    1759         && RT_LIKELY(pThis->pHostDrvAudio->pfnGetConf))
    1760         rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
    1761 
    17621789    if (RT_SUCCESS(rc))
    17631790    {
     
    21862213        return rc;
    21872214
    2188     memcpy(pCfg, &pThis->BackendCfg, sizeof(PDMAUDIOBACKENDCFG));
     2215    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, pCfg);
    21892216
    21902217    int rc2 = RTCritSectLeave(&pThis->CritSect);
  • trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp

    r58378 r59890  
    365365    }
    366366
    367 #ifdef DEBUG
    368     drvAudioStreamCfgPrint(pCfg);
    369 #endif
    370 
    371     LogFlowFunc(("rc=%Rrc\n", rc));
    372367    return rc;
    373368}
  • trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp

    r59470 r59890  
    9595    DWORD                cbPlayWritePos;
    9696    DWORD                csPlaybackBufferSize;
     97    bool                 fEnabled;
    9798    bool                 fRestartPlayback;
    9899    PDMAUDIOSTREAMCFG    streamCfg;
     
    108109    HRESULT                     hrLastCaptureIn;
    109110    PDMAUDIORECSOURCE           enmRecSource;
     111    bool                        fEnabled;
    110112    PDMAUDIOSTREAMCFG           streamCfg;
    111113} DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
     
    123125    /** DirectSound configuration options. */
    124126    DSOUNDHOSTCFG       cfg;
    125     /** Whether the input currently is in an enabled (working)
    126      *  state or not. */
     127    /** Whether this backend supports any audio input. */
    127128    bool                fEnabledIn;
    128     /** Whether the output currently is in an enabled (working)
    129      *  state or not. */
     129    /** Whether this backend supports any audio output. */
    130130    bool                fEnabledOut;
    131131#ifdef VBOX_WITH_AUDIO_CALLBACKS
     
    150150} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
    151151
     152/** No flags specified. */
     153#define DSOUNDENUMCBFLAGS_NONE          0
     154/** (Release) log found devices. */
     155#define DSOUNDENUMCBFLAGS_LOG           RT_BIT(0)
     156
    152157/**
    153158 * Callback context for enumeration callbacks
     
    157162    PDRVHOSTDSOUND      pDrv;
    158163    PPDMAUDIOBACKENDCFG pCfg;
     164    /** Enumeration flags. */
     165    uint32_t            fFlags;
    159166} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
    160167
     
    166173} DSOUNDDEV, *PDSOUNDDEV;
    167174
     175/** Maximum number of attempts to restore the sound buffer before giving up. */
     176#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX         3
     177
    168178/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
    169179#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
    170180    ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
    171181
    172 static HRESULT directSoundPlayRestore(LPDIRECTSOUNDBUFFER8 pDSB);
    173 
    174 static void dsoundDevRemove(PDSOUNDDEV pDev);
     182static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
     183
     184static void dsoundDeviceRemove(PDSOUNDDEV pDev);
     185static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
    175186#ifdef VBOX_WITH_AUDIO_CALLBACKS
    176187static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
     
    225236}
    226237
    227 static int dsoundGetStatusOut(PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
    228 {
     238static int dsoundGetPosOut(PDRVHOSTDSOUND   pThis,
     239                           PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
     240{
     241    AssertPtrReturn(pThis,          VERR_INVALID_POINTER);
    229242    AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
    230243
     
    237250    /* Get the current play position which is used for calculating the free space in the buffer. */
    238251    DWORD cbPlayPos;
    239     HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
    240     if (hr == DSERR_BUFFERLOST)
    241     {
    242         hr = directSoundPlayRestore(pDSB);
    243         if (SUCCEEDED(hr))
    244             hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
    245     }
     252
     253    HRESULT hr;
     254    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     255    {
     256        hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
     257        if (   SUCCEEDED(hr)
     258            || hr != DSERR_BUFFERLOST) /** @todo: MSDN doesn't state this error for GetCurrentPosition(). */
     259        {
     260            break;
     261        }
     262        else
     263        {
     264            LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
     265            directSoundPlayRestore(pThis, pDSB);
     266        }
     267    }
     268
     269    int rc = VINF_SUCCESS;
    246270
    247271    if (FAILED(hr))
     
    250274            DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
    251275        LogFlowFunc(("Failed with %Rhrc\n", hr));
    252         return VERR_NOT_AVAILABLE;
    253     }
    254 
    255     if (pdwBuffer)
    256         *pdwBuffer = cbBuffer;
    257 
    258     if (pdwFree)
    259         *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
    260 
    261     if (pdwPlayPos)
    262         *pdwPlayPos = cbPlayPos;
    263 
    264     return VINF_SUCCESS;
     276
     277        rc = VERR_NOT_AVAILABLE;
     278    }
     279    else
     280    {
     281        if (pdwBuffer)
     282            *pdwBuffer = cbBuffer;
     283
     284        if (pdwFree)
     285            *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
     286
     287        if (pdwPlayPos)
     288            *pdwPlayPos = cbPlayPos;
     289    }
     290
     291    LogFlowFuncLeaveRC(rc);
     292    return rc;
    265293}
    266294
     
    284312}
    285313
    286 static void dsoundFreeDeviceLists(PDRVHOSTDSOUND pThis)
    287 {
     314/**
     315 * Clears the list of the host's playback + capturing devices.
     316 *
     317 * @param   pThis               Host audio driver instance.
     318 */
     319static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
     320{
     321    AssertPtrReturnVoid(pThis);
     322
    288323    PDSOUNDDEV pDev;
    289324    while (!RTListIsEmpty(&pThis->lstDevInput))
    290325    {
    291326        pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
    292         dsoundDevRemove(pDev);
     327        dsoundDeviceRemove(pDev);
    293328    }
    294329
     
    296331    {
    297332        pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
    298         dsoundDevRemove(pDev);
    299     }
    300 }
    301 
    302 static HRESULT directSoundPlayRestore(LPDIRECTSOUNDBUFFER8 pDSB)
     333        dsoundDeviceRemove(pDev);
     334    }
     335}
     336
     337static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
    303338{
    304339    HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
     
    308343}
    309344
    310 static HRESULT directSoundPlayUnlock(LPDIRECTSOUNDBUFFER8 pDSB,
     345static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
    311346                                     LPVOID pv1, LPVOID pv2,
    312347                                     DWORD cb1, DWORD cb2)
     
    328363}
    329364
    330 static HRESULT directSoundPlayLock(LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
     365static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis,
     366                                   LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
    331367                                   DWORD dwOffset, DWORD dwBytes,
    332368                                   LPVOID *ppv1, LPVOID *ppv2,
     
    339375    DWORD cb2 = 0;
    340376
    341     HRESULT hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
    342     if (hr == DSERR_BUFFERLOST)
    343     {
    344         hr = directSoundPlayRestore(pDSB);
    345         if (SUCCEEDED(hr))
    346         {
    347             hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
     377    HRESULT hr;
     378    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     379    {
     380        hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
     381        if (   SUCCEEDED(hr)
     382            || hr != DSERR_BUFFERLOST)
     383            break;
     384        else
     385        {
     386            LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
     387            directSoundPlayRestore(pThis, pDSB);
    348388        }
    349389    }
     
    360400        DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
    361401                  cb1, cb2, pProps->uAlign));
    362         directSoundPlayUnlock(pDSB, pv1, pv2, cb1, cb2);
     402        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
    363403        return E_FAIL;
    364404    }
     
    686726}
    687727
    688 static void dsoundPlayClearSamples(PDSOUNDSTREAMOUT pDSoundStrmOut)
     728static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
    689729{
    690730    AssertPtrReturnVoid(pDSoundStrmOut);
     
    694734    LPVOID pv1, pv2;
    695735    DWORD cb1, cb2;
    696     HRESULT hr = directSoundPlayLock(pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
     736    HRESULT hr = directSoundPlayLock(pThis, pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
    697737                                     0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStrmOut->MixBuf, pDSoundStrmOut->csPlaybackBufferSize),
    698738                                     &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
     
    708748            DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, cb2, len2);
    709749
    710         directSoundPlayUnlock(pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
    711     }
    712 }
    713 
    714 static HRESULT directSoundPlayGetStatus(LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
    715 {
    716     AssertPtrReturn(pDSB, E_POINTER);
     750        directSoundPlayUnlock(pThis, pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
     751    }
     752}
     753
     754static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
     755{
     756    AssertPtrReturn(pThis, E_POINTER);
     757    AssertPtrReturn(pDSB,  E_POINTER);
    717758    /* pdwStatus is optional. */
    718759
    719     bool fRestoreBuffer = false;
    720 
    721760    DWORD dwStatus = 0;
    722     HRESULT hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
    723     if (SUCCEEDED(hr))
    724     {
    725         fRestoreBuffer = RT_BOOL(dwStatus & DSBSTATUS_BUFFERLOST);
    726     }
    727     else if (hr == DSERR_BUFFERLOST)
    728         fRestoreBuffer = true;
    729 
    730     if (fRestoreBuffer)
    731     {
    732         hr = directSoundPlayRestore(pDSB);
    733         if (SUCCEEDED(hr))
    734             hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
     761
     762    HRESULT hr;
     763    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     764    {
     765        hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
     766        if (   hr == DSERR_BUFFERLOST
     767            || (   SUCCEEDED(hr)
     768                && (dwStatus & DSBSTATUS_BUFFERLOST)))
     769        {
     770            LogFlowFunc(("Getting status failed due to lost buffer, restoring ...\n"));
     771            directSoundPlayRestore(pThis, pDSB);
     772        }
     773        else
     774            break;
    735775    }
    736776
     
    748788static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
    749789{
    750     AssertPtrReturn(pThis, E_POINTER);
     790    AssertPtrReturn(pThis,          E_POINTER);
    751791    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
    752792
     
    755795    if (pDSoundStrmOut->pDSB != NULL)
    756796    {
    757         /* This performs some restore, so call it anyway and ignore result. */
    758         hr = directSoundPlayGetStatus(pDSoundStrmOut->pDSB, NULL /* pdwStatus */);
    759         if (SUCCEEDED(hr))
    760         {
    761             DSLOG(("DSound: Stopping playback\n"));
    762 
    763             /** @todo Wait until all data in the buffer has been played. */
    764             hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
    765             if (SUCCEEDED(hr))
    766                 dsoundPlayClearSamples(pDSoundStrmOut);
    767         }
     797        DSLOG(("DSound: Stopping playback\n"));
     798
     799        HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
     800        if (FAILED(hr2))
     801        {
     802            hr2 = directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
     803            if (FAILED(hr2))
     804                hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
     805        }
     806
     807        if (FAILED(hr2))
     808            DSLOG(("DSound: Stopping playback failed with %Rhrc\n", hr2));
     809
     810        hr = S_OK; /* Always report success here. */
    768811    }
    769812    else
    770813        hr = E_UNEXPECTED;
    771814
    772     if (FAILED(hr))
     815    if (SUCCEEDED(hr))
     816    {
     817        dsoundPlayClearSamples(pThis, pDSoundStrmOut);
     818        pDSoundStrmOut->fEnabled = false;
     819    }
     820    else
    773821        DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
    774822
     
    776824}
    777825
    778 static HRESULT directSoundPlayStart(PDSOUNDSTREAMOUT pDSoundStrmOut)
    779 {
     826static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
     827{
     828    AssertPtrReturn(pThis,          E_POINTER);
    780829    AssertPtrReturn(pDSoundStrmOut, E_POINTER);
    781830
     
    784833    {
    785834        DWORD dwStatus;
    786         hr = directSoundPlayGetStatus(pDSoundStrmOut->pDSB, &dwStatus);
     835        hr = directSoundPlayGetStatus(pThis, pDSoundStrmOut->pDSB, &dwStatus);
    787836        if (SUCCEEDED(hr))
    788837        {
     
    793842            else
    794843            {
    795                 dsoundPlayClearSamples(pDSoundStrmOut);
     844                dsoundPlayClearSamples(pThis, pDSoundStrmOut);
    796845
    797846                pDSoundStrmOut->fRestartPlayback = true;
    798 
    799                 DSLOG(("DSound: Playback start\n"));
    800 
    801                 /* The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
     847                pDSoundStrmOut->fEnabled         = true;
     848
     849                DSLOG(("DSound: Playback started\n"));
     850
     851                /*
     852                 * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
    802853                 * because it is necessary to put some samples into the buffer first.
    803854                 */
     
    10701121}
    10711122
    1072 static HRESULT directSoundCaptureStop(PDSOUNDSTREAMIN pDSoundStrmIn)
    1073 {
     1123static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
     1124{
     1125    AssertPtrReturn(pThis        , E_POINTER);
    10741126    AssertPtrReturn(pDSoundStrmIn, E_POINTER);
     1127
     1128    NOREF(pThis);
    10751129
    10761130    HRESULT hr;
     
    10861140    else
    10871141        hr = E_UNEXPECTED;
     1142
     1143    if (SUCCEEDED(hr))
     1144        pDSoundStrmIn->fEnabled = false;
    10881145
    10891146    LogFlowFunc(("Returning %Rhrc\n", hr));
     
    11271184        hr = E_UNEXPECTED;
    11281185
     1186    if (SUCCEEDED(hr))
     1187        pDSoundStrmIn->fEnabled = true;
     1188
    11291189    LogFlowFunc(("Returning %Rhrc\n", hr));
    11301190    return hr;
     
    11551215}
    11561216
    1157 static void dsoundDevRemove(PDSOUNDDEV pDev)
     1217static void dsoundDeviceRemove(PDSOUNDDEV pDev)
    11581218{
    11591219    if (pDev)
     
    11771237}
    11781238
    1179 static BOOL CALLBACK dsoundEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
    1180                                         LPCWSTR lpwstrModule, LPVOID lpContext)
     1239static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
     1240                                                 LPCWSTR lpwstrModule, LPVOID lpContext)
    11811241{
    11821242    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
     
    11891249
    11901250    AssertPtrReturn(lpwstrDescription, FALSE);
    1191     /* Do not care about lpwstrModule */
    1192 
    1193     dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
     1251    /* Do not care about lpwstrModule. */
     1252
     1253    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
     1254        dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
    11941255
    11951256    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
     
    12031264}
    12041265
    1205 static BOOL CALLBACK dsoundCaptureEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
    1206                                                LPCWSTR lpwstrModule, LPVOID lpContext)
     1266static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID lpGUID, LPCWSTR lpwstrDescription,
     1267                                                LPCWSTR lpwstrModule, LPVOID lpContext)
    12071268{
    12081269    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
     
    12141275        return TRUE;
    12151276
    1216     dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
     1277    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
     1278        dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
    12171279
    12181280    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
     
    12261288}
    12271289
     1290/**
     1291 * Does a (Re-)enumeration of the host's playback + capturing devices.
     1292 *
     1293 * @return  IPRT status code.
     1294 * @param   pThis               Host audio driver instance.
     1295 * @param   pCfg                Where to store the enumeration results.
     1296 * @param   fEnum               Enumeration flags.
     1297 */
     1298static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
     1299{
     1300    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     1301    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
     1302
     1303    dsoundDevicesClear(pThis);
     1304
     1305    pCfg->cMaxHstStrmsOut = 0;
     1306    pCfg->cMaxHstStrmsIn  = 0;
     1307
     1308    RTLDRMOD hDSound = NULL;
     1309    int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
     1310    if (RT_SUCCESS(rc))
     1311    {
     1312        PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
     1313        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
     1314
     1315        rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
     1316        if (RT_SUCCESS(rc))
     1317            rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
     1318
     1319        if (RT_SUCCESS(rc))
     1320        {
     1321            DSOUNDENUMCBCTX ctx = { pThis, pCfg, fEnum };
     1322
     1323            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &ctx);
     1324            if (FAILED(hr))
     1325                LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
     1326
     1327            hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &ctx);
     1328            if (FAILED(hr))
     1329                LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
     1330        }
     1331
     1332        RTLdrClose(hDSound);
     1333    }
     1334    else
     1335    {
     1336        /* No dsound.dll on this system. */
     1337        LogRel2(("DSound: Could not load dsound.dll: %Rrc\n", rc));
     1338    }
     1339
     1340    return rc;
     1341}
     1342
     1343/**
     1344 * Updates this host driver's internal status, according to the global, overall input/output
     1345 * state and all connected (native) audio streams.
     1346 *
     1347 * @param   pThis               Host audio driver instance.
     1348 * @param   pCfg                Where to store the backend configuration. Optional.
     1349 * @param   fEnum               Enumeration flags.
     1350 */
     1351void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
     1352{
     1353    AssertPtrReturnVoid(pThis);
     1354    /* pCfg is optional. */
     1355
     1356    PDMAUDIOBACKENDCFG Cfg;
     1357    RT_ZERO(Cfg);
     1358
     1359    Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
     1360    Cfg.cbStreamIn  = sizeof(DSOUNDSTREAMIN);
     1361
     1362    int rc = dsoundDevicesEnumerate(pThis, &Cfg, fEnum);
     1363    AssertRC(rc);
     1364
     1365#ifdef VBOX_WITH_AUDIO_CALLBACKS
     1366    if (   pThis->fEnabledOut != RT_BOOL(Cfg.cMaxHstStrmsOut)
     1367        || pThis->fEnabledIn  != RT_BOOL(Cfg.cMaxHstStrmsIn))
     1368    {
     1369        /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
     1370         *        let the connector know that something has changed within the host backend. */
     1371    }
     1372#else
     1373    pThis->fEnabledOut = RT_BOOL(Cfg.cMaxHstStrmsOut);
     1374    pThis->fEnabledIn  = RT_BOOL(Cfg.cMaxHstStrmsIn);
     1375#endif
     1376
     1377    if (pCfg)
     1378        memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
     1379
     1380    LogFlowFuncLeaveRC(rc);
     1381}
     1382
     1383void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
     1384{
     1385    dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
     1386}
    12281387
    12291388/*
     
    12801439    LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
    12811440
    1282     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1441    PDRVHOSTDSOUND   pThis          = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    12831442    PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
    12841443
     
    12931452            DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_ENABLE\n"));
    12941453            /* Try to start playback. If it fails, then reopen and try again. */
    1295             hr = directSoundPlayStart(pDSoundStrmOut);
     1454            hr = directSoundPlayStart(pThis, pDSoundStrmOut);
    12961455            if (FAILED(hr))
    12971456            {
    1298                 directSoundPlayClose(pThis, pDSoundStrmOut);
    1299                 directSoundPlayOpen(pThis, pDSoundStrmOut);
    1300 
    1301                 hr = directSoundPlayStart(pDSoundStrmOut);
     1457                hr = directSoundPlayClose(pThis, pDSoundStrmOut);
     1458                if (SUCCEEDED(hr))
     1459                    hr = directSoundPlayOpen(pThis, pDSoundStrmOut);
     1460                if (SUCCEEDED(hr))
     1461                    hr = directSoundPlayStart(pThis, pDSoundStrmOut);
    13021462            }
    13031463
    13041464            if (FAILED(hr))
    13051465                rc = VERR_NOT_SUPPORTED;
    1306 
    1307             pThis->fEnabledOut = RT_SUCCESS(rc);
    13081466            break;
    13091467        }
     
    13141472            DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_DISABLE\n"));
    13151473            hr = directSoundPlayStop(pThis, pDSoundStrmOut);
    1316             if (SUCCEEDED(hr))
    1317                 pThis->fEnabledOut = false;
     1474            if (FAILED(hr))
     1475                rc = VERR_NOT_SUPPORTED;
    13181476            break;
    13191477        }
     
    13441502    uint32_t cReadTotal = 0;
    13451503
     1504#ifdef DEBUG_andy
     1505    LogFlowFuncEnter();
     1506#endif
     1507
    13461508    do /* to use 'break' */
    13471509    {
    13481510        DWORD cbBuffer, cbFree, cbPlayPos;
    1349         rc = dsoundGetStatusOut(pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
     1511        rc = dsoundGetPosOut(pThis, pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
    13501512        if (RT_FAILURE(rc))
    1351         {
    1352             /* Set the output status to disabled, as we are not able to retrieve the current
    1353              * status (anymore). */
    1354             pThis->fEnabledOut = false;
    1355             break;
    1356         }
     1513            break;
    13571514
    13581515        /*
     
    13841541        LPVOID pv1, pv2;
    13851542        DWORD cb1, cb2;
    1386         HRESULT hr = directSoundPlayLock(pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
     1543        HRESULT hr = directSoundPlayLock(pThis, pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
    13871544                                         &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
    13881545        if (FAILED(hr))
     
    14131570        }
    14141571
    1415         directSoundPlayUnlock(pDSB, pv1, pv2, cb1, cb2);
     1572        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
    14161573
    14171574        pDSoundStrmOut->cbPlayWritePos =
     
    14451602            fFlags |= DSCBSTART_LOOPING;
    14461603#endif
    1447             hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
     1604            for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
     1605            {
     1606                hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
     1607                if (   SUCCEEDED(hr)
     1608                    || hr != DSERR_BUFFERLOST)
     1609                    break;
     1610                else
     1611                {
     1612                    LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
     1613                    directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
     1614                }
     1615            }
     1616
    14481617            if (FAILED(hr))
    14491618            {
     
    14561625    } while (0);
    14571626
    1458     if (RT_SUCCESS(rc))
     1627    if (RT_FAILURE(rc))
     1628    {
     1629        dsoundUpdateStatusInternal(pThis);
     1630    }
     1631    else
    14591632    {
    14601633        if (pcSamplesPlayed)
     
    14621635    }
    14631636
     1637    LogFlowFuncLeaveRC(rc);
    14641638    return rc;
    14651639}
     
    15301704    LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
    15311705
    1532     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     1706    PDRVHOSTDSOUND  pThis        = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    15331707    PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
    15341708
     
    15561730            if (FAILED(hr))
    15571731                rc = VERR_NOT_SUPPORTED;
    1558 
    1559             pThis->fEnabledIn = RT_SUCCESS(rc);
    15601732            break;
    15611733        }
     
    15641736        case PDMAUDIOSTREAMCMD_PAUSE:
    15651737        {
    1566             hr = directSoundCaptureStop(pDSoundStrmIn);
    1567             if (SUCCEEDED(hr))
    1568                 pThis->fEnabledIn = false;
     1738            hr = directSoundCaptureStop(pThis, pDSoundStrmIn);
     1739            if (FAILED(hr))
     1740                rc = VERR_NOT_SUPPORTED;
    15691741            break;
    15701742        }
     
    15851757{
    15861758    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    1587     PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
    1588     LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStrmIn->pDSCB;
     1759
     1760    PDSOUNDSTREAMIN             pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
     1761    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB         = pDSoundStrmIn->pDSCB;
    15891762
    15901763    int rc = VINF_SUCCESS;
     
    15961769        if (pDSCB == NULL)
    15971770        {
    1598             pThis->fEnabledIn = false;
    1599 
    16001771            rc = VERR_NOT_AVAILABLE;
    16011772            break;
     
    16981869    } while (0);
    16991870
    1700     if (pcSamplesCaptured)
    1701         *pcSamplesCaptured = cCaptured;
    1702 
     1871    if (RT_FAILURE(rc))
     1872    {
     1873        dsoundUpdateStatusInternal(pThis);
     1874    }
     1875    else
     1876    {
     1877        if (pcSamplesCaptured)
     1878            *pcSamplesCaptured = cCaptured;
     1879    }
     1880
     1881    LogFlowFuncLeaveRC(rc);
    17031882    return rc;
    17041883}
     
    17381917    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
    17391918
    1740     dsoundFreeDeviceLists(pThis);
    1741 
    1742     pCfg->cbStreamOut = sizeof(DSOUNDSTREAMOUT);
    1743     pCfg->cbStreamIn  = sizeof(DSOUNDSTREAMIN);
    1744 
    1745     pCfg->cMaxHstStrmsOut = 0;
    1746     pCfg->cMaxHstStrmsIn  = 0;
    1747 
    1748     RTLDRMOD hDSound = NULL;
    1749     int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
    1750     if (RT_SUCCESS(rc))
    1751     {
    1752         PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
    1753         PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
    1754 
    1755         rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
    1756         if (RT_SUCCESS(rc))
    1757         {
    1758             rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
    1759         }
    1760 
    1761         if (RT_SUCCESS(rc))
    1762         {
    1763             DSOUNDENUMCBCTX ctx = { pThis, pCfg };
    1764 
    1765             HRESULT hr = pfnDirectSoundEnumerateW(&dsoundEnumCallback, &ctx);
    1766             if (FAILED(hr))
    1767                 LogRel(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
    1768 
    1769             LogRel(("DSound: Found %RU32 host playback devices\n", pCfg->cMaxHstStrmsOut));
    1770 
    1771             hr = pfnDirectSoundCaptureEnumerateW(&dsoundCaptureEnumCallback, &ctx);
    1772             if (FAILED(hr))
    1773                 LogRel(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
    1774 
    1775             LogRel(("DSound: Found %RU32 host capturing devices\n", pCfg->cMaxHstStrmsIn));
    1776         }
    1777 
    1778         RTLdrClose(hDSound);
    1779     }
    1780     else
    1781     {
    1782         /* No dsound.dll on this system.  */
    1783         LogRel(("DSound: Could not load dsound.dll %Rrc\n", rc));
    1784     }
    1785 
    1786     /* Always return success and at least default values to make the caller happy. */
    1787     if (pCfg->cMaxHstStrmsOut == 0)
    1788     {
    1789         LogRel(("DSound: Adjusting the number of host playback devices to 1\n"));
    1790         pCfg->cMaxHstStrmsOut = 1; /* Support at least one stream. */
    1791     }
    1792 
    1793     if (pCfg->cMaxHstStrmsIn < 2)
    1794     {
    1795         LogRel(("DSound: Adjusting the number of host capturing devices from %RU32 to 2\n", pCfg->cMaxHstStrmsIn));
    1796         pCfg->cMaxHstStrmsIn = 2; /* Support at least two streams (line in + mic). */
    1797     }
     1919    dsoundUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
    17981920
    17991921    return VINF_SUCCESS;
     
    18711993                {
    18721994                    DWORD cbBuffer, cbFree, cbPlayPos;
    1873                     rc = dsoundGetStatusOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
     1995                    rc = dsoundGetPosOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
    18741996                    if (   RT_SUCCESS(rc)
    18751997                        && cbFree)
     
    19732095        rc = VINF_SUCCESS;
    19742096#endif
     2097
     2098        PDMAUDIOBACKENDCFG Cfg;
     2099        dsoundUpdateStatusInternalEx(pThis, &Cfg, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
     2100
     2101        DSLOGREL(("DSound: Found %RU32 host playback devices\n",  Cfg.cMaxHstStrmsOut));
     2102        DSLOGREL(("DSound: Found %RU32 host capturing devices\n", Cfg.cMaxHstStrmsIn));
    19752103    }
    19762104    else
     
    20952223    pThis->fEnabledOut = false;
    20962224#ifdef VBOX_WITH_AUDIO_CALLBACKS
    2097     pThis->fStopped  = false;
    2098     pThis->fShutdown = false;
     2225    pThis->fStopped    = false;
     2226    pThis->fShutdown   = false;
    20992227
    21002228    RT_ZERO(pThis->aEvents);
Note: See TracChangeset for help on using the changeset viewer.

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