Browse Source

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.
Ryan C. Gordon 1 year ago
parent
commit
89408a9705
1 changed files with 42 additions and 22 deletions
  1. 42 22
      src/audio/wasapi/SDL_wasapi.c

+ 42 - 22
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;
+}
 
+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)
+{
     if (!device || !device->hidden) {
-        return 0;
+        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_Stop(device->hidden->client);
-        IAudioClient_Release(device->hidden->client);
+        IAudioClient *client = device->hidden->client;
         device->hidden->client = NULL;
+        WASAPI_ProxyToManagementThread(mgmtthrtask_StopAndReleaseClient, 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);
+        IAudioRenderClient *render = device->hidden->render;
         device->hidden->render = NULL;
+        WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseRenderClient, 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);
+        IAudioCaptureClient *capture = device->hidden->capture;
         device->hidden->capture = NULL;
+        WASAPI_ProxyToManagementThread(mgmtthrtask_ReleaseCaptureClient, capture, NULL);
     }
 
     if (device->hidden->waveformat) {
-        CoTaskMemFree(device->hidden->waveformat);
+        void *ptr = device->hidden->waveformat;
         device->hidden->waveformat = NULL;
+        WASAPI_ProxyToManagementThread(mgmtthrtask_CoTaskMemFree, ptr, NULL);
     }
 
     if (device->hidden->activation_handler) {
-        WASAPI_PlatformDeleteActivationHandler(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) {
-        CloseHandle(device->hidden->event);
+        HANDLE event = device->hidden->event;
         device->hidden->event = NULL;
+        WASAPI_ProxyToManagementThread(mgmtthrtask_CloseHandle, (void *) event, NULL);
     }
-
-    return 0;
-}
-
-static void ResetWasapiDevice(SDL_AudioDevice *device)
-{
-    int rc;
-    WASAPI_ProxyToManagementThread(mgmtthrtask_ResetWasapiDevice, device, &rc);
 }
 
 static int mgmtthrtask_ActivateDevice(void *userdata)