]> Repos - portaudio/commitdiff
DirectSound and CoreAudio draft version of Pa_RefreshDevices() from David Stuart... david_stuart_pa_refresh_devices_20100630
authorRoss Bencina <rossb@audiomulch.com>
Thu, 1 Sep 2016 04:22:02 +0000 (14:22 +1000)
committerRoss Bencina <rossb@audiomulch.com>
Thu, 1 Sep 2016 04:22:02 +0000 (14:22 +1000)
include/portaudio.h
src/common/pa_front.c
src/common/pa_hostapi.h
src/hostapi/coreaudio/pa_mac_core.c
src/hostapi/dsound/pa_win_ds.c

index b55eb0ee3d6ae6e6c679f61cb41026eac6839548..1e81e6ac9a34e90f2f3b9e50061d6040bf364a61 100644 (file)
@@ -397,6 +397,16 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void );
 */
 PaDeviceIndex Pa_GetDefaultOutputDevice( void );
 
+/** Normally the list of devices is frozen after initialization, until the
+ next time port audio is re-initialized. This provides API stability but
+ has the side effect that hot-pluggable devices such as USB audio headsets
+ might not be up-to-date while the program is running. This method is used
+ to refresh the list of devices within port audio without closing open
+ streams.
+
+ @return an error code which indicates whether the device refresh was successful.
+ */
+PaError Pa_RefreshDevices( void );
 
 /** The type used to represent monotonic time in seconds that can be used
  for syncronisation. The type is used for the outTime argument to the
index 22a7fda31389cefe1d66b6d2782ac8d99a6d4b2d..c323be7a6e8386528cd967538679e2e57829c23e 100644 (file)
@@ -700,6 +700,54 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void )
 }
 
 
+PaError Pa_RefreshDevices( void )
+{
+    int i, baseDeviceIndex;
+    PaError result = paNoError;
+
+    PA_LOGAPI_ENTER( "Pa_RefreshDeviceList" );
+    if( !PA_IS_INITIALISED_ )
+        return paNotInitialized;
+
+    baseDeviceIndex = 0;
+    deviceCount_ = 0;
+
+    for( i=0; i < hostApisCount_; ++i )
+    {
+        PaUtilHostApiRepresentation *hostApi = hostApis_[i];
+        if( hostApi->RefreshDevices == NULL )
+        {
+            /* RefreshDevices not yet implemented for this backend. Just
+               assume that the baseDeviceIndex and the deviceCount_ are
+               incremented according to the values in the info */
+            baseDeviceIndex += hostApi->info.deviceCount;
+            deviceCount_ += hostApi->info.deviceCount;
+            continue;
+        }
+
+        PA_DEBUG(( "refreshing device list for host api %d.\n",i));
+
+        if(( result = hostApi->RefreshDevices( hostApi, i )) != paNoError )
+           return result;
+
+        assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
+        assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
+
+        hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
+
+        if( hostApi->info.defaultInputDevice != paNoDevice )
+            hostApi->info.defaultInputDevice += baseDeviceIndex;
+
+        if( hostApi->info.defaultOutputDevice != paNoDevice )
+            hostApi->info.defaultOutputDevice += baseDeviceIndex;
+
+        baseDeviceIndex += hostApi->info.deviceCount;
+        deviceCount_ += hostApi->info.deviceCount;
+    }
+
+    return result;
+}
+
 const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
 {
     int hostSpecificDeviceIndex;
index 7746747827f3fa089ebc07e65434db92e4be545f..eee4def3f4de29f75cc37a1b9ff69ca4df8921eb 100644 (file)
@@ -218,6 +218,8 @@ typedef struct PaUtilHostApiRepresentation {
                                   const PaStreamParameters *inputParameters,
                                   const PaStreamParameters *outputParameters,
                                   double sampleRate );
+
+    PaError (*RefreshDevices)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 } PaUtilHostApiRepresentation;
 
 
index bd509731cbf1d23b9f1abdbc4f8c07fc1142eaca..18df1d4ae3f0d61d6f5eaa916b23fbb1c2101f81 100644 (file)
@@ -242,6 +242,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
                            PaStreamFlags streamFlags,
                            PaStreamCallback *streamCallback,
                            void *userData );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 static PaError CloseStream( PaStream* stream );
 static PaError StartStream( PaStream *stream );
 static PaError StopStream( PaStream *stream );
@@ -636,6 +637,7 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
     (*hostApi)->Terminate = Terminate;
     (*hostApi)->OpenStream = OpenStream;
     (*hostApi)->IsFormatSupported = IsFormatSupported;
+    (*hostApi)->RefreshDevices = RefreshDevices;
 
     PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
                                       CloseStream, StartStream,
@@ -1669,6 +1671,83 @@ error:
     return result;
 }
 
+PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+    PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
+    PaError result = paNoError;
+    PaDeviceInfo *deviceInfoArray;
+    int i;
+
+    VVDBUG(("RefreshDevices(): hostApiIndex=%d\n", hostApiIndex));
+       
+    auhalHostApi->devIds = NULL;
+    auhalHostApi->devCount = 0;
+
+    /* get the info we need about the devices */
+    result = gatherDeviceInfo( auhalHostApi );
+    if( result != paNoError )
+       goto error;
+
+    hostApi->info.defaultInputDevice = paNoDevice;
+    hostApi->info.defaultOutputDevice = paNoDevice;
+    hostApi->info.deviceCount = 0;  
+
+    /* If the device infos already exist, free the old memory */
+    if( hostApi->deviceInfos != NULL )
+    {
+        PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos );
+        hostApi->deviceInfos = NULL;
+    }
+
+    if( auhalHostApi->devCount > 0 )
+    {
+        hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+                auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
+        if( !hostApi->deviceInfos )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        /* allocate all device info structs in a contiguous block */
+        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+                auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount );
+        if( !deviceInfoArray )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        for( i=0; i < auhalHostApi->devCount; ++i )
+        {
+            int err;
+            err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
+                                      auhalHostApi->devIds[i],
+                                      hostApiIndex );
+            if (err == paNoError)
+            { /* copy some info and set the defaults */
+                hostApi->deviceInfos[hostApi->info.deviceCount] = &deviceInfoArray[i];
+                if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn)
+                    hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
+                if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut)
+                    hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
+                hostApi->info.deviceCount++;
+            }
+            else
+            { /* there was an error. we need to shift the devices down, so we ignore this one */
+                int j;
+                auhalHostApi->devCount--;
+                for( j=i; j<auhalHostApi->devCount; ++j )
+                   auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1];
+                i--;
+            }
+        }
+    }
+
+error:
+    return result;
+}
+
 PaTime GetStreamTime( PaStream *s )
 {
    /* FIXME: I am not at all sure this timing info stuff is right.
index 5625810ad17cb18d2970f00c49651a48088da7e3..31e69ca3439e65c1beb64aae9bfde0224c3aaede 100644 (file)
@@ -167,6 +167,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
                                   const PaStreamParameters *inputParameters,
                                   const PaStreamParameters *outputParameters,
                                   double sampleRate );
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
 static PaError CloseStream( PaStream* stream );
 static PaError StartStream( PaStream *stream );
 static PaError StopStream( PaStream *stream );
@@ -1188,6 +1189,7 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde
     (*hostApi)->Terminate = Terminate;
     (*hostApi)->OpenStream = OpenStream;
     (*hostApi)->IsFormatSupported = IsFormatSupported;
+    (*hostApi)->RefreshDevices = RefreshDevices;
 
     PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
@@ -1392,6 +1394,145 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
     return paFormatIsSupported;
 }
 
+/***********************************************************************************/
+static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex )
+{
+    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+    DSDeviceNamesAndGUIDs deviceNamesAndGUIDs;
+    PaWinDsDeviceInfo *deviceInfoArray;
+    int i = 0, deviceCount = 0;
+    char comWasInitialized = winDsHostApi->comWasInitialized;
+    PaError result = paNoError;
+
+    if( !comWasInitialized )
+       return paInternalError;
+
+    /* initialise guid vectors so they can be safely deleted on error */
+    deviceNamesAndGUIDs.winDsHostApi = NULL;
+    deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL;
+    deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL;
+
+    hostApi->info.deviceCount = 0;
+    hostApi->info.defaultInputDevice = paNoDevice;
+    hostApi->info.defaultOutputDevice = paNoDevice;
+
+    /* DSound - enumerate devices to count them and to gather their GUIDs */
+    result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations );
+    if( result != paNoError )
+        goto error;
+
+    result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations );
+    if( result != paNoError )
+        goto error;
+
+    paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+    if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError )
+    {
+        result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError;
+        goto error;
+    }
+
+    if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError )
+    {
+        result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError;
+        goto error;
+    }
+
+    /* Free any old memory which might be in the device info */
+    if( hostApi->deviceInfos )
+    {
+        PaUtil_GroupFreeMemory( winDsHostApi->allocations, hostApi->deviceInfos );
+        hostApi->deviceInfos = NULL;
+    }
+
+    deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count;
+
+#ifdef PAWIN_USE_WDMKS_DEVICE_INFO
+    if( deviceCount > 0 )
+    {
+        deviceNamesAndGUIDs.winDsHostApi = winDsHostApi;
+        FindDevicePnpInterfaces( &deviceNamesAndGUIDs );
+    }
+#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */
+
+    if( deviceCount > 0 )
+    {
+        /* allocate array for pointers to PaDeviceInfo structs */
+        hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+                winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+        if( !hostApi->deviceInfos )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        /* allocate all PaDeviceInfo structs in a contiguous block */
+        deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
+                winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
+        if( !deviceInfoArray )
+        {
+            result = paInsufficientMemory;
+            goto error;
+        }
+
+        for( i=0; i < deviceCount; ++i )
+        {
+            PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo;
+            deviceInfo->structVersion = 2;
+            deviceInfo->hostApi = hostApiIndex;
+            deviceInfo->name = 0;
+            hostApi->deviceInfos[i] = deviceInfo;
+        }
+
+        for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i )
+        {
+            result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID,
+                    deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface );
+            if( result != paNoError )
+                goto error;
+        }
+
+        for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i )
+        {
+            result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID,
+                    deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface );
+            if( result != paNoError )
+                goto error;
+        }
+    }    
+
+    result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    if( result != paNoError )
+        goto error;
+
+    result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+    if( result != paNoError )
+        goto error;
+
+    return result;
+
+error:
+    if( winDsHostApi )
+    {
+        if( winDsHostApi->allocations )
+        {
+            PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+            PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+        }
+    }
+
+    TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs );
+    TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs );
+
+
+    return result;
+}
 
 /*************************************************************************
 ** Determine minimum number of buffers required for this host based