summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/out/ao_wasapi.c115
-rwxr-xr-xaudio/out/ao_wasapi.h17
-rwxr-xr-xaudio/out/ao_wasapi_utils.c9
-rwxr-xr-xaudio/out/ao_wasapi_utils.h2
4 files changed, 78 insertions, 65 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)
diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h
index eb06e46566..24b9b862ed 100755
--- a/audio/out/ao_wasapi.h
+++ b/audio/out/ao_wasapi.h
@@ -43,11 +43,18 @@ void wasapi_change_uninit(struct ao* ao);
#define SAFE_RELEASE(unk, release) \
do { if ((unk) != NULL) { release; (unk) = NULL; } } while(0)
+enum wasapi_thread_state {
+ WASAPI_THREAD_FEED = 0,
+ WASAPI_THREAD_RESUME,
+ WASAPI_THREAD_RESET,
+ WASAPI_THREAD_SHUTDOWN
+};
+
typedef struct wasapi_state {
struct mp_log *log;
/* Init phase */
HRESULT init_ret;
- HANDLE init_done;
+ HANDLE hInitDone;
int share_mode;
/* volume control */
@@ -66,11 +73,9 @@ typedef struct wasapi_state {
IMMDeviceEnumerator *pEnumerator;
/* thread handles */
- HANDLE threadLoop; /* the thread itself */
- HANDLE hUninit; /* thread shutdown */
- HANDLE hFeed; /* wasapi event */
- HANDLE hResume; /* signal audio thread to resume the stream */
- HANDLE hReset; /* signal audio thread to reset the stream */
+ HANDLE hAudioThread; /* the thread itself */
+ HANDLE hWake; /* thread wakeup event */
+ atomic_int thread_state; /* enum wasapi_thread_state */
/* for setting the audio thread priority */
HANDLE hTask; /* AV thread */
diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c
index dfe76918f9..b0b0c10575 100755
--- a/audio/out/ao_wasapi_utils.c
+++ b/audio/out/ao_wasapi_utils.c
@@ -697,7 +697,7 @@ reinit:
EXIT_ON_ERROR(hr);
MP_DBG(state, "IAudioClient::Initialize IAudioClient_SetEventHandle\n");
- hr = IAudioClient_SetEventHandle(state->pAudioClient, state->hFeed);
+ hr = IAudioClient_SetEventHandle(state->pAudioClient, state->hWake);
EXIT_ON_ERROR(hr);
MP_DBG(state, "IAudioClient::Initialize IAudioClient_GetBufferSize\n");
@@ -1054,8 +1054,9 @@ static void destroy_proxies(struct wasapi_state *state) {
SAFE_RELEASE(state->sSessionControl, IUnknown_Release(state->sSessionControl));
}
-void wasapi_dispatch(void)
+void wasapi_dispatch(struct ao *ao)
{
+ MP_DBG(ao, "Dispatch\n");
/* dispatch any possible pending messages */
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
@@ -1154,8 +1155,8 @@ exit_label:
void wasapi_thread_uninit(struct ao *ao)
{
struct wasapi_state *state = ao->priv;
-
- wasapi_dispatch();
+ MP_DBG(ao, "Thread shutdown\n");
+ wasapi_dispatch(ao);
if (state->pAudioClient)
IAudioClient_Stop(state->pAudioClient);
diff --git a/audio/out/ao_wasapi_utils.h b/audio/out/ao_wasapi_utils.h
index 330a502046..5ac2d3efba 100755
--- a/audio/out/ao_wasapi_utils.h
+++ b/audio/out/ao_wasapi_utils.h
@@ -38,7 +38,7 @@ bool wasapi_fill_VistaBlob(wasapi_state *state);
void wasapi_list_devs(struct ao *ao, struct ao_device_list *list);
-void wasapi_dispatch(void);
+void wasapi_dispatch(struct ao *ao);
HRESULT wasapi_thread_init(struct ao *ao);
void wasapi_thread_uninit(struct ao *ao);