From 89408a97056722fe8f0a836ea6809793c86212f1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 9 Nov 2023 20:27:58 -0500 Subject: [PATCH] wasapi: ResetWasapiDevice no longer blocks on management thread. It just proxies all its necessary releases and frees to these without blocking, and sets the appropriate fields to NULL so they can be used again immediately, regardless of when the old stuff actually gets released. --- src/audio/wasapi/SDL_wasapi.c | 104 ++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index c7d251d6eb..934ac4e6e6 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -294,6 +294,14 @@ static SDL_bool WasapiFailed(SDL_AudioDevice *device, const HRESULT err) return SDL_TRUE; } +static int mgmtthrtask_StopAndReleaseClient(void *userdata) +{ + IAudioClient *client = (IAudioClient *) userdata; + IAudioClient_Stop(client); + IAudioClient_Release(client); + return 0; +} + static int mgmtthrtask_ReleaseCaptureClient(void *userdata) { IAudioCaptureClient_Release((IAudioCaptureClient *)userdata); @@ -306,56 +314,68 @@ static int mgmtthrtask_ReleaseRenderClient(void *userdata) return 0; } -static int mgmtthrtask_ResetWasapiDevice(void *userdata) +static int mgmtthrtask_CoTaskMemFree(void *userdata) { - SDL_AudioDevice *device = (SDL_AudioDevice *)userdata; + CoTaskMemFree(userdata); + return 0; +} - if (!device || !device->hidden) { - return 0; - } - - if (device->hidden->client) { - IAudioClient_Stop(device->hidden->client); - IAudioClient_Release(device->hidden->client); - device->hidden->client = NULL; - } - - if (device->hidden->render) { - // this is silly, but this will block indefinitely if you call it from SDLMMNotificationClient_OnDefaultDeviceChanged, so - // proxy this to the management thread to be released later. - WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseRenderClient, device->hidden->render, NULL); - device->hidden->render = NULL; - } - - if (device->hidden->capture) { - // this is silly, but this will block indefinitely if you call it from SDLMMNotificationClient_OnDefaultDeviceChanged, so - // proxy this to the management thread to be released later. - WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseCaptureClient, device->hidden->capture, NULL); - device->hidden->capture = NULL; - } - - if (device->hidden->waveformat) { - CoTaskMemFree(device->hidden->waveformat); - device->hidden->waveformat = NULL; - } - - if (device->hidden->activation_handler) { - WASAPI_PlatformDeleteActivationHandler(device->hidden->activation_handler); - device->hidden->activation_handler = NULL; - } - - if (device->hidden->event) { - CloseHandle(device->hidden->event); - device->hidden->event = NULL; - } +static int mgmtthrtask_PlatformDeleteActivationHandler(void *userdata) +{ + WASAPI_PlatformDeleteActivationHandler(userdata); + return 0; +} +static int mgmtthrtask_CloseHandle(void *userdata) +{ + CloseHandle((HANDLE) userdata); return 0; } static void ResetWasapiDevice(SDL_AudioDevice *device) { - int rc; - WASAPI_ProxyToManagementThread(mgmtthrtask_ResetWasapiDevice, device, &rc); + if (!device || !device->hidden) { + return; + } + + // just queue up all the tasks in the management thread and don't block. + // We don't care when any of these actually get free'd. + + if (device->hidden->client) { + IAudioClient *client = device->hidden->client; + device->hidden->client = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_StopAndReleaseClient, client, NULL); + } + + if (device->hidden->render) { + IAudioRenderClient *render = device->hidden->render; + device->hidden->render = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseRenderClient, render, NULL); + } + + if (device->hidden->capture) { + IAudioCaptureClient *capture = device->hidden->capture; + device->hidden->capture = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseCaptureClient, capture, NULL); + } + + if (device->hidden->waveformat) { + void *ptr = device->hidden->waveformat; + device->hidden->waveformat = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_CoTaskMemFree, ptr, NULL); + } + + if (device->hidden->activation_handler) { + void *activation_handler = device->hidden->activation_handler; + device->hidden->activation_handler = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_PlatformDeleteActivationHandler, activation_handler, NULL); + } + + if (device->hidden->event) { + HANDLE event = device->hidden->event; + device->hidden->event = NULL; + WASAPI_ProxyToManagementThread(mgmtthrtask_CloseHandle, (void *) event, NULL); + } } static int mgmtthrtask_ActivateDevice(void *userdata)