[vlc-commits] wasapi: respect IAudioClock and IAudioRenderClient threading rules

Rémi Denis-Courmont git at videolan.org
Wed May 16 18:46:44 CEST 2012


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed May 16 19:44:53 2012 +0300| [752bdd983a683dfc1c7478e1a53636952575a5df] | committer: Rémi Denis-Courmont

wasapi: respect IAudioClock and IAudioRenderClient threading rules

These interfaces must be released on the interface that created them.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=752bdd983a683dfc1c7478e1a53636952575a5df
---

 modules/audio_output/wasapi.c |   71 +++++++++++++++++++++++++----------------
 1 file changed, 43 insertions(+), 28 deletions(-)

diff --git a/modules/audio_output/wasapi.c b/modules/audio_output/wasapi.c
index 887f6b6..b4fcf66 100644
--- a/modules/audio_output/wasapi.c
+++ b/modules/audio_output/wasapi.c
@@ -52,7 +52,8 @@ struct aout_sys_t
     IAudioRenderClient *render;
     IAudioClock *clock;
     UINT32 frames; /**< Total buffer size (frames) */
-    HANDLE done; /**< Semaphore for MTA thread */
+    HANDLE ready; /**< Semaphore from MTA thread */
+    HANDLE done; /**< Semaphore to MTA thread */
 };
 
 static void Play(audio_output_t *aout, block_t *block)
@@ -233,18 +234,40 @@ static int vlc_FromWave(const WAVEFORMATEX *restrict wf,
     return 0;
 }
 
-/* Dummy thread to keep COM MTA alive */
+/* Dummy thread to create and release COM interfaces when needed. */
 static void MTAThread(void *data)
 {
-    HANDLE done = data;
+    audio_output_t *aout = data;
+    aout_sys_t *sys = aout->sys;
     HRESULT hr;
 
     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
     if (unlikely(FAILED(hr)))
         abort();
-    WaitForSingleObject(done, INFINITE);
+
+    hr = IAudioClient_GetService(sys->client, &IID_IAudioRenderClient,
+                                 (void **)&sys->render);
+    if (FAILED(hr))
+    {
+        msg_Err(aout, "cannot get audio render service (error 0x%lx)", hr);
+        goto fail;
+    }
+
+    hr = IAudioClient_GetService(sys->client, &IID_IAudioClock,
+                                 (void **)&sys->clock);
+    if (FAILED(hr))
+        msg_Warn(aout, "cannot get audio clock (error 0x%lx)", hr);
+
+    /* do nothing until the audio session terminates */
+    ReleaseSemaphore(sys->ready, 1, NULL);
+    WaitForSingleObject(sys->done, INFINITE);
+
+    if (sys->clock != NULL)
+        IAudioClock_Release(sys->clock);
+    IAudioRenderClient_Release(sys->render);
+fail:
     CoUninitialize();
-    CloseHandle(done);
+    ReleaseSemaphore(sys->ready, 1, NULL);
 }
 
 static int Open(vlc_object_t *obj)
@@ -263,7 +286,9 @@ static int Open(vlc_object_t *obj)
     sys->client = NULL;
     sys->render = NULL;
     sys->clock = NULL;
+    sys->ready = NULL;
     sys->done = NULL;
+    aout->sys = sys;
 
     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
     if (FAILED(hr))
@@ -355,28 +380,19 @@ static int Open(vlc_object_t *obj)
         goto error;
     }
 
-    hr = IAudioClient_GetService(sys->client, &IID_IAudioRenderClient,
-                                 (void **)&sys->render);
-    if (FAILED(hr))
-    {
-        msg_Err(aout, "cannot get audio render service (error 0x%lx)", hr);
-        goto error;
-    }
-
-    hr = IAudioClient_GetService(sys->client, &IID_IAudioClock,
-                                 (void **)&sys->clock);
-    if (FAILED(hr))
-        msg_Warn(aout, "cannot get audio clock (error 0x%lx)", hr);
-
+    sys->ready = CreateSemaphore(NULL, 0, 1, NULL);
     sys->done = CreateSemaphore(NULL, 0, 1, NULL);
-    if (unlikely(sys->done == NULL))
+    if (unlikely(sys->ready == NULL || sys->done == NULL))
         goto error;
     /* Note: thread handle released by CRT, ignore it. */
-    if (_beginthread(MTAThread, 0, sys->done) == (uintptr_t)-1)
+    if (_beginthread(MTAThread, 0, aout) == (uintptr_t)-1)
+        goto error;
+
+    WaitForSingleObject(sys->ready, INFINITE);
+    if (sys->render == NULL)
         goto error;
 
     aout->format = format;
-    aout->sys = sys;
     aout->pf_play = Play;
     aout->pf_pause = Pause;
     aout->pf_flush = Flush;
@@ -386,10 +402,8 @@ static int Open(vlc_object_t *obj)
 error:
     if (sys->done != NULL)
         CloseHandle(sys->done);
-    if (sys->clock != NULL)
-        IAudioClock_Release(sys->clock);
-    if (sys->render != NULL)
-        IAudioRenderClient_Release(sys->render);
+    if (sys->ready != NULL)
+        CloseHandle(sys->done);
     if (sys->client != NULL)
         IAudioClient_Release(sys->client);
     CoUninitialize();
@@ -403,12 +417,13 @@ static void Close (vlc_object_t *obj)
     aout_sys_t *sys = aout->sys;
 
     CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    ReleaseSemaphore(sys->done, 1, NULL); /* tell MTA thread to finish */
+    WaitForSingleObject(sys->ready, INFINITE); /* wait for that ^ */
     IAudioClient_Stop(sys->client); /* should not be needed */
-    IAudioClock_Release(sys->clock);
-    IAudioRenderClient_Release(sys->render);
     IAudioClient_Release(sys->client);
     CoUninitialize();
 
-    ReleaseSemaphore(sys->done, 1, NULL); /* MTA thread will exit */
+    CloseHandle(sys->done);
+    CloseHandle(sys->ready);
     free(sys);
 }



More information about the vlc-commits mailing list