summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi.c
diff options
context:
space:
mode:
authorKevin Mitchell <kevmitch@gmail.com>2015-03-28 17:12:48 -0700
committerKevin Mitchell <kevmitch@gmail.com>2015-04-04 16:31:14 -0700
commit642f84f9227607f0c64bf35ec5896cb80804f64f (patch)
tree6c21e7b59235686b5284ec2ad47858eb6b6ce5bf /audio/out/ao_wasapi.c
parentfe60cff03bbdc0790f96365d6cf3ab8116785bb0 (diff)
downloadmpv-642f84f9227607f0c64bf35ec5896cb80804f64f.tar.bz2
mpv-642f84f9227607f0c64bf35ec5896cb80804f64f.tar.xz
ao/wasapi: use atomic state variable instead of different events
Unfortunately, because we have proxy objects (pAudioVolumeProxy, pEndpointVolumeProxy, pSessionControlProxy) it looks like we still have to use MsgWaitForMultipleObjects and watch for and dispatch pending messages: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680112%28v=vs.85%29.aspx
Diffstat (limited to 'audio/out/ao_wasapi.c')
-rw-r--r--audio/out/ao_wasapi.c115
1 files changed, 61 insertions, 54 deletions
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index c86e7311d7..3c0bab3231 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -126,9 +126,12 @@ static void thread_resume(struct ao *ao)
/* Fill the buffer before starting, but only if there is no audio queued to play. */
/* This prevents overfilling the buffer, which leads to problems in exclusive mode */
- if (padding < (UINT32)state->bufferFrameCount)
+ if (padding < (UINT32) state->bufferFrameCount)
thread_feed(ao);
+ // start feeding next wakeup if something else hasn't been requested
+ int expected = WASAPI_THREAD_RESUME;
+ atomic_compare_exchange_strong(&state->thread_state, &expected, WASAPI_THREAD_FEED);
hr = IAudioClient_Start(state->pAudioClient);
if (hr != S_OK)
MP_ERR(state, "IAudioClient_Start returned %s\n", mp_HRESULT_to_str(hr));
@@ -152,46 +155,55 @@ static void thread_reset(struct ao *ao)
MP_ERR(state, "IAudioClient_Reset returned: %s\n", mp_HRESULT_to_str(hr));
atomic_store(&state->sample_count, 0);
+ // start feeding next wakeup if something else hasn't been requested
+ int expected = WASAPI_THREAD_RESET;
+ atomic_compare_exchange_strong(&state->thread_state, &expected, WASAPI_THREAD_FEED);
return;
}
-static DWORD __stdcall ThreadLoop(void *lpParameter)
+static DWORD __stdcall AudioThread(void *lpParameter)
{
struct ao *ao = lpParameter;
struct wasapi_state *state = ao->priv;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
state->init_ret = wasapi_thread_init(ao);
- SetEvent(state->init_done);
+ SetEvent(state->hInitDone);
if (state->init_ret != S_OK)
goto exit_label;
- DWORD waitstatus;
- HANDLE playcontrol[] =
- {state->hUninit, state->hFeed, state->hReset, state->hResume, NULL};
MP_DBG(ao, "Entering dispatch loop\n");
while (true) { /* watch events */
- waitstatus = MsgWaitForMultipleObjects(4, playcontrol, FALSE, INFINITE,
- QS_POSTMESSAGE | QS_SENDMESSAGE);
- switch (waitstatus) {
- case WAIT_OBJECT_0: /*shutdown*/
- MP_DBG(ao, "Thread shutdown\n");
- goto exit_label;
- case (WAIT_OBJECT_0 + 1): /* feed */
- thread_feed(ao);
- break;
- case (WAIT_OBJECT_0 + 2): /* reset */
- thread_reset(ao);
- break;
- case (WAIT_OBJECT_0 + 3): /* resume */
- thread_resume(ao);
+ HANDLE events[] = {state->hWake};
+ switch (MsgWaitForMultipleObjects(MP_ARRAY_SIZE(events), events, FALSE, INFINITE,
+ QS_POSTMESSAGE | QS_SENDMESSAGE)) {
+ /* AudioThread wakeup */
+ case WAIT_OBJECT_0:
+ switch (atomic_load(&state->thread_state)) {
+ case WASAPI_THREAD_FEED:
+ thread_feed(ao);
+ break;
+ case WASAPI_THREAD_RESET:
+ thread_reset(ao);
+ break;
+ case WASAPI_THREAD_RESUME:
+ thread_reset(ao);
+ thread_resume(ao);
+ break;
+ case WASAPI_THREAD_SHUTDOWN:
+ thread_reset(ao);
+ goto exit_label;
+ default:
+ MP_ERR(ao, "Unhandled thread state\n");
+ goto exit_label;
+ }
break;
- case (WAIT_OBJECT_0 + 4): /* messages to dispatch (COM marshalling) */
- MP_DBG(ao, "Dispatch\n");
- wasapi_dispatch();
+ /* messages to dispatch (COM marshalling) */
+ case (WAIT_OBJECT_0 + MP_ARRAY_SIZE(events)):
+ wasapi_dispatch(ao);
break;
default:
- MP_ERR(ao, "Unhandled case in thread loop\n");
+ MP_ERR(ao, "Unhandled thread event\n");
goto exit_label;
}
}
@@ -203,15 +215,11 @@ exit_label:
return 0;
}
-static void closehandles(struct ao *ao)
+static void set_thread_state(struct ao *ao, enum wasapi_thread_state thread_state)
{
struct wasapi_state *state = ao->priv;
- if (state->init_done) CloseHandle(state->init_done);
- if (state->hUninit) CloseHandle(state->hUninit);
- if (state->hFeed) CloseHandle(state->hFeed);
- if (state->hResume) CloseHandle(state->hResume);
- if (state->hReset) CloseHandle(state->hReset);
- if (state->threadLoop) CloseHandle(state->threadLoop);
+ atomic_store(&state->thread_state, thread_state);
+ SetEvent(state->hWake);
}
static void uninit(struct ao *ao)
@@ -219,16 +227,23 @@ static void uninit(struct ao *ao)
MP_DBG(ao, "Uninit wasapi\n");
struct wasapi_state *state = ao->priv;
wasapi_release_proxies(state);
- if (state->hUninit)
- SetEvent(state->hUninit);
+ if (state->hWake)
+ set_thread_state(ao, WASAPI_THREAD_SHUTDOWN);
+
/* wait up to 10 seconds */
- if (WaitForSingleObject(state->threadLoop, 10000) == WAIT_TIMEOUT) {
+ if (state->hAudioThread &&
+ WaitForSingleObject(state->hAudioThread, 10000) == WAIT_TIMEOUT)
+ {
MP_ERR(ao, "Audio loop thread refuses to abort\n");
return;
}
if (state->VistaBlob.hAvrt)
FreeLibrary(state->VistaBlob.hAvrt);
- closehandles(ao);
+
+ SAFE_RELEASE(state->hInitDone, CloseHandle(state->hInitDone));
+ SAFE_RELEASE(state->hWake, CloseHandle(state->hWake));
+ SAFE_RELEASE(state->hAudioThread,CloseHandle(state->hAudioThread));
+
CoUninitialize();
MP_DBG(ao, "Uninit wasapi done\n");
}
@@ -243,30 +258,24 @@ static int init(struct ao *ao)
if(!wasapi_fill_VistaBlob(state))
MP_WARN(ao, "Error loading thread priority functions\n");
- state->init_done = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hUninit = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hFeed = CreateEventW(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */
- state->hResume = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hReset = CreateEventW(NULL, FALSE, FALSE, NULL);
- if (!state->init_done || !state->hFeed || !state->hUninit ||
- !state->hResume || !state->hReset)
- {
- MP_ERR(ao, "Error initing events\n");
+ state->hInitDone = CreateEventW(NULL, FALSE, FALSE, NULL);
+ state->hWake = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if (!state->hInitDone || !state->hWake) {
+ MP_ERR(ao, "Error creating events\n");
uninit(ao);
- /* failed to init events */
return -1;
}
state->init_ret = E_FAIL;
- state->threadLoop = CreateThread(NULL, 0, &ThreadLoop, ao, 0, NULL);
- if (!state->threadLoop) {
- /* failed to init thread */
- MP_ERR(ao, "Failed to create thread\n");
+ state->hAudioThread = CreateThread(NULL, 0, &AudioThread, ao, 0, NULL);
+ if (!state->hAudioThread) {
+ MP_ERR(ao, "Failed to create audio thread\n");
uninit(ao);
return -1;
}
- WaitForSingleObject(state->init_done, INFINITE); /* wait on init complete */
+ WaitForSingleObject(state->hInitDone, INFINITE); /* wait on init complete */
+ SAFE_RELEASE(state->hInitDone,CloseHandle(state->hInitDone));
if (state->init_ret != S_OK) {
if (!ao->probing)
MP_ERR(ao, "Received failure from audio thread\n");
@@ -360,14 +369,12 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
static void audio_reset(struct ao *ao)
{
- struct wasapi_state *state = ao->priv;
- SetEvent(state->hReset);
+ set_thread_state(ao, WASAPI_THREAD_RESET);
}
static void audio_resume(struct ao *ao)
{
- struct wasapi_state *state = ao->priv;
- SetEvent(state->hResume);
+ set_thread_state(ao, WASAPI_THREAD_RESUME);
}
static void hotplug_uninit(struct ao *ao)