DirectSound and CoreAudio draft version of Pa_RefreshDevices() from David Stuart (Sourced from Ross private email June 30, 2010). This is an early version before we implemented 2-phase commit/rollback for device list changes. Pushed so that Evan can look at the CoreAudio code.

This commit is contained in:
Ross Bencina 2016-09-01 14:22:02 +10:00
commit 7fcdfbf5df
5 changed files with 280 additions and 0 deletions

View file

@ -397,6 +397,16 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void );
*/ */
PaDeviceIndex Pa_GetDefaultOutputDevice( 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 /** 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 for syncronisation. The type is used for the outTime argument to the

View 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 ) const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
{ {
int hostSpecificDeviceIndex; int hostSpecificDeviceIndex;

View file

@ -218,6 +218,8 @@ typedef struct PaUtilHostApiRepresentation {
const PaStreamParameters *inputParameters, const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters, const PaStreamParameters *outputParameters,
double sampleRate ); double sampleRate );
PaError (*RefreshDevices)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
} PaUtilHostApiRepresentation; } PaUtilHostApiRepresentation;

View file

@ -242,6 +242,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaStreamFlags streamFlags, PaStreamFlags streamFlags,
PaStreamCallback *streamCallback, PaStreamCallback *streamCallback,
void *userData ); void *userData );
static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
static PaError CloseStream( PaStream* stream ); static PaError CloseStream( PaStream* stream );
static PaError StartStream( PaStream *stream ); static PaError StartStream( PaStream *stream );
static PaError StopStream( PaStream *stream ); static PaError StopStream( PaStream *stream );
@ -636,6 +637,7 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn
(*hostApi)->Terminate = Terminate; (*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream; (*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported; (*hostApi)->IsFormatSupported = IsFormatSupported;
(*hostApi)->RefreshDevices = RefreshDevices;
PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface, PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
CloseStream, StartStream, CloseStream, StartStream,
@ -1669,6 +1671,83 @@ error:
return result; 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 ) PaTime GetStreamTime( PaStream *s )
{ {
/* FIXME: I am not at all sure this timing info stuff is right. /* FIXME: I am not at all sure this timing info stuff is right.

View file

@ -167,6 +167,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
const PaStreamParameters *inputParameters, const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters, const PaStreamParameters *outputParameters,
double sampleRate ); double sampleRate );
static PaError RefreshDevices( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index );
static PaError CloseStream( PaStream* stream ); static PaError CloseStream( PaStream* stream );
static PaError StartStream( PaStream *stream ); static PaError StartStream( PaStream *stream );
static PaError StopStream( PaStream *stream ); static PaError StopStream( PaStream *stream );
@ -1188,6 +1189,7 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde
(*hostApi)->Terminate = Terminate; (*hostApi)->Terminate = Terminate;
(*hostApi)->OpenStream = OpenStream; (*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported; (*hostApi)->IsFormatSupported = IsFormatSupported;
(*hostApi)->RefreshDevices = RefreshDevices;
PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream, PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
StopStream, AbortStream, IsStreamStopped, IsStreamActive, StopStream, AbortStream, IsStreamStopped, IsStreamActive,
@ -1392,6 +1394,145 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
return paFormatIsSupported; 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 ** Determine minimum number of buffers required for this host based