WinRT: Wait until audio device activation is complete and PrepDevice during OpenAudio

This commit is contained in:
Ethan Lee 2018-09-25 01:45:12 -04:00
parent aa9683bb6f
commit 7f9854b9b2
3 changed files with 43 additions and 34 deletions

View File

@ -725,6 +725,12 @@ WASAPI_ThreadDeinit(_THIS)
WASAPI_PlatformThreadDeinit(this); WASAPI_PlatformThreadDeinit(this);
} }
void
WASAPI_BeginLoopIteration(_THIS)
{
/* no-op. */
}
static void static void
WASAPI_Deinitialize(void) WASAPI_Deinitialize(void)
{ {

View File

@ -405,12 +405,6 @@ WASAPI_PlatformDeleteActivationHandler(void *handler)
SDL_assert(!"This function should have only been called on WinRT."); SDL_assert(!"This function should have only been called on WinRT.");
} }
void
WASAPI_BeginLoopIteration(_THIS)
{
/* no-op. */
}
#endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */ #endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */

View File

@ -185,20 +185,9 @@ struct SDL_WasapiActivationHandler : public RuntimeClass< RuntimeClassFlags< Cla
HRESULT HRESULT
SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async) SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
{ {
HRESULT result = S_OK; // 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.
IUnknown *iunknown = nullptr; SDL_AtomicSet(&device->hidden->just_activated, 1);
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);
}
}
WASAPI_UnrefDevice(device); WASAPI_UnrefDevice(device);
return S_OK; return S_OK;
} }
@ -236,27 +225,47 @@ WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
IActivateAudioInterfaceAsyncOperation *async = nullptr; IActivateAudioInterfaceAsyncOperation *async = nullptr;
const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async); const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient), nullptr, handler.Get(), &async);
if (async != nullptr) { if (FAILED(ret) || async == nullptr) {
async->Release(); if (async != nullptr) {
} async->Release();
}
if (FAILED(ret)) {
handler.Get()->Release(); handler.Get()->Release();
WASAPI_UnrefDevice(_this); WASAPI_UnrefDevice(_this);
return WIN_SetErrorFromHRESULT("WASAPI can't activate requested audio endpoint", ret); 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
void * - The 'obtained' spec will be wrong for ALLOW_CHANGE properties
WASAPI_BeginLoopIteration(_THIS) * - SDL_AudioStreams will/will not be allocated at the right time
{ * - SDL_assert(device->callbackspec.size == device->spec.size) will fail
if (SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) { * - When the assert is ignored, skipping or a buffer overflow will occur
if (WASAPI_PrepDevice(_this, SDL_TRUE) == -1) { */
SDL_OpenedAudioDeviceDisconnected(_this); while (!SDL_AtomicCAS(&_this->hidden->just_activated, 1, 0)) {
} SDL_Delay(1);
} }
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 void