Index: trunk/include/VBox/vmm/pdmaudioifs.h
===================================================================
--- trunk/include/VBox/vmm/pdmaudioifs.h	(revision 59889)
+++ trunk/include/VBox/vmm/pdmaudioifs.h	(revision 59890)
@@ -68,8 +68,8 @@
 typedef struct PDMAUDIOBACKENDCFG
 {
-    uint32_t    cbStreamOut;
-    uint32_t    cbStreamIn;
-    uint32_t    cMaxHstStrmsOut;
-    uint32_t    cMaxHstStrmsIn;
+    size_t   cbStreamOut;
+    size_t   cbStreamIn;
+    uint32_t cMaxHstStrmsOut;
+    uint32_t cMaxHstStrmsIn;
 } PDMAUDIOBACKENDCFG, *PPDMAUDIOBACKENDCFG;
 
Index: trunk/src/VBox/Devices/Audio/DrvAudio.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 59889)
+++ trunk/src/VBox/Devices/Audio/DrvAudio.cpp	(revision 59890)
@@ -1399,4 +1399,7 @@
         rc = rc2;
 
+    if (RT_FAILURE(rc))
+        LogFlowFuncLeaveRC(rc);
+
     return rc;
 }
@@ -1412,4 +1415,19 @@
     if (RT_FAILURE(rc))
         return rc;
+
+    /* Backend output (temporarily) disabled / unavailable? */
+    if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
+    {
+        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
+        AssertRC(rc);
+
+        if (!pThis->BackendCfg.cMaxHstStrmsOut)
+        {
+            int rc2 = RTCritSectLeave(&pThis->CritSect);
+            AssertRC(rc2);
+
+            return VERR_NOT_AVAILABLE;
+        }
+    }
 
     /*
@@ -1450,7 +1468,11 @@
 
         uint32_t cSamplesPlayed = 0;
-        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut,
-                                                   &cSamplesPlayed);
-        if (RT_SUCCESS(rc2))
+        int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
+        if (RT_FAILURE(rc2))
+        {
+            rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+            AssertRC(rc2);
+        }
+        else
             cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
 
@@ -1494,4 +1516,7 @@
         rc = rc2;
 
+    if (RT_FAILURE(rc))
+        LogFlowFuncLeaveRC(rc);
+
     return rc;
 }
@@ -1628,4 +1653,5 @@
     LogFlowFuncEnter();
 
+    AssertPtr(pThis->pHostDrvAudio);
     int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
     if (RT_FAILURE(rc))
@@ -1635,6 +1661,14 @@
     }
 
+    /* Get the configuration data from backend. */
+    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
+    if (RT_FAILURE(rc))
+    {
+        LogFlowFunc(("Getting backend configuration failed with rc=%Rrc\n", rc));
+        return rc;
+    }
+
     uint32_t cMaxHstStrmsOut = pThis->BackendCfg.cMaxHstStrmsOut;
-    uint32_t cbHstStrmsOut   = pThis->BackendCfg.cbStreamOut;
+    size_t cbHstStrmsOut     = pThis->BackendCfg.cbStreamOut;
 
     if (cbHstStrmsOut)
@@ -1646,5 +1680,5 @@
 
     uint32_t cMaxHstStrmsIn = pThis->BackendCfg.cMaxHstStrmsIn;
-    uint32_t cbHstStrmIn    = pThis->BackendCfg.cbStreamIn;
+    size_t cbHstStrmIn      = pThis->BackendCfg.cbStreamIn;
 
     if (cbHstStrmIn)
@@ -1660,5 +1694,5 @@
         pThis->cFreeInputStreams = 0;
 
-    LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%RU32), cMaxHstStrmsIn=%RU32 (cb=%RU32)\n",
+    LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%zu), cMaxHstStrmsIn=%RU32 (cb=%zu)\n",
                  cMaxHstStrmsOut, cbHstStrmsOut, cMaxHstStrmsIn, cbHstStrmIn));
 
@@ -1753,11 +1787,4 @@
 
     int rc = RTCritSectInit(&pThis->CritSect);
-
-    /* Get the configuration data from the selected backend (if available). */
-    AssertPtr(pThis->pHostDrvAudio);
-    if (   RT_SUCCESS(rc)
-        && RT_LIKELY(pThis->pHostDrvAudio->pfnGetConf))
-        rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
-
     if (RT_SUCCESS(rc))
     {
@@ -2186,5 +2213,5 @@
         return rc;
 
-    memcpy(pCfg, &pThis->BackendCfg, sizeof(PDMAUDIOBACKENDCFG));
+    rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, pCfg);
 
     int rc2 = RTCritSectLeave(&pThis->CritSect);
Index: trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 59889)
+++ trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp	(revision 59890)
@@ -365,9 +365,4 @@
     }
 
-#ifdef DEBUG
-    drvAudioStreamCfgPrint(pCfg);
-#endif
-
-    LogFlowFunc(("rc=%Rrc\n", rc));
     return rc;
 }
Index: trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 59889)
+++ trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 59890)
@@ -95,4 +95,5 @@
     DWORD                cbPlayWritePos;
     DWORD                csPlaybackBufferSize;
+    bool                 fEnabled;
     bool                 fRestartPlayback;
     PDMAUDIOSTREAMCFG    streamCfg;
@@ -108,4 +109,5 @@
     HRESULT                     hrLastCaptureIn;
     PDMAUDIORECSOURCE           enmRecSource;
+    bool                        fEnabled;
     PDMAUDIOSTREAMCFG           streamCfg;
 } DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
@@ -123,9 +125,7 @@
     /** DirectSound configuration options. */
     DSOUNDHOSTCFG       cfg;
-    /** Whether the input currently is in an enabled (working)
-     *  state or not. */
+    /** Whether this backend supports any audio input. */
     bool                fEnabledIn;
-    /** Whether the output currently is in an enabled (working)
-     *  state or not. */
+    /** Whether this backend supports any audio output. */
     bool                fEnabledOut;
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -150,4 +150,9 @@
 } DRVHOSTDSOUND, *PDRVHOSTDSOUND;
 
+/** No flags specified. */
+#define DSOUNDENUMCBFLAGS_NONE          0
+/** (Release) log found devices. */
+#define DSOUNDENUMCBFLAGS_LOG           RT_BIT(0)
+
 /**
  * Callback context for enumeration callbacks
@@ -157,4 +162,6 @@
     PDRVHOSTDSOUND      pDrv;
     PPDMAUDIOBACKENDCFG pCfg;
+    /** Enumeration flags. */
+    uint32_t            fFlags;
 } DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
 
@@ -166,11 +173,15 @@
 } DSOUNDDEV, *PDSOUNDDEV;
 
+/** Maximum number of attempts to restore the sound buffer before giving up. */
+#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX         3
+
 /** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
 #define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
     ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
 
-static HRESULT directSoundPlayRestore(LPDIRECTSOUNDBUFFER8 pDSB);
-
-static void dsoundDevRemove(PDSOUNDDEV pDev);
+static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
+
+static void dsoundDeviceRemove(PDSOUNDDEV pDev);
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
 static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
@@ -225,6 +236,8 @@
 }
 
-static int dsoundGetStatusOut(PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
-{
+static int dsoundGetPosOut(PDRVHOSTDSOUND   pThis,
+                           PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
+{
+    AssertPtrReturn(pThis,          VERR_INVALID_POINTER);
     AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
 
@@ -237,11 +250,22 @@
     /* Get the current play position which is used for calculating the free space in the buffer. */
     DWORD cbPlayPos;
-    HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
-    if (hr == DSERR_BUFFERLOST)
-    {
-        hr = directSoundPlayRestore(pDSB);
-        if (SUCCEEDED(hr))
-            hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
-    }
+
+    HRESULT hr;
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
+        if (   SUCCEEDED(hr)
+            || hr != DSERR_BUFFERLOST) /** @todo: MSDN doesn't state this error for GetCurrentPosition(). */
+        {
+            break;
+        }
+        else
+        {
+            LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
+            directSoundPlayRestore(pThis, pDSB);
+        }
+    }
+
+    int rc = VINF_SUCCESS;
 
     if (FAILED(hr))
@@ -250,17 +274,21 @@
             DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
         LogFlowFunc(("Failed with %Rhrc\n", hr));
-        return VERR_NOT_AVAILABLE;
-    }
-
-    if (pdwBuffer)
-        *pdwBuffer = cbBuffer;
-
-    if (pdwFree)
-        *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
-
-    if (pdwPlayPos)
-        *pdwPlayPos = cbPlayPos;
-
-    return VINF_SUCCESS;
+
+        rc = VERR_NOT_AVAILABLE;
+    }
+    else
+    {
+        if (pdwBuffer)
+            *pdwBuffer = cbBuffer;
+
+        if (pdwFree)
+            *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
+
+        if (pdwPlayPos)
+            *pdwPlayPos = cbPlayPos;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
 }
 
@@ -284,11 +312,18 @@
 }
 
-static void dsoundFreeDeviceLists(PDRVHOSTDSOUND pThis)
-{
+/**
+ * Clears the list of the host's playback + capturing devices.
+ *
+ * @param   pThis               Host audio driver instance.
+ */
+static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
+{
+    AssertPtrReturnVoid(pThis);
+
     PDSOUNDDEV pDev;
     while (!RTListIsEmpty(&pThis->lstDevInput))
     {
         pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
-        dsoundDevRemove(pDev);
+        dsoundDeviceRemove(pDev);
     }
 
@@ -296,9 +331,9 @@
     {
         pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
-        dsoundDevRemove(pDev);
-    }
-}
-
-static HRESULT directSoundPlayRestore(LPDIRECTSOUNDBUFFER8 pDSB)
+        dsoundDeviceRemove(pDev);
+    }
+}
+
+static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
 {
     HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
@@ -308,5 +343,5 @@
 }
 
-static HRESULT directSoundPlayUnlock(LPDIRECTSOUNDBUFFER8 pDSB,
+static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
                                      LPVOID pv1, LPVOID pv2,
                                      DWORD cb1, DWORD cb2)
@@ -328,5 +363,6 @@
 }
 
-static HRESULT directSoundPlayLock(LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
+static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis,
+                                   LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
                                    DWORD dwOffset, DWORD dwBytes,
                                    LPVOID *ppv1, LPVOID *ppv2,
@@ -339,11 +375,15 @@
     DWORD cb2 = 0;
 
-    HRESULT hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
-    if (hr == DSERR_BUFFERLOST)
-    {
-        hr = directSoundPlayRestore(pDSB);
-        if (SUCCEEDED(hr))
-        {
-            hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
+    HRESULT hr;
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
+        if (   SUCCEEDED(hr)
+            || hr != DSERR_BUFFERLOST)
+            break;
+        else
+        {
+            LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
+            directSoundPlayRestore(pThis, pDSB);
         }
     }
@@ -360,5 +400,5 @@
         DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
                   cb1, cb2, pProps->uAlign));
-        directSoundPlayUnlock(pDSB, pv1, pv2, cb1, cb2);
+        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
         return E_FAIL;
     }
@@ -686,5 +726,5 @@
 }
 
-static void dsoundPlayClearSamples(PDSOUNDSTREAMOUT pDSoundStrmOut)
+static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
 {
     AssertPtrReturnVoid(pDSoundStrmOut);
@@ -694,5 +734,5 @@
     LPVOID pv1, pv2;
     DWORD cb1, cb2;
-    HRESULT hr = directSoundPlayLock(pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
+    HRESULT hr = directSoundPlayLock(pThis, pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
                                      0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStrmOut->MixBuf, pDSoundStrmOut->csPlaybackBufferSize),
                                      &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
@@ -708,29 +748,29 @@
             DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, cb2, len2);
 
-        directSoundPlayUnlock(pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
-    }
-}
-
-static HRESULT directSoundPlayGetStatus(LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
-{
-    AssertPtrReturn(pDSB, E_POINTER);
+        directSoundPlayUnlock(pThis, pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
+    }
+}
+
+static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
+{
+    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pDSB,  E_POINTER);
     /* pdwStatus is optional. */
 
-    bool fRestoreBuffer = false;
-
     DWORD dwStatus = 0;
-    HRESULT hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
-    if (SUCCEEDED(hr))
-    {
-        fRestoreBuffer = RT_BOOL(dwStatus & DSBSTATUS_BUFFERLOST);
-    }
-    else if (hr == DSERR_BUFFERLOST)
-        fRestoreBuffer = true;
-
-    if (fRestoreBuffer)
-    {
-        hr = directSoundPlayRestore(pDSB);
-        if (SUCCEEDED(hr))
-            hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
+
+    HRESULT hr;
+    for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+    {
+        hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
+        if (   hr == DSERR_BUFFERLOST
+            || (   SUCCEEDED(hr)
+                && (dwStatus & DSBSTATUS_BUFFERLOST)))
+        {
+            LogFlowFunc(("Getting status failed due to lost buffer, restoring ...\n"));
+            directSoundPlayRestore(pThis, pDSB);
+        }
+        else
+            break;
     }
 
@@ -748,5 +788,5 @@
 static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
 {
-    AssertPtrReturn(pThis, E_POINTER);
+    AssertPtrReturn(pThis,          E_POINTER);
     AssertPtrReturn(pDSoundStrmOut, E_POINTER);
 
@@ -755,20 +795,28 @@
     if (pDSoundStrmOut->pDSB != NULL)
     {
-        /* This performs some restore, so call it anyway and ignore result. */
-        hr = directSoundPlayGetStatus(pDSoundStrmOut->pDSB, NULL /* pdwStatus */);
-        if (SUCCEEDED(hr))
-        {
-            DSLOG(("DSound: Stopping playback\n"));
-
-            /** @todo Wait until all data in the buffer has been played. */
-            hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
-            if (SUCCEEDED(hr))
-                dsoundPlayClearSamples(pDSoundStrmOut);
-        }
+        DSLOG(("DSound: Stopping playback\n"));
+
+        HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
+        if (FAILED(hr2))
+        {
+            hr2 = directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
+            if (FAILED(hr2))
+                hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
+        }
+
+        if (FAILED(hr2))
+            DSLOG(("DSound: Stopping playback failed with %Rhrc\n", hr2));
+
+        hr = S_OK; /* Always report success here. */
     }
     else
         hr = E_UNEXPECTED;
 
-    if (FAILED(hr))
+    if (SUCCEEDED(hr))
+    {
+        dsoundPlayClearSamples(pThis, pDSoundStrmOut);
+        pDSoundStrmOut->fEnabled = false;
+    }
+    else
         DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
 
@@ -776,6 +824,7 @@
 }
 
-static HRESULT directSoundPlayStart(PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
+static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
+{
+    AssertPtrReturn(pThis,          E_POINTER);
     AssertPtrReturn(pDSoundStrmOut, E_POINTER);
 
@@ -784,5 +833,5 @@
     {
         DWORD dwStatus;
-        hr = directSoundPlayGetStatus(pDSoundStrmOut->pDSB, &dwStatus);
+        hr = directSoundPlayGetStatus(pThis, pDSoundStrmOut->pDSB, &dwStatus);
         if (SUCCEEDED(hr))
         {
@@ -793,11 +842,13 @@
             else
             {
-                dsoundPlayClearSamples(pDSoundStrmOut);
+                dsoundPlayClearSamples(pThis, pDSoundStrmOut);
 
                 pDSoundStrmOut->fRestartPlayback = true;
-
-                DSLOG(("DSound: Playback start\n"));
-
-                /* The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
+                pDSoundStrmOut->fEnabled         = true;
+
+                DSLOG(("DSound: Playback started\n"));
+
+                /*
+                 * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
                  * because it is necessary to put some samples into the buffer first.
                  */
@@ -1070,7 +1121,10 @@
 }
 
-static HRESULT directSoundCaptureStop(PDSOUNDSTREAMIN pDSoundStrmIn)
-{
+static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
+{
+    AssertPtrReturn(pThis        , E_POINTER);
     AssertPtrReturn(pDSoundStrmIn, E_POINTER);
+
+    NOREF(pThis);
 
     HRESULT hr;
@@ -1086,4 +1140,7 @@
     else
         hr = E_UNEXPECTED;
+
+    if (SUCCEEDED(hr))
+        pDSoundStrmIn->fEnabled = false;
 
     LogFlowFunc(("Returning %Rhrc\n", hr));
@@ -1127,4 +1184,7 @@
         hr = E_UNEXPECTED;
 
+    if (SUCCEEDED(hr))
+        pDSoundStrmIn->fEnabled = true;
+
     LogFlowFunc(("Returning %Rhrc\n", hr));
     return hr;
@@ -1155,5 +1215,5 @@
 }
 
-static void dsoundDevRemove(PDSOUNDDEV pDev)
+static void dsoundDeviceRemove(PDSOUNDDEV pDev)
 {
     if (pDev)
@@ -1177,6 +1237,6 @@
 }
 
-static BOOL CALLBACK dsoundEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
-                                        LPCWSTR lpwstrModule, LPVOID lpContext)
+static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+                                                 LPCWSTR lpwstrModule, LPVOID lpContext)
 {
     PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
@@ -1189,7 +1249,8 @@
 
     AssertPtrReturn(lpwstrDescription, FALSE);
-    /* Do not care about lpwstrModule */
-
-    dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
+    /* Do not care about lpwstrModule. */
+
+    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
+        dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
 
     int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
@@ -1203,6 +1264,6 @@
 }
 
-static BOOL CALLBACK dsoundCaptureEnumCallback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
-                                               LPCWSTR lpwstrModule, LPVOID lpContext)
+static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+                                                LPCWSTR lpwstrModule, LPVOID lpContext)
 {
     PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
@@ -1214,5 +1275,6 @@
         return TRUE;
 
-    dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
+    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
+        dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
 
     int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
@@ -1226,4 +1288,101 @@
 }
 
+/**
+ * Does a (Re-)enumeration of the host's playback + capturing devices.
+ *
+ * @return  IPRT status code.
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the enumeration results.
+ * @param   fEnum               Enumeration flags.
+ */
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+{
+    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+    AssertPtrReturn(pCfg,  VERR_INVALID_POINTER);
+
+    dsoundDevicesClear(pThis);
+
+    pCfg->cMaxHstStrmsOut = 0;
+    pCfg->cMaxHstStrmsIn  = 0;
+
+    RTLDRMOD hDSound = NULL;
+    int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
+    if (RT_SUCCESS(rc))
+    {
+        PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
+        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
+
+        rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
+        if (RT_SUCCESS(rc))
+            rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
+
+        if (RT_SUCCESS(rc))
+        {
+            DSOUNDENUMCBCTX ctx = { pThis, pCfg, fEnum };
+
+            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &ctx);
+            if (FAILED(hr))
+                LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
+
+            hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &ctx);
+            if (FAILED(hr))
+                LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
+        }
+
+        RTLdrClose(hDSound);
+    }
+    else
+    {
+        /* No dsound.dll on this system. */
+        LogRel2(("DSound: Could not load dsound.dll: %Rrc\n", rc));
+    }
+
+    return rc;
+}
+
+/**
+ * Updates this host driver's internal status, according to the global, overall input/output
+ * state and all connected (native) audio streams.
+ *
+ * @param   pThis               Host audio driver instance.
+ * @param   pCfg                Where to store the backend configuration. Optional.
+ * @param   fEnum               Enumeration flags.
+ */
+void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+{
+    AssertPtrReturnVoid(pThis);
+    /* pCfg is optional. */
+
+    PDMAUDIOBACKENDCFG Cfg;
+    RT_ZERO(Cfg);
+
+    Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
+    Cfg.cbStreamIn  = sizeof(DSOUNDSTREAMIN);
+
+    int rc = dsoundDevicesEnumerate(pThis, &Cfg, fEnum);
+    AssertRC(rc);
+
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+    if (   pThis->fEnabledOut != RT_BOOL(Cfg.cMaxHstStrmsOut)
+        || pThis->fEnabledIn  != RT_BOOL(Cfg.cMaxHstStrmsIn))
+    {
+        /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
+         *        let the connector know that something has changed within the host backend. */
+    }
+#else
+    pThis->fEnabledOut = RT_BOOL(Cfg.cMaxHstStrmsOut);
+    pThis->fEnabledIn  = RT_BOOL(Cfg.cMaxHstStrmsIn);
+#endif
+
+    if (pCfg)
+        memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
+
+    LogFlowFuncLeaveRC(rc);
+}
+
+void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
+{
+    dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
+}
 
 /*
@@ -1280,5 +1439,5 @@
     LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
 
-    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDRVHOSTDSOUND   pThis          = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
 
@@ -1293,17 +1452,16 @@
             DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_ENABLE\n"));
             /* Try to start playback. If it fails, then reopen and try again. */
-            hr = directSoundPlayStart(pDSoundStrmOut);
+            hr = directSoundPlayStart(pThis, pDSoundStrmOut);
             if (FAILED(hr))
             {
-                directSoundPlayClose(pThis, pDSoundStrmOut);
-                directSoundPlayOpen(pThis, pDSoundStrmOut);
-
-                hr = directSoundPlayStart(pDSoundStrmOut);
+                hr = directSoundPlayClose(pThis, pDSoundStrmOut);
+                if (SUCCEEDED(hr))
+                    hr = directSoundPlayOpen(pThis, pDSoundStrmOut);
+                if (SUCCEEDED(hr))
+                    hr = directSoundPlayStart(pThis, pDSoundStrmOut);
             }
 
             if (FAILED(hr))
                 rc = VERR_NOT_SUPPORTED;
-
-            pThis->fEnabledOut = RT_SUCCESS(rc);
             break;
         }
@@ -1314,6 +1472,6 @@
             DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_DISABLE\n"));
             hr = directSoundPlayStop(pThis, pDSoundStrmOut);
-            if (SUCCEEDED(hr))
-                pThis->fEnabledOut = false;
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
             break;
         }
@@ -1344,15 +1502,14 @@
     uint32_t cReadTotal = 0;
 
+#ifdef DEBUG_andy
+    LogFlowFuncEnter();
+#endif
+
     do /* to use 'break' */
     {
         DWORD cbBuffer, cbFree, cbPlayPos;
-        rc = dsoundGetStatusOut(pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
+        rc = dsoundGetPosOut(pThis, pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
         if (RT_FAILURE(rc))
-        {
-            /* Set the output status to disabled, as we are not able to retrieve the current
-             * status (anymore). */
-            pThis->fEnabledOut = false;
-            break;
-        }
+            break;
 
         /*
@@ -1384,5 +1541,5 @@
         LPVOID pv1, pv2;
         DWORD cb1, cb2;
-        HRESULT hr = directSoundPlayLock(pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
+        HRESULT hr = directSoundPlayLock(pThis, pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
                                          &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
         if (FAILED(hr))
@@ -1413,5 +1570,5 @@
         }
 
-        directSoundPlayUnlock(pDSB, pv1, pv2, cb1, cb2);
+        directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
 
         pDSoundStrmOut->cbPlayWritePos =
@@ -1445,5 +1602,17 @@
             fFlags |= DSCBSTART_LOOPING;
 #endif
-            hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
+            for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
+            {
+                hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
+                if (   SUCCEEDED(hr)
+                    || hr != DSERR_BUFFERLOST)
+                    break;
+                else
+                {
+                    LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
+                    directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
+                }
+            }
+
             if (FAILED(hr))
             {
@@ -1456,5 +1625,9 @@
     } while (0);
 
-    if (RT_SUCCESS(rc))
+    if (RT_FAILURE(rc))
+    {
+        dsoundUpdateStatusInternal(pThis);
+    }
+    else
     {
         if (pcSamplesPlayed)
@@ -1462,4 +1635,5 @@
     }
 
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -1530,5 +1704,5 @@
     LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
 
-    PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+    PDRVHOSTDSOUND  pThis         = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
     PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
 
@@ -1556,6 +1730,4 @@
             if (FAILED(hr))
                 rc = VERR_NOT_SUPPORTED;
-
-            pThis->fEnabledIn = RT_SUCCESS(rc);
             break;
         }
@@ -1564,7 +1736,7 @@
         case PDMAUDIOSTREAMCMD_PAUSE:
         {
-            hr = directSoundCaptureStop(pDSoundStrmIn);
-            if (SUCCEEDED(hr))
-                pThis->fEnabledIn = false;
+            hr = directSoundCaptureStop(pThis, pDSoundStrmIn);
+            if (FAILED(hr))
+                rc = VERR_NOT_SUPPORTED;
             break;
         }
@@ -1585,6 +1757,7 @@
 {
     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-    PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
-    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStrmIn->pDSCB;
+
+    PDSOUNDSTREAMIN             pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+    LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB         = pDSoundStrmIn->pDSCB;
 
     int rc = VINF_SUCCESS;
@@ -1596,6 +1769,4 @@
         if (pDSCB == NULL)
         {
-            pThis->fEnabledIn = false;
-
             rc = VERR_NOT_AVAILABLE;
             break;
@@ -1698,7 +1869,15 @@
     } while (0);
 
-    if (pcSamplesCaptured)
-        *pcSamplesCaptured = cCaptured;
-
+    if (RT_FAILURE(rc))
+    {
+        dsoundUpdateStatusInternal(pThis);
+    }
+    else
+    {
+        if (pcSamplesCaptured)
+            *pcSamplesCaptured = cCaptured;
+    }
+
+    LogFlowFuncLeaveRC(rc);
     return rc;
 }
@@ -1738,62 +1917,5 @@
     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
 
-    dsoundFreeDeviceLists(pThis);
-
-    pCfg->cbStreamOut = sizeof(DSOUNDSTREAMOUT);
-    pCfg->cbStreamIn  = sizeof(DSOUNDSTREAMIN);
-
-    pCfg->cMaxHstStrmsOut = 0;
-    pCfg->cMaxHstStrmsIn  = 0;
-
-    RTLDRMOD hDSound = NULL;
-    int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
-    if (RT_SUCCESS(rc))
-    {
-        PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
-        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
-
-        rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
-        if (RT_SUCCESS(rc))
-        {
-            rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
-        }
-
-        if (RT_SUCCESS(rc))
-        {
-            DSOUNDENUMCBCTX ctx = { pThis, pCfg };
-
-            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundEnumCallback, &ctx);
-            if (FAILED(hr))
-                LogRel(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
-
-            LogRel(("DSound: Found %RU32 host playback devices\n", pCfg->cMaxHstStrmsOut));
-
-            hr = pfnDirectSoundCaptureEnumerateW(&dsoundCaptureEnumCallback, &ctx);
-            if (FAILED(hr))
-                LogRel(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
-
-            LogRel(("DSound: Found %RU32 host capturing devices\n", pCfg->cMaxHstStrmsIn));
-        }
-
-        RTLdrClose(hDSound);
-    }
-    else
-    {
-        /* No dsound.dll on this system.  */
-        LogRel(("DSound: Could not load dsound.dll %Rrc\n", rc));
-    }
-
-    /* Always return success and at least default values to make the caller happy. */
-    if (pCfg->cMaxHstStrmsOut == 0)
-    {
-        LogRel(("DSound: Adjusting the number of host playback devices to 1\n"));
-        pCfg->cMaxHstStrmsOut = 1; /* Support at least one stream. */
-    }
-
-    if (pCfg->cMaxHstStrmsIn < 2)
-    {
-        LogRel(("DSound: Adjusting the number of host capturing devices from %RU32 to 2\n", pCfg->cMaxHstStrmsIn));
-        pCfg->cMaxHstStrmsIn = 2; /* Support at least two streams (line in + mic). */
-    }
+    dsoundUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
 
     return VINF_SUCCESS;
@@ -1871,5 +1993,5 @@
                 {
                     DWORD cbBuffer, cbFree, cbPlayPos;
-                    rc = dsoundGetStatusOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
+                    rc = dsoundGetPosOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
                     if (   RT_SUCCESS(rc)
                         && cbFree)
@@ -1973,4 +2095,10 @@
         rc = VINF_SUCCESS;
 #endif
+
+        PDMAUDIOBACKENDCFG Cfg;
+        dsoundUpdateStatusInternalEx(pThis, &Cfg, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
+
+        DSLOGREL(("DSound: Found %RU32 host playback devices\n",  Cfg.cMaxHstStrmsOut));
+        DSLOGREL(("DSound: Found %RU32 host capturing devices\n", Cfg.cMaxHstStrmsIn));
     }
     else
@@ -2095,6 +2223,6 @@
     pThis->fEnabledOut = false;
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
-    pThis->fStopped  = false;
-    pThis->fShutdown = false;
+    pThis->fStopped    = false;
+    pThis->fShutdown   = false;
 
     RT_ZERO(pThis->aEvents);
