From 6d6be2630448ebbd0ded596a6be1ca69a9f326c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= <remi@remlab.net>
Date: Tue, 15 May 2012 22:27:22 +0300
Subject: [PATCH] wasapi: fix COM initialization and deinitialization

---
 modules/audio_output/wasapi.c | 55 +++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/modules/audio_output/wasapi.c b/modules/audio_output/wasapi.c
index e5b3c72c4169..80bcff6afb92 100644
--- a/modules/audio_output/wasapi.c
+++ b/modules/audio_output/wasapi.c
@@ -50,7 +50,8 @@ struct aout_sys_t
 {
     IAudioClient *client;
     IAudioRenderClient *render;
-    UINT32 frames;
+    UINT32 frames; /**< Total buffer size (frames) */
+    HANDLE done; /**< Semaphore for MTA thread */
 };
 
 static void Play(audio_output_t *aout, block_t *block)
@@ -58,6 +59,8 @@ static void Play(audio_output_t *aout, block_t *block)
     aout_sys_t *sys = aout->sys;
     HRESULT hr;
 
+    CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
     while (block->i_nb_samples > 0)
     {
         UINT32 frames;
@@ -100,6 +103,7 @@ static void Play(audio_output_t *aout, block_t *block)
         Sleep(AOUT_MIN_PREPARE_TIME / 1000);
     }
 
+    CoUninitialize();
     block_Release(block);
 }
 
@@ -111,9 +115,11 @@ static void Pause(audio_output_t *aout, bool paused, mtime_t date)
     if (!paused)
         return;
 
+    CoInitializeEx(NULL, COINIT_MULTITHREADED);
     hr = IAudioClient_Stop(sys->client);
     if (FAILED(hr))
         msg_Warn(aout, "cannot stop stream (error 0x%lx)", hr);
+    CoUninitialize();
     (void) date;
 }
 
@@ -125,10 +131,12 @@ static void Flush(audio_output_t *aout, bool wait)
     if (wait)
         return; /* Not drain implemented */
 
+    CoInitializeEx(NULL, COINIT_MULTITHREADED);
     IAudioClient_Stop(sys->client);
     hr = IAudioClient_Reset(sys->client);
     if (FAILED(hr))
         msg_Warn(aout, "cannot reset stream (error 0x%lx)", hr);
+    CoUninitialize();
 }
 
 /*static int VolumeSet(audio_output_t *aout, float vol, bool mute)
@@ -211,6 +219,20 @@ static int vlc_FromWave(const WAVEFORMATEX *restrict wf,
     return 0;
 }
 
+/* Dummy thread to keep COM MTA alive */
+static void MTAThread(void *data)
+{
+    HANDLE done = data;
+    HRESULT hr;
+
+    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    if (unlikely(FAILED(hr)))
+        abort();
+    WaitForSingleObject(done, INFINITE);
+    CoUninitialize();
+    CloseHandle(done);
+}
+
 static int Open(vlc_object_t *obj)
 {
     audio_output_t *aout = (audio_output_t *)obj;
@@ -219,10 +241,9 @@ static int Open(vlc_object_t *obj)
     aout_sys_t *sys = malloc(sizeof (*sys));
     if (unlikely(sys == NULL))
         return VLC_ENOMEM;
-
-    aout->sys = sys;
     sys->client = NULL;
     sys->render = NULL;
+    sys->done = NULL;
 
     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
     if (FAILED(hr))
@@ -322,15 +343,30 @@ static int Open(vlc_object_t *obj)
         goto error;
     }
 
+    sys->done = CreateSemaphore(NULL, 0, 1, NULL);
+    if (unlikely(sys->done == NULL))
+        goto error;
+    /* Note: thread handle released by CRT, ignore it. */
+    if (_beginthread(MTAThread, 0, sys->done) == (uintptr_t)-1)
+        goto error;
+
     aout->format = format;
     aout->sys = sys;
     aout->pf_play = Play;
     aout->pf_pause = Pause;
     aout->pf_flush = Flush;
     aout_VolumeNoneInit (aout);
+    CoUninitialize();
     return VLC_SUCCESS;
 error:
-    Close(obj);
+    if (sys->done != NULL)
+        CloseHandle(sys->done);
+    if (sys->render != NULL)
+        IAudioRenderClient_Release(sys->render);
+    if (sys->client != NULL)
+        IAudioClient_Release(sys->client);
+    CoUninitialize();
+    free(sys);
     return VLC_EGENERIC;
 }
 
@@ -339,10 +375,11 @@ static void Close (vlc_object_t *obj)
     audio_output_t *aout = (audio_output_t *)obj;
     aout_sys_t *sys = aout->sys;
 
-    if (sys->render != NULL)
-        IAudioRenderClient_Release(sys->render);
-    if (sys->client != NULL)
-        IAudioClient_Release(sys->client);
-    /* FIXME: CoUninitialize(); */
+    CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    IAudioRenderClient_Release(sys->render);
+    IAudioClient_Release(sys->client);
+    CoUninitialize();
+
+    ReleaseSemaphore(sys->done, 1, NULL); /* MTA thread will exit */
     free(sys);
 }
-- 
GitLab