From 9745b2a590e5cf11b41ebc5c54dc53c3313cf2b8 Mon Sep 17 00:00:00 2001 From: Ross Bencina Date: Sun, 11 Sep 2016 17:25:48 +1000 Subject: [PATCH] wmme hotplug: Implement ScanDeviceInfos, CommitDeviceInfos, DisposeDeviceInfos by factoring out the relevant parts from Initialize(). Replace winMmeDeviceIds[] array with storing the native id for the corresponding device's PaWinMmeDeviceInfo struct. Switch to using PA/DirectSound behavior: if enumeration fails on one device, skip it and keep enumerating others. This patch made with reference to Jitsi [5ca6fed damencho], thank you. --- src/hostapi/wmme/pa_win_wmme.c | 508 +++++++++++++++++++++------------ 1 file changed, 320 insertions(+), 188 deletions(-) diff --git a/src/hostapi/wmme/pa_win_wmme.c b/src/hostapi/wmme/pa_win_wmme.c index 995b1c0..06dc234 100644 --- a/src/hostapi/wmme/pa_win_wmme.c +++ b/src/hostapi/wmme/pa_win_wmme.c @@ -287,6 +287,9 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount ); +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); @@ -434,13 +437,6 @@ typedef struct PaUtilAllocationGroup *allocations; int inputDeviceCount, outputDeviceCount; - - /** winMmeDeviceIds is an array of WinMme device ids. - fields in the range [0, inputDeviceCount) are input device ids, - and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output - device ids. - */ - UINT *winMmeDeviceIds; } PaWinMmeHostApiRepresentation; @@ -448,12 +444,21 @@ PaWinMmeHostApiRepresentation; typedef struct { PaDeviceInfo inheritedDeviceInfo; + UINT winWmmeDeviceId; /*<< Windows MME device id for this device */ DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */ char deviceInputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ char deviceOutputChannelCountIsKnown; /**<< if the system returns 0xFFFF then we don't really know the number of supported channels (1=>known, 0=>unknown)*/ } PaWinMmeDeviceInfo; +typedef struct +{ /* used for transferring device infos during scanning / rescanning */ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; + int inputDeviceCount, outputDeviceCount; +} +PaWinMmeScanDeviceInfosResults; /************************************************************************* * Returns recommended device ID. @@ -516,9 +521,11 @@ static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *ho */ static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device ) { - assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount ); + PaWinMmeDeviceInfo *winWmmeDeviceInfo; - return hostApi->winMmeDeviceIds[ device ]; + assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount ); + winWmmeDeviceInfo = (PaWinMmeDeviceInfo *)hostApi->inheritedHostApiRep.deviceInfos[device]; + return winWmmeDeviceInfo->winWmmeDeviceId; } @@ -794,6 +801,8 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId, QueryInputWaveFormatEx, deviceInfo->maxInputChannels ); + winMmeDeviceInfo->winWmmeDeviceId = winMmeInputDeviceId; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); *success = 1; @@ -931,6 +940,8 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId, QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels ); + winMmeDeviceInfo->winWmmeDeviceId = winMmeOutputDeviceId; + deviceInfo->connectionId = PaUtil_MakeDeviceConnectionId(); *success = 1; @@ -979,14 +990,9 @@ See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprec PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - int i; PaWinMmeHostApiRepresentation *winMmeHostApi; - int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount; - PaWinMmeDeviceInfo *deviceInfoArray; - int deviceInfoInitializationSucceeded; - PaTime defaultLowLatency, defaultHighLatency; - DWORD waveInPreferredDevice, waveOutPreferredDevice; - DWORD preferredDeviceStatusFlags; + void *scanResults = 0; + int deviceCount; winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) ); if( !winMmeHostApi ) @@ -1007,10 +1013,11 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.type = paMME; (*hostApi)->info.name = "MME"; - - /* initialise device counts and default devices under the assumption that - there are no devices. These values are incremented below if and when + /* Initialize device counts and default devices under the assumption that + there are no devices. These values are incremented if and when devices are successfully initialized. + + Note: the following are all updated by CommitDeviceInfos(). */ (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; @@ -1018,180 +1025,19 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd winMmeHostApi->inputDeviceCount = 0; winMmeHostApi->outputDeviceCount = 0; - /* Default device determination: - Here we query for the system preferred input and output devices using - DRVM_MAPPER_PREFERRED_GET; on error fall back to WAVE_MAPPER. Preferred - devices are stored in wave{In, Out}PreferredDevice. - - When enumerating devices, set PA default devices to the MME devices - with ids matching wave{In, Out}PreferredDevice. If such devices are not - encountered during enumeration, the first device enumerated for each of - {input, output} will be selected as the PA default device. - - Note that if PAWIN_WMME_NO_WAVE_MAPPER is defined, the WAVE_MAPPER - devices will never be enumerated, and will never be made a PA - default device, irrespective of the wave{In, Out}PreferredDevice values. - */ - preferredDeviceStatusFlags = 0; - waveInPreferredDevice = WAVE_MAPPER; - if( waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ) != MMSYSERR_NOERROR ) - waveInPreferredDevice = WAVE_MAPPER; - - preferredDeviceStatusFlags = 0; - waveOutPreferredDevice = WAVE_MAPPER; - if( waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ) != MMSYSERR_NOERROR ) - waveOutPreferredDevice = WAVE_MAPPER; - - maximumPossibleDeviceCount = 0; - -#ifdef PAWIN_WMME_NO_WAVE_MAPPER - #define PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_ 0 -#else - #define PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_ 1 -#endif - - inputDeviceCount = waveInGetNumDevs(); - if( inputDeviceCount > 0 ) - maximumPossibleDeviceCount += inputDeviceCount + PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_; - - outputDeviceCount = waveOutGetNumDevs(); - if( outputDeviceCount > 0 ) - maximumPossibleDeviceCount += outputDeviceCount + PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_; - - if( maximumPossibleDeviceCount > 0 ){ - - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); - if( !(*hostApi)->deviceInfos ) - { - result = paInsufficientMemory; - goto error; - } - - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); - if( !deviceInfoArray ) - { - result = paInsufficientMemory; - goto error; - } - - winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount ); - if( !winMmeHostApi->winMmeDeviceIds ) - { - result = paInsufficientMemory; - goto error; - } - - GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); - - if( inputDeviceCount > 0 ){ -#ifdef PAWIN_WMME_NO_WAVE_MAPPER - for( i = 0; i < inputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)i; -#else - /* -1 enumerates the WAVE_MAPPER */ - for( i = -1; i < inputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); -#endif - PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; - PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 3; - deviceInfo->hostApi = hostApiIndex; - - deviceInfo->maxInputChannels = 0; - wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; - deviceInfo->maxOutputChannels = 0; - wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; - - deviceInfo->defaultLowInputLatency = defaultLowLatency; - deviceInfo->defaultLowOutputLatency = defaultLowLatency; - deviceInfo->defaultHighInputLatency = defaultHighLatency; - deviceInfo->defaultHighOutputLatency = defaultHighLatency; - - result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, - winMmeDeviceId, &deviceInfoInitializationSucceeded ); - if( result != paNoError ) - goto error; - - if( deviceInfoInitializationSucceeded ){ - if( (*hostApi)->info.defaultInputDevice == paNoDevice ){ - /* if there is currently no default device, use the first one available */ - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - - }else if( winMmeDeviceId == waveInPreferredDevice ){ - /* set the default device to the system preferred device */ - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - } - - winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; - (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; - - winMmeHostApi->inputDeviceCount++; - (*hostApi)->info.deviceCount++; - } - } - } - - if( outputDeviceCount > 0 ){ -#ifdef PAWIN_WMME_NO_WAVE_MAPPER - for( i = 0; i < outputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)i; -#else - /* -1 enumerates the WAVE_MAPPER */ - for( i = -1; i < outputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); -#endif - PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; - PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 3; - deviceInfo->hostApi = hostApiIndex; - - deviceInfo->maxInputChannels = 0; - wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; - deviceInfo->maxOutputChannels = 0; - wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; - - deviceInfo->defaultLowInputLatency = defaultLowLatency; - deviceInfo->defaultLowOutputLatency = defaultLowLatency; - deviceInfo->defaultHighInputLatency = defaultHighLatency; - deviceInfo->defaultHighOutputLatency = defaultHighLatency; - - result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, - winMmeDeviceId, &deviceInfoInitializationSucceeded ); - if( result != paNoError ) - goto error; - - if( deviceInfoInitializationSucceeded ){ - if( (*hostApi)->info.defaultOutputDevice == paNoDevice ){ - /* if there is currently no default device, use the first one available */ - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - - }else if( winMmeDeviceId == waveOutPreferredDevice ){ - /* set the default device to the system preferred device */ - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - } - - winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; - (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; + result = ScanDeviceInfos( &winMmeHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount ); + if( result != paNoError ) + goto error; - winMmeHostApi->outputDeviceCount++; - (*hostApi)->info.deviceCount++; - } - } - } - } - - InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); + /* Ignore the result of CommitDeviceInfos(), it is a non-failing operation */ + CommitDeviceInfos( &winMmeHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount ); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; - (*hostApi)->ScanDeviceInfos = 0; - (*hostApi)->CommitDeviceInfos = 0; - (*hostApi)->DisposeDeviceInfos = 0; + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, @@ -1428,6 +1274,292 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, return paFormatIsSupported; } +/**************************************************************************************************************************/ + +static void FreeDeviceInfos( PaUtilAllocationGroup *allocations, PaDeviceInfo **deviceInfos ) +{ + if( deviceInfos ) + { + if( deviceInfos[0] ) + { + /* all device info structs are allocated in a block so we can destroy them like this */ + PaUtil_GroupFreeMemory( allocations, deviceInfos[0] ); + } + + PaUtil_GroupFreeMemory( allocations, deviceInfos ); + } +} + +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaError result = paNoError; + int i; + int inputDeviceCount, outputDeviceCount; + int maximumPossibleDeviceCount; + PaWinMmeDeviceInfo *deviceInfoArray; + int deviceInfoInitializationSucceeded; + PaTime defaultLowLatency, defaultHighLatency; + DWORD waveInPreferredDevice, waveOutPreferredDevice; + DWORD preferredDeviceStatusFlags; + PaWinMmeScanDeviceInfosResults *outArgument = 0; + + /* Check preconditions */ + if( scanResults == NULL || newDeviceCount == NULL ) + return paInternalError; + + /* initialize the out params */ + *scanResults = NULL; + *newDeviceCount = 0; + + /* Default device determination: + Here we query for the system preferred input and output devices using + DRVM_MAPPER_PREFERRED_GET; on error fall back to WAVE_MAPPER. Preferred + devices are stored in wave{In, Out}PreferredDevice. + + When enumerating devices, set PA default devices to the MME devices + with ids matching wave{In, Out}PreferredDevice. If such devices are not + encountered during enumeration, the first device enumerated for each of + {input, output} will be selected as the PA default device. + + Note that if PAWIN_WMME_NO_WAVE_MAPPER is defined, the WAVE_MAPPER + devices will never be enumerated, and will never be made a PA + default device, irrespective of the wave{In, Out}PreferredDevice values. + */ + preferredDeviceStatusFlags = 0; + waveInPreferredDevice = WAVE_MAPPER; + if( waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, + (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ) != MMSYSERR_NOERROR ) + waveInPreferredDevice = WAVE_MAPPER; + + preferredDeviceStatusFlags = 0; + waveOutPreferredDevice = WAVE_MAPPER; + if( waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, + (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ) != MMSYSERR_NOERROR ) + waveOutPreferredDevice = WAVE_MAPPER; + + maximumPossibleDeviceCount = 0; + +#ifdef PAWIN_WMME_NO_WAVE_MAPPER + #define PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_ 0 +#else + #define PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_ 1 +#endif + + inputDeviceCount = waveInGetNumDevs(); + if( inputDeviceCount > 0 ) + maximumPossibleDeviceCount += inputDeviceCount + PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_; + + outputDeviceCount = waveOutGetNumDevs(); + if( outputDeviceCount > 0 ) + maximumPossibleDeviceCount += outputDeviceCount + PAWIN_WMME_POSSIBLE_WAVE_MAPPER_COUNT_; + + if( maximumPossibleDeviceCount > 0 ) + { + /* Allocate the out param for all the info we need */ + outArgument = (PaWinMmeScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaWinMmeScanDeviceInfosResults) ); + if( !outArgument ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate array for pointers to PaDeviceInfo structs */ + outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); + if( !outArgument->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); + + if( inputDeviceCount > 0 ){ +#ifdef PAWIN_WMME_NO_WAVE_MAPPER + for( i = 0; i < inputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)i; +#else + /* -1 enumerates the WAVE_MAPPER */ + for( i = -1; i < inputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); +#endif + PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ *newDeviceCount ]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + deviceInfo->structVersion = 3; + deviceInfo->hostApi = hostApiIndex; + + deviceInfo->maxInputChannels = 0; + wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 0; + wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + if( result != paNoError ) + continue; /* ignore error results here and just skip the device. */ + /* N.B. Prior WMME versions failed scanning with an error here. */ + + if( deviceInfoInitializationSucceeded ){ + if( outArgument->defaultInputDevice == paNoDevice ) + { + /* if there is currently no default device, use the first one available */ + outArgument->defaultInputDevice = *newDeviceCount; + } + else if( winMmeDeviceId == waveInPreferredDevice ) + { + /* set the default device to the system preferred device */ + outArgument->defaultInputDevice = *newDeviceCount; + } + + outArgument->deviceInfos[ *newDeviceCount ] = deviceInfo; + outArgument->inputDeviceCount++; + (*newDeviceCount)++; + } + } + } + + if( outputDeviceCount > 0 ){ +#ifdef PAWIN_WMME_NO_WAVE_MAPPER + for( i = 0; i < outputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)i; +#else + /* -1 enumerates the WAVE_MAPPER */ + for( i = -1; i < outputDeviceCount; ++i ){ + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); +#endif + PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ *newDeviceCount ]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + deviceInfo->structVersion = 3; + deviceInfo->hostApi = hostApiIndex; + + deviceInfo->maxInputChannels = 0; + wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 0; + wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + if( result != paNoError ) + continue; /* ignore error results here and just skip the device. */ + /* N.B. Prior WMME versions failed scanning with an error here. */ + + if( deviceInfoInitializationSucceeded ){ + if( outArgument->defaultOutputDevice == paNoDevice ) + { + /* if there is currently no default device, use the first one available */ + outArgument->defaultOutputDevice = *newDeviceCount; + + } + else if( winMmeDeviceId == waveOutPreferredDevice ) + { + /* set the default device to the system preferred device */ + outArgument->defaultOutputDevice = *newDeviceCount; + } + + outArgument->deviceInfos[ *newDeviceCount ] = deviceInfo; + outArgument->outputDeviceCount++; + (*newDeviceCount)++; + } + } + } + } + + InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); + + *scanResults = outArgument; + return result; + +error: + if( outArgument ) + { + FreeDeviceInfos( winMmeHostApi->allocations, outArgument->deviceInfos ); + } + return result; +} + +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaError result = paNoError; + + (void)index; /* unused parameter */ + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + FreeDeviceInfos( winMmeHostApi->allocations, hostApi->deviceInfos ); + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaWinMmeScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinMmeScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + hostApi->info.deviceCount = deviceCount; + + winMmeHostApi->inputDeviceCount = scanDeviceInfosResults->inputDeviceCount; + winMmeHostApi->outputDeviceCount = scanDeviceInfosResults->outputDeviceCount; + } + + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults ); + } + + return result; +} + +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + + (void)deviceCount; /* unused parameter */ + + if( scanResults != NULL ) + { + PaWinMmeScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinMmeScanDeviceInfosResults * ) scanResults; + + if( scanDeviceInfosResults->deviceInfos ) + { + FreeDeviceInfos( winMmeHostApi->allocations, hostApi->deviceInfos ); + } + + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; +} + +/**************************************************************************************************************************/ static unsigned long ComputeHostBufferCountForFixedBufferSizeFrames( unsigned long suggestedLatencyFrames, -- 2.43.0