diff options
Diffstat (limited to 'audio/out/ao_wasapi.c')
-rw-r--r-- | audio/out/ao_wasapi.c | 115 |
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) |