From d99940b26eb6a48d1a069b3195a50d06badabb46 Mon Sep 17 00:00:00 2001 From: dmitrykos Date: Sat, 9 Mar 2019 12:43:14 +0200 Subject: [PATCH] wasapi: set IAudioClient2+ properties before GetClosestFormat() in order to avoid failing with unsupported format error if PaWasapiStreamCategory is other than default, for example eAudioCategorySpeech --- src/hostapi/wasapi/pa_win_wasapi.c | 97 ++++++++++++++++-------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index 1dc888e..ffc4b11 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -1571,13 +1571,54 @@ error: #endif // ------------------------------------------------------------------------------------------ -static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) +static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, const PaWasapiStreamInfo *streamInfo, + IAudioClient **client) { + HRESULT hr; + #ifndef PA_WINRT - return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client); + if (FAILED(hr = IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client))) + return hr; #else - return ActivateAudioInterface_WINRT(deviceInfo->flow, GetAudioClientIID(), (void **)client); + if (FAILED(hr = ActivateAudioInterface_WINRT(deviceInfo->flow, GetAudioClientIID(), (void **)client))) + return hr; +#endif + + // Set audio client options (applicable only to IAudioClient2+): options may affect the audio format + // support by IAudioClient implementation and therefore we should set them before GetClosestFormat() + // in order to correctly match the requested format +#ifdef __IAudioClient2_INTERFACE_DEFINED__ + if ((streamInfo != NULL) && (GetAudioClientVersion() >= 2)) + { + pa_AudioClientProperties audioProps = { 0 }; + audioProps.cbSize = sizeof(pa_AudioClientProperties); + audioProps.bIsOffload = FALSE; + audioProps.eCategory = (AUDIO_STREAM_CATEGORY)streamInfo->streamCategory; + switch (streamInfo->streamOption) + { + case eStreamOptionRaw: + if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW; + break; + case eStreamOptionMatchFormat: + if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT; + break; + } + + if (FAILED(hr = IAudioClient2_SetClientProperties((IAudioClient2 *)(*client), (AudioClientProperties *)&audioProps))) + { + PRINT(("WASAPI: IAudioClient2_SetClientProperties(IsOffload = %d, Category = %d, Options = %d) failed\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); + LogHostError(hr); + } + else + { + PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); + } + } #endif + + return S_OK; } // ------------------------------------------------------------------------------------------ @@ -1873,7 +1914,7 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA #endif // Create temp Audio Client instance to query additional details - hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[i], NULL, &tmpClient); // 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); @@ -2801,9 +2842,9 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo; if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive)) - shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], &tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], inputStreamInfo, &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2826,9 +2867,9 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo; if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive)) - shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], &tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], outputStreamInfo, &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2972,7 +3013,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu } // Get the audio client - if (FAILED(hr = ActivateAudioInterface(pInfo, &audioClient))) + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) { (*pa_error) = paInsufficientMemory; LogHostError(hr); @@ -3122,38 +3163,6 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu } } - // Set Raw mode (applicable only to IAudioClient2) -#ifdef __IAudioClient2_INTERFACE_DEFINED__ - if (GetAudioClientVersion() >= 2) - { - pa_AudioClientProperties audioProps = { 0 }; - audioProps.cbSize = sizeof(pa_AudioClientProperties); - audioProps.bIsOffload = FALSE; - audioProps.eCategory = (AUDIO_STREAM_CATEGORY)pSub->params.wasapi_params.streamCategory; - switch (pSub->params.wasapi_params.streamOption) - { - case eStreamOptionRaw: - if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2) - audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW; - break; - case eStreamOptionMatchFormat: - if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) - audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT; - break; - } - - if (FAILED(hr = IAudioClient2_SetClientProperties((IAudioClient2 *)audioClient, (AudioClientProperties *)&audioProps))) - { - PRINT(("WASAPI: IAudioClient2_SetClientProperties(IsOffload = %d, Category = %d, Options = %d) failed\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); - LogHostError(hr); - } - else - { - PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); - } - } -#endif - // Set device scheduling period (always 0 in Shared mode according Microsoft docs) _CalculatePeriodicity(pSub, output, &eventPeriodicity); @@ -3201,7 +3210,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - if (FAILED(hr = ActivateAudioInterface(pInfo, &audioClient))) + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) { (*pa_error) = paInsufficientMemory; LogHostError(hr); @@ -3241,7 +3250,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - if (FAILED(hr = ActivateAudioInterface(pInfo, &audioClient))) + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) { (*pa_error) = paInsufficientMemory; LogHostError(hr); @@ -3274,7 +3283,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - if (FAILED(hr = ActivateAudioInterface(pInfo, &audioClient))) + if (FAILED(hr = ActivateAudioInterface(pInfo, &pSub->params.wasapi_params, &audioClient))) { (*pa_error) = paInsufficientMemory; LogHostError(hr); -- 2.43.0