]> Repos - portaudio/commitdiff
wasapi: new WASAPI specific API PaWasapi_UpdateDeviceList() which allows to update...
authordmitrykos <dmitrykos@neutroncode.com>
Mon, 2 Apr 2018 18:50:16 +0000 (21:50 +0300)
committerdmitrykos <dmitrykos@neutroncode.com>
Mon, 2 Apr 2018 18:50:16 +0000 (21:50 +0300)
This new implementation overcomes current limitation of Pa_GetDeviceCount() API which gives constant device count by making WASAPI device list constant (32 devices by default) where 32 device slots can either be filled with a real device info or be empty for a future device changes.

Constant device list size can be altered by PA_WASAPI_MAX_CONST_DEVICE_COUNT define during a compile time. If PA_WASAPI_MAX_CONST_DEVICE_COUNT is set to 0 then PaWasapi_UpdateDeviceList() will be unavailable as well as dynamic device list update functionality.

This implementation also detects the audio device format change if user alters it via Windows Audio Controller GUI.

This implementation also makes WASAPI backend ready for a future implementation of device list updates via PortAudio public API. See internal PaError UpdateDeviceList().

include/pa_win_wasapi.h
src/hostapi/wasapi/pa_win_wasapi.c

index 1d86896caef9efbfc83a1cb7d8eb3901adb26d53..3d35379019a097a135c52b6c01d1d0c2751ce7c1 100644 (file)
@@ -291,6 +291,18 @@ typedef struct PaWasapiStreamInfo
 PaWasapiStreamInfo;
 
 
+/** Update device list. 
+    This function will be available if PA_WASAPI_MAX_CONST_DEVICE_COUNT is defined with maximum 
+    constant WASAPI device count (defined by default with value 32). 
+    If PA_WASAPI_MAX_CONST_DEVICE_COUNT is set to 0 during compile time the implementation will not
+    define PaWasapi_UpdateDeviceList() and thus updating device list can only be possible by calling
+    Pa_Terminate() and then Pa_Initialize().
+
+ @return Error code indicating success or failure.
+*/
+PaError PaWasapi_UpdateDeviceList();
+
+
 /** Returns default sound format for device. Format is represented by PaWinWaveFormat or 
     WAVEFORMATEXTENSIBLE structure.
 
@@ -356,6 +368,7 @@ PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput
 /** Get number of jacks associated with a WASAPI device.  Use this method to determine if
     there are any jacks associated with the provided WASAPI device.  Not all audio devices
     will support this capability.  This is valid for both input and output devices.
+
  @param  nDevice  device index.
  @param  jcount   Number of jacks is returned in this variable
  @return Error code indicating success or failure
@@ -369,6 +382,7 @@ PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount);
     number of jacks associated with device.  If jcount is greater than zero, then
     each jack from 0 to jcount can be queried with this function to get the jack
     description.
+
  @param  nDevice  device index.
  @param  jindex   Which jack to return information
  @param  KSJACK_DESCRIPTION This structure filled in on success.
index 090ccd4b9eca14de3a6333db217f55c0b7276435..d1129025d70bdc01266110c394033c8afdeaaee5 100644 (file)
 #include <process.h>
 #include <assert.h>
 
+// Max device count (if defined) causes max constant device count in the device list that
+// enables PaWasapi_UpdateDeviceList() API and makes it possible to update WASAPI list dynamically
+#ifndef PA_WASAPI_MAX_CONST_DEVICE_COUNT
+       #define PA_WASAPI_MAX_CONST_DEVICE_COUNT 32
+#endif
+
 // WinRT
 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
        #define PA_WINRT
@@ -432,11 +438,6 @@ typedef struct
 
     PaWinUtilComInitializationResult comInitializationResult;
 
-    //in case we later need the synch
-#ifndef PA_WINRT
-    IMMDeviceEnumerator *enumerator;
-#endif
-
     //this is the REAL number of devices, whether they are usefull to PA or not!
     UINT32 deviceCount;
 
@@ -1423,62 +1424,28 @@ static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn,
 #endif
 
 // ------------------------------------------------------------------------------------------
-PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostApiIndex hostApiIndex)
 {
+       PaUtilHostApiRepresentation *hostApi = (PaUtilHostApiRepresentation *)paWasapi;
     PaError result = paNoError;
-    PaWasapiHostApiRepresentation *paWasapi;
     PaDeviceInfo *deviceInfoArray;
     HRESULT hr = S_OK;
        UINT i;
 #ifndef PA_WINRT
     IMMDeviceCollection* pEndPoints = NULL;
+       IMMDeviceEnumerator *pEnumerator = NULL;
 #else
        WAVEFORMATEX *mixFormat;
 #endif
        IAudioClient *tmpClient;
 
-#ifndef PA_WINRT
-    if (!SetupAVRT())
-       {
-        PRINT(("WASAPI: No AVRT! (not VISTA?)"));
-        return paNoError;
-    }
-#endif
-
-    paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );
-    if (paWasapi == NULL)
-       {
-        result = paInsufficientMemory;
-        goto error;
-    }
-       
-    memset( paWasapi, 0, sizeof(PaWasapiHostApiRepresentation) ); /* ensure all fields are zeroed. especially paWasapi->allocations */
-
-    result = PaWinUtil_CoInitialize( paWASAPI, &paWasapi->comInitializationResult );
-    if( result != paNoError )
-    {
-        goto error;
-    }
-
-    paWasapi->allocations = PaUtil_CreateAllocationGroup();
-    if (paWasapi->allocations == NULL)
-       {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    *hostApi                             = &paWasapi->inheritedHostApiRep;
-    (*hostApi)->info.structVersion              = 1;
-    (*hostApi)->info.type                               = paWASAPI;
-    (*hostApi)->info.name                               = "Windows WASAPI";
-    (*hostApi)->info.deviceCount                = 0;
-    (*hostApi)->info.defaultInputDevice         = paNoDevice;
-    (*hostApi)->info.defaultOutputDevice = paNoDevice;
+       // Make sure device list empty
+       if ((paWasapi->deviceCount != 0) || (hostApi->info.deviceCount != 0))
+               return paInternalError;
 
 #ifndef PA_WINRT
-    paWasapi->enumerator = NULL;
     hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
-             &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator);
+             &pa_IID_IMMDeviceEnumerator, (void **)&pEnumerator);
     
        // We need to set the result to a value otherwise we will return paNoError
        // [IF_FAILED_JUMP(hResult, error);]
@@ -1488,7 +1455,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
     {
         {
             IMMDevice *defaultRenderer = NULL;
-            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eRender, eMultimedia, &defaultRenderer);
+            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eMultimedia, &defaultRenderer);
             if (hr != S_OK)
                        {
                                if (hr != E_NOTFOUND) {
@@ -1512,7 +1479,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
 
         {
             IMMDevice *defaultCapturer = NULL;
-            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eCapture, eMultimedia, &defaultCapturer);
+            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eCapture, eMultimedia, &defaultCapturer);
             if (hr != S_OK)
                        {
                                if (hr != E_NOTFOUND) {
@@ -1535,7 +1502,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
         }
     }
 
-    hr = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
+    hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
        // We need to set the result to a value otherwise we will return paNoError
        // [IF_FAILED_JUMP(hResult, error);]
        IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
@@ -1569,9 +1536,15 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
 
     if (paWasapi->deviceCount > 0)
     {
-        (*hostApi)->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(
-                paWasapi->allocations, sizeof(PaDeviceInfo *) * paWasapi->deviceCount);
-        if ((*hostApi)->deviceInfos == NULL)
+               UINT32 deviceCount = paWasapi->deviceCount;
+       #if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
+               if (deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT)
+                       deviceCount = PA_WASAPI_MAX_CONST_DEVICE_COUNT;
+       #endif
+
+        hostApi->deviceInfos = (PaDeviceInfo **)PaUtil_GroupAllocateMemory(
+                paWasapi->allocations, sizeof(PaDeviceInfo *) * deviceCount);
+        if (hostApi->deviceInfos == NULL)
                {
             result = paInsufficientMemory;
             goto error;
@@ -1579,12 +1552,13 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
 
         /* allocate all device info structs in a contiguous block */
         deviceInfoArray = (PaDeviceInfo *)PaUtil_GroupAllocateMemory(
-                paWasapi->allocations, sizeof(PaDeviceInfo) * paWasapi->deviceCount);
+                paWasapi->allocations, sizeof(PaDeviceInfo) * deviceCount);
         if (deviceInfoArray == NULL)
                {
             result = paInsufficientMemory;
             goto error;
         }
+               memset(deviceInfoArray, 0, sizeof(PaDeviceInfo) * deviceCount);
 
         for (i = 0; i < paWasapi->deviceCount; ++i)
                {
@@ -1613,11 +1587,11 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
 
                 if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCapturer) == 0)
                                {// we found the default input!
-                    (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
+                    hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
                 }
                 if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultRenderer) == 0)
                                {// we found the default output!
-                    (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+                    hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
                 }
             }
 
@@ -1640,25 +1614,21 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
 
                 // "Friendly" Name
                 {
-                                       char *deviceName;
                     PROPVARIANT value;
                     PropVariantInit(&value);
                     hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);
                                        // We need to set the result to a value otherwise we will return paNoError
                                        // [IF_FAILED_JUMP(hResult, error);]
                                        IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
-                    deviceInfo->name = NULL;
-                    deviceName = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
-                    if (deviceName == NULL)
+                    if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL)
                                        {
                         result = paInsufficientMemory;
                         goto error;
                     }
                                        if (value.pwszVal)
-                                               WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN - 1, 0, 0);
+                                               WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), (char *)deviceInfo->name, MAX_STR_LEN - 1, 0, 0);
                                        else
-                                               _snprintf(deviceName, MAX_STR_LEN - 1, "baddev%d", i);
-                    deviceInfo->name = deviceName;
+                                               _snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "baddev%d", i);
                     PropVariantClear(&value);
                                        PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name));
                 }
@@ -1751,9 +1721,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
                                {
                                        // Default device
                                        if (i == 0)
-                                               (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+                                               hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
                                        else
-                                               (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
+                                               hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
 
                                        // State
                                        paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE;
@@ -1766,8 +1736,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
                                        paWasapi->devInfo[i].formFactor = UnknownFormFactor;
 
                                        // Name
-                    deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);
-                    if (deviceInfo->name == NULL)
+                    if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1)) == NULL)
                                        {
                                                SAFE_RELEASE(tmpClient);
                         result = paInsufficientMemory;
@@ -1821,35 +1790,39 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
                                 break;
             }
 
-            (*hostApi)->deviceInfos[i] = deviceInfo;
-            ++(*hostApi)->info.deviceCount;
+            hostApi->deviceInfos[i] = deviceInfo;
+            ++hostApi->info.deviceCount;
         }
-    }
 
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+       #if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
+               if (hostApi->info.deviceCount < PA_WASAPI_MAX_CONST_DEVICE_COUNT)
+               {               
+                       for (i = hostApi->info.deviceCount; i < PA_WASAPI_MAX_CONST_DEVICE_COUNT; ++i)
+                       {
+                               PaDeviceInfo *deviceInfo  = &deviceInfoArray[i];
+                               deviceInfo->structVersion = 2;
+                               deviceInfo->hostApi       = hostApiIndex;
 
+                if ((deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, 1)) == NULL)
+                               {
+                    result = paInsufficientMemory;
+                    goto error;
+                }
+                               ((char *)deviceInfo->name)[0] = 0;
 
-       // findout if platform workaround is required
-       paWasapi->useWOW64Workaround = UseWOW64Workaround();
+                               hostApi->deviceInfos[i] = deviceInfo;
+                               ++hostApi->info.deviceCount;
+                       }
+               }
+       #endif
+    }
 
 #ifndef PA_WINRT
     SAFE_RELEASE(pEndPoints);
+       SAFE_RELEASE(pEnumerator);
 #endif
 
-       PRINT(("WASAPI: initialized ok\n"));
+       PRINT(("WASAPI: device list created ok\n"));
 
     return paNoError;
 
@@ -1859,44 +1832,119 @@ error:
 
 #ifndef PA_WINRT
     SAFE_RELEASE(pEndPoints);
+       SAFE_RELEASE(pEnumerator);
 #endif
-
-       Terminate((PaUtilHostApiRepresentation *)paWasapi);
-
+       
        // Safety if error was not set so that we do not think initialize was a success
-       if (result == paNoError) {
+       if (result == paNoError)
                result = paInternalError;
-       }
 
     return result;
 }
 
 // ------------------------------------------------------------------------------------------
-static void Terminate( PaUtilHostApiRepresentation *hostApi )
+PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
 {
-       UINT i;
-    PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi;
-       if (paWasapi == NULL)
-               return;
+    PaError result = paInternalError;
+    PaWasapiHostApiRepresentation *paWasapi;
 
-       // Release IMMDeviceEnumerator
 #ifndef PA_WINRT
-    SAFE_RELEASE(paWasapi->enumerator);
+    if (!SetupAVRT())
+       {
+        PRINT(("WASAPI: No AVRT! (not VISTA?)"));
+        return paNoError;
+    }
 #endif
 
+    paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory(sizeof(PaWasapiHostApiRepresentation));
+    if (paWasapi == NULL)
+       {
+        result = paInsufficientMemory;
+        goto error;
+    }  
+    memset(paWasapi, 0, sizeof(PaWasapiHostApiRepresentation)); /* ensure all fields are zeroed. especially paWasapi->allocations */
+
+    result = PaWinUtil_CoInitialize(paWASAPI, &paWasapi->comInitializationResult);
+    if (result != paNoError)
+        goto error;
+
+    paWasapi->allocations = PaUtil_CreateAllocationGroup();
+    if (paWasapi->allocations == NULL)
+       {
+        result = paInsufficientMemory;
+        goto error;
+    }
+
+       // Fill basic interface info
+    *hostApi                             = &paWasapi->inheritedHostApiRep;
+    (*hostApi)->info.structVersion              = 1;
+    (*hostApi)->info.type                               = paWASAPI;
+    (*hostApi)->info.name                               = "Windows WASAPI";
+    (*hostApi)->info.deviceCount                = 0;
+    (*hostApi)->info.defaultInputDevice         = paNoDevice;
+    (*hostApi)->info.defaultOutputDevice = paNoDevice;
+       (*hostApi)->Terminate                = Terminate;
+    (*hostApi)->OpenStream               = OpenStream;
+    (*hostApi)->IsFormatSupported        = IsFormatSupported;
+
+       // Fill the device list
+       if ((result = CreateDeviceList(paWasapi, hostApiIndex)) != paNoError)
+               goto error;
+
+       // Detect if platform workaround is required
+       paWasapi->useWOW64Workaround = UseWOW64Workaround();
+
+    PaUtil_InitializeStreamInterface( &paWasapi->callbackStreamInterface, CloseStream, StartStream,
+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+                                      GetStreamTime, GetStreamCpuLoad,
+                                      PaUtil_DummyRead, PaUtil_DummyWrite,
+                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
+
+    PaUtil_InitializeStreamInterface( &paWasapi->blockingStreamInterface, CloseStream, StartStream,
+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+       PRINT(("WASAPI: initialized ok\n"));
+
+    return paNoError;
+
+error:
+
+       PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result)));
+
+       Terminate((PaUtilHostApiRepresentation *)paWasapi);
+
+    return result;
+}
+
+// ------------------------------------------------------------------------------------------
+static void ReleaseWasapiDeviceInfoList( PaWasapiHostApiRepresentation *paWasapi )
+{
+       UINT32 i;
+
        // Release device info bound objects and device info itself
     for (i = 0; i < paWasapi->deviceCount; ++i)
        {
-        PaWasapiDeviceInfo *info = &paWasapi->devInfo[i];
        #ifndef PA_WINRT
-        SAFE_RELEASE(info->device);
-       #else
-               (void)info;
+        SAFE_RELEASE(paWasapi->devInfo[i].device);
        #endif
     }
     PaUtil_FreeMemory(paWasapi->devInfo);
 
-    if (paWasapi->allocations)
+       paWasapi->deviceCount = 0;
+}
+
+// ------------------------------------------------------------------------------------------
+static void Terminate( PaUtilHostApiRepresentation *hostApi )
+{
+    PaWasapiHostApiRepresentation *paWasapi = (PaWasapiHostApiRepresentation*)hostApi;
+       if (paWasapi == NULL)
+               return;
+
+       ReleaseWasapiDeviceInfoList(paWasapi);
+
+    if (paWasapi->allocations != NULL)
        {
         PaUtil_FreeAllAllocations(paWasapi->allocations);
         PaUtil_DestroyAllocationGroup(paWasapi->allocations);
@@ -1926,6 +1974,52 @@ static PaWasapiHostApiRepresentation *_GetHostApi(PaError *_error)
        return (PaWasapiHostApiRepresentation *)pApi;
 }
 
+// ------------------------------------------------------------------------------------------
+static PaError UpdateDeviceList()
+{
+       int i;
+       PaError ret;
+       PaWasapiHostApiRepresentation *paWasapi;
+       PaUtilHostApiRepresentation *hostApi;
+
+       // Get API
+       hostApi = (PaUtilHostApiRepresentation *)(paWasapi = _GetHostApi(&ret));
+       if (paWasapi == NULL)
+               return ret;
+
+       // Release WASAPI internal device info list
+       ReleaseWasapiDeviceInfoList(paWasapi);
+
+       // Release external device info list
+       if (hostApi->deviceInfos != NULL)
+       {
+               for (i = 0; i < hostApi->info.deviceCount; ++i)
+               {
+                       PaUtil_GroupFreeMemory(paWasapi->allocations, (void *)hostApi->deviceInfos[i]->name);
+               }
+               PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos[0]);
+               PaUtil_GroupFreeMemory(paWasapi->allocations, hostApi->deviceInfos);
+
+               hostApi->info.deviceCount = 0;
+               hostApi->info.defaultInputDevice = paNoDevice;
+               hostApi->info.defaultOutputDevice = paNoDevice;
+       }
+
+       // Fill possibly updated device list
+       if ((ret = CreateDeviceList(paWasapi, Pa_HostApiTypeIdToHostApiIndex(paWASAPI))) != paNoError)
+               return ret;
+
+       return paNoError;
+}
+
+// ------------------------------------------------------------------------------------------
+#if defined(PA_WASAPI_MAX_CONST_DEVICE_COUNT) && (PA_WASAPI_MAX_CONST_DEVICE_COUNT > 0)
+PaError PaWasapi_UpdateDeviceList()
+{
+       return UpdateDeviceList();
+}
+#endif
+
 // ------------------------------------------------------------------------------------------
 int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
 {