diff options
Diffstat (limited to 'Source/3rdParty/SDL2/src/audio/wasapi')
3 files changed, 96 insertions, 41 deletions
diff --git a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c index b7c8dda..f517539 100644 --- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi.c +++ b/Source/3rdParty/SDL2/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/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c index 8b55582..9d7c159 100644 --- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c +++ b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_win32.c @@ -351,10 +351,42 @@ WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery) } +typedef struct +{ + LPWSTR devid; + char *devname; +} EndpointItem; + +static int sort_endpoints(const void *_a, const void *_b) +{ + LPWSTR a = ((const EndpointItem *) _a)->devid; + LPWSTR b = ((const EndpointItem *) _b)->devid; + if (!a && b) { + return -1; + } else if (a && !b) { + return 1; + } + + while (SDL_TRUE) { + if (*a < *b) { + return -1; + } else if (*a > *b) { + return 1; + } else if (*a == 0) { + break; + } + a++; + b++; + } + + return 0; +} + static void WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture) { IMMDeviceCollection *collection = NULL; + EndpointItem *items; UINT i, total; /* Note that WASAPI separates "adapter devices" from "audio endpoint devices" @@ -369,22 +401,36 @@ WASAPI_EnumerateEndpointsForFlow(const SDL_bool iscapture) return; } + items = (EndpointItem *) SDL_calloc(total, sizeof (EndpointItem)); + if (!items) { + return; /* oh well. */ + } + for (i = 0; i < total; i++) { + EndpointItem *item = items + i; IMMDevice *device = NULL; if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &device))) { - LPWSTR devid = NULL; - if (SUCCEEDED(IMMDevice_GetId(device, &devid))) { - char *devname = GetWasapiDeviceName(device); - if (devname) { - WASAPI_AddDevice(iscapture, devname, devid); - SDL_free(devname); - } - CoTaskMemFree(devid); + if (SUCCEEDED(IMMDevice_GetId(device, &item->devid))) { + item->devname = GetWasapiDeviceName(device); } IMMDevice_Release(device); } } + /* sort the list of devices by their guid so list is consistent between runs */ + SDL_qsort(items, total, sizeof (*items), sort_endpoints); + + /* Send the sorted list on to the SDL's higher level. */ + for (i = 0; i < total; i++) { + EndpointItem *item = items + i; + if ((item->devid) && (item->devname)) { + WASAPI_AddDevice(iscapture, item->devname, item->devid); + } + SDL_free(item->devname); + CoTaskMemFree(item->devid); + } + + SDL_free(items); IMMDeviceCollection_Release(collection); } @@ -405,12 +451,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/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp b/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp index 309ec6a..2ca09de 100644 --- a/Source/3rdParty/SDL2/src/audio/wasapi/SDL_wasapi_winrt.cpp +++ b/Source/3rdParty/SDL2/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 |