From 7f9854b9b2177dea32eb5d2f4434609ea5dd58d5 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Tue, 25 Sep 2018 01:45:12 -0400 Subject: [PATCH] WinRT: Wait until audio device activation is complete and PrepDevice during OpenAudio --- src/audio/wasapi/SDL_wasapi.c | 6 +++ src/audio/wasapi/SDL_wasapi_win32.c | 6 --- src/audio/wasapi/SDL_wasapi_winrt.cpp | 63 +++++++++++++++------------ 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index b7c8dda5d1a44..f517539657262 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -725,6 +725,12 @@ WASAPI_ThreadDeinit(_THIS) WASAPI_PlatformThreadDeinit(this); } +void +WASAPI_BeginLoopIteration(_THIS) +{ + /* no-op. */ +} + static void WASAPI_Deinitialize(void) { diff --git a/src/audio/wasapi/SDL_wasapi_win32.c b/src/audio/wasapi/SDL_wasapi_win32.c index 8b55582c30c3d..731dcffb7fa9e 100644 --- a/src/audio/wasapi/SDL_wasapi_win32.c +++ b/src/audio/wasapi/SDL_wasapi_win32.c @@ -405,12 +405,6 @@ WASAPI_PlatformDeleteActivationHandler(void *handler) SDL_assert(!"This function should have only been called on WinRT."); } -void -WASAPI_BeginLoopIteration(_THIS) -{ - /* no-op. */ -} - #endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/wasapi/SDL_wasapi_winrt.cpp b/src/audio/wasapi/SDL_wasapi_winrt.cpp index 309ec6a78886e..2ca09de863f4a 100644 --- a/src/audio/wasapi/SDL_wasapi_winrt.cpp +++ b/src/audio/wasapi/SDL_wasapi_winrt.cpp @@ -185,20 +185,9 @@ struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< Cla HRESULT SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async) { - HRESULT result = S_OK; - IUnknown *iunknown = nullptr; - const HRESULT ret = async->GetActivateResult(&result, &iunknown); - - if (SUCCEEDED(ret) && SUCCEEDED(result)) { - iunknown->QueryInterface(IID_PPV_ARGS(&device->hidden->client)); - if (device->hidden->client) { - // Just set a flag, since we're probably in a different thread. We'll pick it up and init everything on our own thread to prevent races. - SDL_AtomicSet(&device->hidden->just_activated, 1); - } - } - + // Just set a flag, since we're probably in a different thread. We'll pick it up and init everything on our own thread to prevent races. + SDL_AtomicSet(&device->hidden->just_activated, 1); WASAPI_UnrefDevice(device); - return S_OK; } @@ -236,27 +225,47 @@ WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery) IActivateAudioInterfaceAsyncOperation *async = nullptr; const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async); - if (async != nullptr) { - async->Release(); - } - - if (FAILED(ret)) { + if (FAILED(ret) || async == nullptr) { + if (async != nullptr) { + async->Release(); + } handler.Get()->Release(); WASAPI_UnrefDevice(_this); return WIN_SetErrorFromHRESULT("WASAPI can't activate requested audio endpoint", ret); } - return 0; -} + /* Spin until the async operation is complete. + * If we don't PrepDevice before leaving this function, the bug list gets LONG: + * - device.spec is not filled with the correct information + * - The 'obtained' spec will be wrong for ALLOW_CHANGE properties + * - SDL_AudioStreams will/will not be allocated at the right time + * - SDL_assert(device->callbackspec.size == device->spec.size) will fail + * - When the assert is ignored, skipping or a buffer overflow will occur + */ + while (!SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) { + SDL_Delay(1); + } -void -WASAPI_BeginLoopIteration(_THIS) -{ - if (SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) { - if (WASAPI_PrepDevice(_this, SDL_TRUE) == -1) { - SDL_OpenedAudioDeviceDisconnected(_this); - } + HRESULT activateRes = S_OK; + IUnknown *iunknown = nullptr; + const HRESULT getActivateRes = async->GetActivateResult(&activateRes, &iunknown); + async->Release(); + if (FAILED(getActivateRes)) { + return WIN_SetErrorFromHRESULT("Failed to get WASAPI activate result", getActivateRes); + } else if (FAILED(activateRes)) { + return WIN_SetErrorFromHRESULT("Failed to activate WASAPI device", activateRes); + } + + iunknown->QueryInterface(IID_PPV_ARGS(&_this->hidden->client)); + if (!_this->hidden->client) { + return SDL_SetError("Failed to query WASAPI client interface"); + } + + if (WASAPI_PrepDevice(_this, isrecovery) == -1) { + return -1; } + + return 0; } void