static void thread_resume(struct ao *ao) { struct wasapi_state *state = ao->priv; HRESULT hr; MP_DBG(state, "Thread Resume\n"); UINT32 padding = 0; hr = IAudioClient_GetCurrentPadding(state->pAudioClient, &padding); if (hr != S_OK) { MP_ERR(state, "IAudioClient_GetCurrentPadding returned %s\n", mp_HRESULT_to_str(hr)); } // 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) 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)); } return; }
static DWORD __stdcall ThreadLoop(void *lpParameter) { struct ao *ao = lpParameter; if (!ao || !ao->priv) return -1; struct wasapi_state *state = (struct wasapi_state *)ao->priv; if (wasapi_thread_init(ao)) goto exit_label; MSG msg; DWORD waitstatus = WAIT_FAILED; HANDLE playcontrol[] = {state->hUninit, state->hFeed, state->hForceFeed, NULL}; MP_VERBOSE(ao, "Entering dispatch loop!\n"); while (1) { /* watch events */ waitstatus = MsgWaitForMultipleObjects(3, playcontrol, FALSE, INFINITE, QS_POSTMESSAGE | QS_SENDMESSAGE); switch (waitstatus) { case WAIT_OBJECT_0: /*shutdown*/ wasapi_thread_uninit(state); goto exit_label; case (WAIT_OBJECT_0 + 1): /* feed */ thread_feed(ao); break; case (WAIT_OBJECT_0 + 2): /* force feed */ thread_feed(ao); SetEvent(state->hFeedDone); break; case (WAIT_OBJECT_0 + 3): /* messages to dispatch (COM marshalling) */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } break; case WAIT_FAILED: /* ??? */ return -1; } } exit_label: /* dispatch any possible pending messages */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } return state->init_ret; }
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->hInitDone); if (state->init_ret != S_OK) goto exit_label; MP_DBG(ao, "Entering dispatch loop\n"); while (true) { // watch events 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; // messages to dispatch (COM marshalling) case (WAIT_OBJECT_0 + MP_ARRAY_SIZE(events)): wasapi_dispatch(ao); break; default: MP_ERR(ao, "Unhandled thread event\n"); goto exit_label; } } exit_label: wasapi_thread_uninit(ao); CoUninitialize(); MP_DBG(ao, "Thread return\n"); return 0; }