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:
parent
6421f964d7
commit
7fcdfbf5df
5 changed files with 280 additions and 0 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue