Index: trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp
===================================================================
--- trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 77027)
+++ trunk/src/VBox/Devices/Audio/DrvHostDSound.cpp	(revision 77028)
@@ -177,4 +177,24 @@
 } DSOUNDSTREAM, *PDSOUNDSTREAM;
 
+/**
+ * Structure for keeping a DirectSound-specific device entry.
+ * This is then bound to the PDMAUDIODEVICE's pvData area.
+ */
+typedef struct DSOUNDDEV
+{
+    GUID Guid;
+} DSOUNDDEV, *PDSOUNDDEV;
+
+/**
+ * Structure for holding a device enumeration context.
+ */
+typedef struct DSOUNDENUMCBCTX
+{
+    /** Enumeration flags. */
+    uint32_t            fFlags;
+    /** Pointer to device list to populate. */
+    PPDMAUDIODEVICEENUM pDevEnm;
+} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
+
 typedef struct DRVHOSTDSOUND
 {
@@ -185,10 +205,8 @@
     /** Critical section to serialize access. */
     RTCRITSECT                  CritSect;
-    /** List of found host input devices. */
-    RTLISTANCHOR                lstDevInput;
-    /** List of found host output devices. */
-    RTLISTANCHOR                lstDevOutput;
     /** DirectSound configuration options. */
     DSOUNDHOSTCFG               Cfg;
+    /** List of devices of last enumeration. */
+    PDMAUDIODEVICEENUM          DeviceEnum;
     /** Whether this backend supports any audio input. */
     bool                        fEnabledIn;
@@ -213,32 +231,4 @@
 } DRVHOSTDSOUND, *PDRVHOSTDSOUND;
 
-/** No flags specified. */
-#define DSOUNDENUMCBFLAGS_NONE          0
-/** (Release) log found devices. */
-#define DSOUNDENUMCBFLAGS_LOG           RT_BIT(0)
-
-/**
- * Callback context for enumeration callbacks
- */
-typedef struct DSOUNDENUMCBCTX
-{
-    /** Pointer to host backend driver. */
-    PDRVHOSTDSOUND      pDrv;
-    /** Enumeration flags. */
-    uint32_t            fFlags;
-    /** Number of found input devices. */
-    uint8_t             cDevIn;
-    /** Number of found output devices. */
-    uint8_t             cDevOut;
-} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
-
-typedef struct DSOUNDDEV
-{
-    RTLISTNODE  Node;
-    char       *pszName;
-    GUID        Guid;
-} DSOUNDDEV, *PDSOUNDDEV;
-
-
 /*********************************************************************************************************************************
 *   Internal Functions                                                                                                           *
@@ -249,11 +239,9 @@
 static HRESULT  directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fFlush);
 
-static void     dsoundDeviceRemove(PDSOUNDDEV pDev);
-static int      dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
+static int      dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDMAUDIODEVICEENUM pDevEnm, uint32_t fEnum);
 
 static int      dsoundStreamEnable(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS, bool fEnable);
 static void     dsoundStreamReset(PDRVHOSTDSOUND pThis, PDSOUNDSTREAM pStreamDS);
 static void     dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis);
-static void     dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum);
 
 
@@ -379,25 +367,4 @@
 
     return RTStrDup("{Default device}");
-}
-
-/**
- * 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, pDevNext;
-    RTListForEachSafe(&pThis->lstDevInput, pDev, pDevNext, DSOUNDDEV, Node)
-        dsoundDeviceRemove(pDev);
-
-    Assert(RTListIsEmpty(&pThis->lstDevInput));
-
-    RTListForEachSafe(&pThis->lstDevOutput, pDev, pDevNext, DSOUNDDEV, Node)
-        dsoundDeviceRemove(pDev);
-
-    Assert(RTListIsEmpty(&pThis->lstDevOutput));
 }
 
@@ -522,24 +489,37 @@
  */
 
-static void directSoundPlayInterfaceDestroy(PDRVHOSTDSOUND pThis)
-{
-    if (pThis->pDS)
+/**
+ * Destroys a DirectSound playback interface.
+ *
+ * @param   pDS                 Playback interface to destroy.
+ */
+static void directSoundPlayInterfaceDestroy(LPDIRECTSOUND8 pDS)
+{
+    if (pDS)
     {
         LogFlowFuncEnter();
 
-        IDirectSound8_Release(pThis->pDS);
-        pThis->pDS = NULL;
-    }
-}
-
-static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis)
-{
-    if (pThis->pDS != NULL)
-        return S_OK;
+        IDirectSound8_Release(pDS);
+        pDS = NULL;
+    }
+}
+
+/**
+ * Creates a DirectSound playback interface.
+ *
+ * @return  HRESULT
+ * @param   pThis               GUID of device to create the playback interface for.
+ * @param   ppDSC               Where to store the created interface. Optional.
+ */
+static HRESULT directSoundPlayInterfaceCreate(LPCGUID pGUID, LPDIRECTSOUND8 *ppDS)
+{
+    /* pGUID can be NULL, if this is the default device. */
+    /* ppDS is optional. */
 
     LogFlowFuncEnter();
 
+    LPDIRECTSOUND8 pDS;
     HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL,
-                                  IID_IDirectSound8, (void **)&pThis->pDS);
+                                  IID_IDirectSound8, (void **)&pDS);
     if (FAILED(hr))
     {
@@ -548,9 +528,9 @@
     else
     {
-        hr = IDirectSound8_Initialize(pThis->pDS, pThis->Cfg.pGuidPlay);
+        hr = IDirectSound8_Initialize(pDS, pGUID);
         if (SUCCEEDED(hr))
         {
             HWND hWnd = GetDesktopWindow();
-            hr = IDirectSound8_SetCooperativeLevel(pThis->pDS, hWnd, DSSCL_PRIORITY);
+            hr = IDirectSound8_SetCooperativeLevel(pDS, hWnd, DSSCL_PRIORITY);
             if (FAILED(hr))
                 DSLOGREL(("DSound: Setting cooperative level for window %p failed with %Rhrc\n", hWnd, hr));
@@ -564,5 +544,9 @@
                 DSLOGREL(("DSound: DirectSound playback initialization failed with %Rhrc\n", hr));
 
-            directSoundPlayInterfaceDestroy(pThis);
+            directSoundPlayInterfaceDestroy(pDS);
+        }
+        else if (ppDS)
+        {
+            *ppDS = pDS;
         }
     }
@@ -656,5 +640,5 @@
     dsoundUpdateStatusInternal(pThis);
 
-    HRESULT hr = directSoundPlayInterfaceCreate(pThis);
+    HRESULT hr = directSoundPlayInterfaceCreate(pThis->Cfg.pGuidPlay, &pThis->pDS);
     if (FAILED(hr))
         return hr;
@@ -1153,5 +1137,5 @@
     if (!pGUID)
     {
-        PDSOUNDDEV pDev = NULL;
+        PPDMAUDIODEVICE pDev = NULL;
 
         switch (pCfg->DestSource.Source)
@@ -1167,13 +1151,5 @@
             case PDMAUDIORECSOURCE_MIC:
             {
-                RTListForEach(&pThis->lstDevInput, pDev, DSOUNDDEV, Node)
-                {
-                    if (RTStrIStr(pDev->pszName, "Mic")) /** @todo What is with non en_us windows versions? */
-                        break;
-                }
-
-                if (RTListNodeIsDummy(&pThis->lstDevInput, pDev, DSOUNDDEV, Node))
-                    pDev = NULL; /* Found nothing. */
-
+                pDev = DrvAudioHlpDeviceEnumGetDefaultDevice(&pThis->DeviceEnum, PDMAUDIODIR_IN);
                 break;
             }
@@ -1188,7 +1164,10 @@
         {
             DSLOG(("DSound: Guest source '%s' is using host recording device '%s'\n",
-                   DrvAudioHlpRecSrcToStr(pCfg->DestSource.Source), pDev->pszName));
-
-            pGUID = &pDev->Guid;
+                   DrvAudioHlpRecSrcToStr(pCfg->DestSource.Source), pDev->szName));
+
+            PDSOUNDDEV pDSoundDev = (PDSOUNDDEV )pDev->pvData;
+            AssertPtr(pDSoundDev);
+
+            pGUID = &pDSoundDev->Guid;
         }
     }
@@ -1306,39 +1285,36 @@
 
 /**
- * Destroys the DirectSound capturing interface.
+ * Destroys a DirectSound capture interface.
  *
- * @return  IPRT status code.
- * @param   pThis               Driver instance to destroy capturing interface for.
- */
-static void directSoundCaptureInterfaceDestroy(PDRVHOSTDSOUND pThis)
-{
-    if (pThis->pDSC)
+ * @param   pDSC                Capture interface to destroy.
+ */
+static void directSoundCaptureInterfaceDestroy(LPDIRECTSOUNDCAPTURE8 pDSC)
+{
+    if (pDSC)
     {
         LogFlowFuncEnter();
 
-        IDirectSoundCapture_Release(pThis->pDSC);
-        pThis->pDSC = NULL;
-    }
-}
-
-/**
- * Creates the DirectSound capturing interface.
+        IDirectSoundCapture_Release(pDSC);
+        pDSC = NULL;
+    }
+}
+
+/**
+ * Creates a DirectSound capture interface.
  *
- * @return  IPRT status code.
- * @param   pThis               Driver instance to create the capturing interface for.
- * @param   pCfg                Audio stream to use for creating the capturing interface.
- */
-static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
-    AssertPtrReturn(pThis,     E_POINTER);
-    AssertPtrReturn(pCfg,      E_POINTER);
-
-    if (pThis->pDSC)
-        return S_OK;
+ * @return  HRESULT
+ * @param   pGUID               GUID of device to create the capture interface for.
+ * @param   ppDSC               Where to store the created interface. Optional.
+ */
+static HRESULT directSoundCaptureInterfaceCreate(LPCGUID pGUID, LPDIRECTSOUNDCAPTURE8 *ppDSC)
+{
+    /* pGUID can be NULL, if this is the default device. */
+    /* ppDSC is optional. */
 
     LogFlowFuncEnter();
 
+    LPDIRECTSOUNDCAPTURE8 pDSC;
     HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,
-                                  IID_IDirectSoundCapture8, (void **)&pThis->pDSC);
+                                  IID_IDirectSoundCapture8, (void **)&pDSC);
     if (FAILED(hr))
     {
@@ -1347,8 +1323,5 @@
     else
     {
-        LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pCfg);
-        /* pGUID can be NULL when using the default device. */
-
-        hr = IDirectSoundCapture_Initialize(pThis->pDSC, pGUID);
+        hr = IDirectSoundCapture_Initialize(pDSC, pGUID);
         if (FAILED(hr))
         {
@@ -1358,5 +1331,9 @@
                 DSLOGREL(("DSound: Initializing capturing device failed with %Rhrc\n", hr));
 
-            directSoundCaptureInterfaceDestroy(pThis);
+            directSoundCaptureInterfaceDestroy(pDSC);
+        }
+        else if (ppDSC)
+        {
+            *ppDSC = pDSC;
         }
     }
@@ -1413,7 +1390,7 @@
         return E_INVALIDARG;
 
-    dsoundUpdateStatusInternalEx(pThis, NULL /* Cfg */, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
-
-    HRESULT hr = directSoundCaptureInterfaceCreate(pThis, pCfgReq);
+    dsoundUpdateStatusInternal(pThis);
+
+    HRESULT hr = directSoundCaptureInterfaceCreate(pThis->Cfg.pGuidCapture, &pThis->pDSC);
     if (FAILED(hr))
         return hr;
@@ -1593,99 +1570,192 @@
 }
 
-static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID pGUID, LPCWSTR pwszDescription, PDSOUNDDEV *ppDev)
-{
-    AssertPtrReturn(pList, VERR_INVALID_POINTER);
-    AssertPtrReturn(pGUID, VERR_INVALID_POINTER);
-    AssertPtrReturn(pwszDescription, VERR_INVALID_POINTER);
-
-    PDSOUNDDEV pDev = (PDSOUNDDEV)RTMemAlloc(sizeof(DSOUNDDEV));
-    if (!pDev)
-        return VERR_NO_MEMORY;
-
-    int rc = RTUtf16ToUtf8(pwszDescription, &pDev->pszName);
-    if (   RT_SUCCESS(rc)
-        && pGUID)
-    {
-        memcpy(&pDev->Guid, pGUID, sizeof(GUID));
-    }
-
-    if (RT_SUCCESS(rc))
-        RTListAppend(pList, &pDev->Node);
-
-    if (ppDev)
-        *ppDev = pDev;
-
-    return rc;
-}
-
-static void dsoundDeviceRemove(PDSOUNDDEV pDev)
-{
-    if (pDev)
-    {
-        if (pDev->pszName)
-        {
-            RTStrFree(pDev->pszName);
-            pDev->pszName = NULL;
-        }
-
-        RTListNodeRemove(&pDev->Node);
-
-        RTMemFree(pDev);
-        pDev = NULL;
-    }
-}
-
-static void dsoundLogDevice(const char *pszType, LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule)
-{
-    char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
-    /* This always has to be in the release log.
-     * Only print this when we're running in verbose (audio debug) mode, as this can generate a lot of content. */
-    LogRel2(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n", pszType, pszGUID ? pszGUID : "{?}", pwszDescription, pwszModule));
-    RTStrFree(pszGUID);
-}
-
+/**
+ * Callback for the playback device enumeration.
+ *
+ * @return  TRUE if continuing enumeration, FALSE if not.
+ * @param   pGUID               Pointer to GUID of enumerated device. Can be NULL.
+ * @param   pwszDescription     Pointer to (friendly) description of enumerated device.
+ * @param   pwszModule          Pointer to module name of enumerated device.
+ * @param   lpContext           Pointer to PDSOUNDENUMCBCTX context for storing the enumerated information.
+ */
 static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
 {
-    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
-    AssertPtrReturn(pCtx, FALSE);
-    AssertPtrReturn(pCtx->pDrv, FALSE);
-
-    if (!pGUID)
-        return TRUE;
-
+    RT_NOREF(pwszModule);
+
+    PDSOUNDENUMCBCTX pEnumCtx = (PDSOUNDENUMCBCTX)lpContext;
+    AssertPtrReturn(pEnumCtx , FALSE);
+
+    PPDMAUDIODEVICEENUM pDevEnm = pEnumCtx->pDevEnm;
+    AssertPtrReturn(pDevEnm, FALSE);
+
+    /* pGUID can be NULL for default device(s). */
     AssertPtrReturn(pwszDescription, FALSE);
     /* Do not care about pwszModule. */
 
-    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
-        dsoundLogDevice("Output", pGUID, pwszDescription, pwszModule);
-
-    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
-                          pGUID, pwszDescription, NULL /* ppDev */);
+    int rc;
+
+    PPDMAUDIODEVICE pDev = DrvAudioHlpDeviceAlloc(sizeof(DSOUNDDEV));
+    if (pDev)
+    {
+        pDev->enmUsage = PDMAUDIODIR_OUT;
+        pDev->enmType  = PDMAUDIODEVICETYPE_BUILTIN;
+
+        if (pGUID == NULL)
+            pDev->fFlags = PDMAUDIODEV_FLAGS_DEFAULT;
+
+        char *pszName;
+        rc = RTUtf16ToUtf8(pwszDescription, &pszName);
+        if (RT_SUCCESS(rc))
+        {
+            RTStrCopy(pDev->szName, sizeof(pDev->szName), pszName);
+            RTStrFree(pszName);
+
+            PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
+
+            if (pGUID)
+                memcpy(&pDSoundDev->Guid, pGUID, sizeof(GUID));
+
+            LPDIRECTSOUND8 pDS;
+            HRESULT hr = directSoundPlayInterfaceCreate(pGUID, &pDS);
+            if (SUCCEEDED(hr))
+            {
+                do
+                {
+                    DSCAPS DSCaps;
+                    RT_ZERO(DSCaps);
+                    DSCaps.dwSize = sizeof(DSCAPS);
+                    hr = IDirectSound_GetCaps(pDS, &DSCaps);
+                    if (FAILED(hr))
+                        break;
+
+                    pDev->cMaxOutputChannels = DSCaps.dwFlags & DSCAPS_PRIMARYSTEREO ? 2 : 1;
+
+                    DWORD dwSpeakerCfg;
+                    hr = IDirectSound_GetSpeakerConfig(pDS, &dwSpeakerCfg);
+                    if (FAILED(hr))
+                        break;
+
+                    unsigned uSpeakerCount = 0;
+                    switch (DSSPEAKER_CONFIG(dwSpeakerCfg))
+                    {
+                        case DSSPEAKER_MONO:             uSpeakerCount = 1; break;
+                        case DSSPEAKER_HEADPHONE:        uSpeakerCount = 2; break;
+                        case DSSPEAKER_STEREO:           uSpeakerCount = 2; break;
+                        case DSSPEAKER_QUAD:             uSpeakerCount = 4; break;
+                        case DSSPEAKER_SURROUND:         uSpeakerCount = 4; break;
+                        case DSSPEAKER_5POINT1:          uSpeakerCount = 6; break;
+                        case DSSPEAKER_5POINT1_SURROUND: uSpeakerCount = 6; break;
+                        case DSSPEAKER_7POINT1:          uSpeakerCount = 8; break;
+                        case DSSPEAKER_7POINT1_SURROUND: uSpeakerCount = 8; break;
+                        default:                                            break;
+                    }
+
+                    if (uSpeakerCount) /* Do we need to update the channel count? */
+                        pDev->cMaxOutputChannels = uSpeakerCount;
+
+                } while (0);
+
+                directSoundPlayInterfaceDestroy(pDS);
+
+                rc = VINF_SUCCESS;
+            }
+            else
+                rc = VERR_GENERAL_FAILURE;
+
+            if (RT_SUCCESS(rc))
+                rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
     if (RT_FAILURE(rc))
+    {
+        LogRel(("DSound: Error enumeration playback device '%ls', rc=%Rrc\n", pwszDescription, rc));
         return FALSE; /* Abort enumeration. */
-
-    pCtx->cDevOut++;
+    }
 
     return TRUE;
 }
 
+/**
+ * Callback for the capture device enumeration.
+ *
+ * @return  TRUE if continuing enumeration, FALSE if not.
+ * @param   pGUID               Pointer to GUID of enumerated device. Can be NULL.
+ * @param   pwszDescription     Pointer to (friendly) description of enumerated device.
+ * @param   pwszModule          Pointer to module name of enumerated device.
+ * @param   lpContext           Pointer to PDSOUNDENUMCBCTX context for storing the enumerated information.
+ */
 static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
 {
-    PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
-    AssertPtrReturn(pCtx, FALSE);
-    AssertPtrReturn(pCtx->pDrv, FALSE);
-
-    if (!pGUID)
-        return TRUE;
-
-    if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
-        dsoundLogDevice("Input", pGUID, pwszDescription, pwszModule);
-
-    int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
-                          pGUID, pwszDescription, NULL /* ppDev */);
+    RT_NOREF(pwszModule);
+
+    PDSOUNDENUMCBCTX pEnumCtx = (PDSOUNDENUMCBCTX )lpContext;
+    AssertPtrReturn(pEnumCtx , FALSE);
+
+    PPDMAUDIODEVICEENUM pDevEnm = pEnumCtx->pDevEnm;
+    AssertPtrReturn(pDevEnm, FALSE);
+
+    /* pGUID can be NULL for default device(s). */
+    AssertPtrReturn(pwszDescription, FALSE);
+    /* Do not care about pwszModule. */
+
+    int rc;
+
+    PPDMAUDIODEVICE pDev = DrvAudioHlpDeviceAlloc(sizeof(DSOUNDDEV));
+    if (pDev)
+    {
+        pDev->enmUsage = PDMAUDIODIR_IN;
+        pDev->enmType  = PDMAUDIODEVICETYPE_BUILTIN;
+
+        char *pszName;
+        rc = RTUtf16ToUtf8(pwszDescription, &pszName);
+        if (RT_SUCCESS(rc))
+        {
+            RTStrCopy(pDev->szName, sizeof(pDev->szName), pszName);
+            RTStrFree(pszName);
+
+            PDSOUNDDEV pDSoundDev = (PDSOUNDDEV)pDev->pvData;
+
+            if (pGUID)
+                memcpy(&pDSoundDev->Guid, pGUID, sizeof(GUID));
+
+            LPDIRECTSOUNDCAPTURE8 pDSC;
+            HRESULT hr = directSoundCaptureInterfaceCreate(pGUID, &pDSC);
+            if (SUCCEEDED(hr))
+            {
+                do
+                {
+                    DSCCAPS DSCCaps;
+                    RT_ZERO(DSCCaps);
+                    DSCCaps.dwSize = sizeof(DSCCAPS);
+                    hr = IDirectSoundCapture_GetCaps(pDSC, &DSCCaps);
+                    if (FAILED(hr))
+                        break;
+
+                    pDev->cMaxInputChannels = DSCCaps.dwChannels;
+
+                } while (0);
+
+                directSoundCaptureInterfaceDestroy(pDSC);
+
+                rc = VINF_SUCCESS;
+            }
+            else
+                rc = VERR_GENERAL_FAILURE;
+
+            if (RT_SUCCESS(rc))
+                rc = DrvAudioHlpDeviceEnumAdd(pDevEnm, pDev);
+        }
+    }
+    else
+        rc = VERR_NO_MEMORY;
+
     if (RT_FAILURE(rc))
+    {
+        LogRel(("DSound: Error enumeration capture device '%ls', rc=%Rrc\n", pwszDescription, rc));
         return FALSE; /* Abort enumeration. */
-
-    pCtx->cDevIn++;
+    }
 
     return TRUE;
@@ -1697,13 +1767,11 @@
  * @return  IPRT status code.
  * @param   pThis               Host audio driver instance.
- * @param   pEnmCtx             Enumeration context to use.
- * @param   fEnum               Enumeration flags.
- */
-static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx, uint32_t fEnum)
-{
-    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
-    AssertPtrReturn(pEnmCtx, VERR_INVALID_POINTER);
-
-    dsoundDevicesClear(pThis);
+ * @param   pDevEnm             Where to store the enumerated devices.
+ */
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIODEVICEENUM pDevEnm)
+{
+    AssertPtrReturn(pThis,    VERR_INVALID_POINTER);
+
+    DSLOG(("DSound: Enumerating devices ...\n"));
 
     RTLDRMOD hDSound = NULL;
@@ -1711,27 +1779,29 @@
     if (RT_SUCCESS(rc))
     {
+        DSOUNDENUMCBCTX EnumCtx;
+        EnumCtx.fFlags  = 0;
+        EnumCtx.pDevEnm = pDevEnm;
+
         PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
-        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
-
         rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
         if (RT_SUCCESS(rc))
-            rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
-
+        {
+            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &EnumCtx);
+            if (FAILED(hr))
+                LogRel(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
+        }
+        else
+            LogRel(("DSound: Error starting to enumerate host playback devices: %Rrc\n", rc));
+
+        PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
+        rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
         if (RT_SUCCESS(rc))
         {
-            HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, pEnmCtx);
+            HRESULT hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &EnumCtx);
             if (FAILED(hr))
-                LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
-
-            hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, pEnmCtx);
-            if (FAILED(hr))
-                LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
-
-            if (fEnum & DSOUNDENUMCBFLAGS_LOG)
-            {
-                LogRel2(("DSound: Found %RU8 host playback devices\n",  pEnmCtx->cDevOut));
-                LogRel2(("DSound: Found %RU8 host capturing devices\n", pEnmCtx->cDevIn));
-            }
-        }
+                LogRel(("DSound: Error enumerating host capture devices: %Rhrc\n", hr));
+        }
+        else
+            LogRel(("DSound: Error starting to enumerate host capture devices: %Rrc\n", rc));
 
         RTLdrClose(hDSound);
@@ -1740,6 +1810,8 @@
     {
         /* No dsound.dll on this system. */
-        LogRel2(("DSound: Could not load dsound.dll: %Rrc\n", rc));
-    }
+        LogRel(("DSound: Could not load dsound.dll: %Rrc\n", rc));
+    }
+
+    DSLOG(("DSound: Enumerating devices done\n"));
 
     return rc;
@@ -1751,21 +1823,13 @@
  *
  * @param   pThis               Host audio driver instance.
- * @param   pCfg                Where to store the backend configuration. Optional.
- * @param   fEnum               Enumeration flags.
- */
-static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+ */
+static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
 {
     AssertPtrReturnVoid(pThis);
     /* pCfg is optional. */
 
-    PDMAUDIOBACKENDCFG Cfg;
-    RT_ZERO(Cfg);
-
-    Cfg.cbStreamOut = sizeof(DSOUNDSTREAM);
-    Cfg.cbStreamIn  = sizeof(DSOUNDSTREAM);
-
-    DSOUNDENUMCBCTX cbCtx = { pThis, fEnum, 0, 0 };
-
-    int rc = dsoundDevicesEnumerate(pThis, &cbCtx, fEnum);
+    LogFlowFuncEnter();
+
+    int rc = dsoundDevicesEnumerate(pThis, &pThis->DeviceEnum);
     if (RT_SUCCESS(rc))
     {
@@ -1778,22 +1842,9 @@
         }
 #endif
-        pThis->fEnabledOut = RT_BOOL(cbCtx.cDevOut);
-        pThis->fEnabledIn  = RT_BOOL(cbCtx.cDevIn);
-
-        RTStrPrintf2(Cfg.szName, sizeof(Cfg.szName), "DirectSound audio driver");
-
-        Cfg.cMaxStreamsIn  = UINT32_MAX;
-        Cfg.cMaxStreamsOut = UINT32_MAX;
-
-        if (pCfg)
-            memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
+        pThis->fEnabledIn  = RT_BOOL(DrvAudioHlpDeviceEnumGetDeviceCount(&pThis->DeviceEnum, PDMAUDIODIR_IN));
+        pThis->fEnabledOut = RT_BOOL(DrvAudioHlpDeviceEnumGetDeviceCount(&pThis->DeviceEnum, PDMAUDIODIR_OUT));
     }
 
     LogFlowFuncLeaveRC(rc);
-}
-
-static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
-{
-    dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
 }
 
@@ -2125,12 +2176,48 @@
 int drvHostDSoundGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
 {
+    RT_NOREF(pInterface);
     AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
     AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
 
+    RT_BZERO(pBackendCfg, sizeof(PPDMAUDIOBACKENDCFG));
+
+    pBackendCfg->cbStreamOut = sizeof(DSOUNDSTREAM);
+    pBackendCfg->cbStreamIn  = sizeof(DSOUNDSTREAM);
+
+    RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "DirectSound audio driver");
+
+    pBackendCfg->cMaxStreamsIn  = UINT32_MAX;
+    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * @interface_method_impl{PDMIHOSTAUDIO,pfnGetDevices}
+ */
+static DECLCALLBACK(int) drvHostDSoundGetDevices(PPDMIHOSTAUDIO pInterface, PPDMAUDIODEVICEENUM pDeviceEnum)
+{
+    AssertPtrReturn(pInterface,  VERR_INVALID_POINTER);
+    AssertPtrReturn(pDeviceEnum, VERR_INVALID_POINTER);
+
     PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
 
-    dsoundUpdateStatusInternalEx(pThis, pBackendCfg, 0 /* fEnum */);
-
-    return VINF_SUCCESS;
+    int rc = RTCritSectEnter(&pThis->CritSect);
+    if (RT_SUCCESS(rc))
+    {
+        rc = DrvAudioHlpDeviceEnumInit(pDeviceEnum);
+        if (RT_SUCCESS(rc))
+        {
+            rc = dsoundDevicesEnumerate(pThis, pDeviceEnum);
+            if (RT_FAILURE(rc))
+                DrvAudioHlpDeviceEnumFree(pDeviceEnum);
+        }
+
+        int rc2 = RTCritSectLeave(&pThis->CritSect);
+        AssertRC(rc2);
+    }
+
+    LogFlowFunc(("Returning %Rrc\n", rc));
+    return rc;
 }
 
@@ -2168,5 +2255,5 @@
         rc = VINF_SUCCESS;
 
-        dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
+        dsoundUpdateStatusInternal(pThis);
     }
     else
@@ -2504,4 +2591,6 @@
     }
 #endif
+
+    DrvAudioHlpDeviceEnumFree(&pThis->DeviceEnum);
 
     if (pThis->pDrvIns)
@@ -2544,4 +2633,7 @@
     pThis->IHostAudio.pfnStreamGetPending  = drvHostDSoundStreamGetPending;
 
+    /* This backend supports device enumeration. */
+    pThis->IHostAudio.pfnGetDevices  = drvHostDSoundGetDevices;
+
 #ifdef VBOX_WITH_AUDIO_CALLBACKS
     /* This backend supports host audio callbacks. */
@@ -2553,6 +2645,5 @@
      * Init the static parts.
      */
-    RTListInit(&pThis->lstDevInput);
-    RTListInit(&pThis->lstDevOutput);
+    DrvAudioHlpDeviceEnumInit(&pThis->DeviceEnum);
 
     pThis->fEnabledIn  = false;
