1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-11 08:37:59 +00:00

ao_wasapi: move reset into audio thread

This makes things a bit more deterministic. It ensures that the audio
thread isn't doing anything between IAudioClient_Stop(),
IAudioClient_Reset() and setting the sample_count to 0.

Buffer overfilling on resume is still a problem in exclusive mode (see
next commit).
This commit is contained in:
Kevin Mitchell 2015-02-22 18:47:50 -08:00
parent 36011c7f6d
commit 446fd5a43a
2 changed files with 37 additions and 9 deletions

View File

@ -113,6 +113,31 @@ exit_label:
return; return;
} }
static void thread_reset(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
HRESULT hr;
MP_DBG(state, "Thread Reset\n");
hr = IAudioClient_Stop(state->pAudioClient);
/* we may get S_FALSE if the stream is already stopped */
if (hr != S_OK &&
hr != S_FALSE) {
MP_ERR(state, "IAudioClient_Stop returned: %s (0x%"PRIx32")\n",
wasapi_explain_err(hr), (uint32_t) hr);
}
/* we may get S_FALSE if the stream is already reset */
hr = IAudioClient_Reset(state->pAudioClient);
if (hr != S_OK &&
hr != S_FALSE) {
MP_ERR(state, "IAudioClient_Reset returned: %s (0x%"PRIx32")\n",
wasapi_explain_err(hr), (uint32_t) hr);
}
atomic_store(&state->sample_count, 0);
return;
}
static DWORD __stdcall ThreadLoop(void *lpParameter) static DWORD __stdcall ThreadLoop(void *lpParameter)
{ {
struct ao *ao = lpParameter; struct ao *ao = lpParameter;
@ -126,10 +151,10 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)
DWORD waitstatus; DWORD waitstatus;
HANDLE playcontrol[] = HANDLE playcontrol[] =
{state->hUninit, state->hFeed, state->hForceFeed, NULL}; {state->hUninit, state->hFeed, state->hForceFeed, state->hReset, NULL};
MP_DBG(ao, "Entering dispatch loop\n"); MP_DBG(ao, "Entering dispatch loop\n");
while (true) { /* watch events */ while (true) { /* watch events */
waitstatus = MsgWaitForMultipleObjects(3, playcontrol, FALSE, INFINITE, waitstatus = MsgWaitForMultipleObjects(4, playcontrol, FALSE, INFINITE,
QS_POSTMESSAGE | QS_SENDMESSAGE); QS_POSTMESSAGE | QS_SENDMESSAGE);
switch (waitstatus) { switch (waitstatus) {
case WAIT_OBJECT_0: /*shutdown*/ case WAIT_OBJECT_0: /*shutdown*/
@ -142,12 +167,15 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)
thread_feed(ao); thread_feed(ao);
SetEvent(state->hFeedDone); SetEvent(state->hFeedDone);
break; break;
case (WAIT_OBJECT_0 + 3): /* messages to dispatch (COM marshalling) */ case (WAIT_OBJECT_0 + 3): /* reset */
thread_reset(ao);
break;
case (WAIT_OBJECT_0 + 4): /* messages to dispatch (COM marshalling) */
MP_DBG(ao, "Dispatch\n"); MP_DBG(ao, "Dispatch\n");
wasapi_dispatch(); wasapi_dispatch();
break; break;
default: default:
MP_ERR(ao, "Unhandled case in thread loop"); MP_ERR(ao, "Unhandled case in thread loop\n");
goto exit_label; goto exit_label;
} }
} }
@ -167,6 +195,7 @@ static void closehandles(struct ao *ao)
if (state->hFeed) CloseHandle(state->hFeed); if (state->hFeed) CloseHandle(state->hFeed);
if (state->hForceFeed) CloseHandle(state->hForceFeed); if (state->hForceFeed) CloseHandle(state->hForceFeed);
if (state->hFeedDone) CloseHandle(state->hFeedDone); if (state->hFeedDone) CloseHandle(state->hFeedDone);
if (state->hReset) CloseHandle(state->hReset);
if (state->threadLoop) CloseHandle(state->threadLoop); if (state->threadLoop) CloseHandle(state->threadLoop);
} }
@ -222,8 +251,9 @@ static int init(struct ao *ao)
state->hFeed = CreateEventW(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */ state->hFeed = CreateEventW(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */
state->hForceFeed = CreateEventW(NULL, FALSE, FALSE, NULL); state->hForceFeed = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hFeedDone = CreateEventW(NULL, FALSE, FALSE, NULL); state->hFeedDone = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hReset = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!state->init_done || !state->hFeed || !state->hUninit || if (!state->init_done || !state->hFeed || !state->hUninit ||
!state->hForceFeed || !state->hFeedDone) !state->hForceFeed || !state->hFeedDone || !state->hReset)
{ {
MP_ERR(ao, "Error initing events\n"); MP_ERR(ao, "Error initing events\n");
uninit(ao); uninit(ao);
@ -335,10 +365,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
static void audio_reset(struct ao *ao) static void audio_reset(struct ao *ao)
{ {
struct wasapi_state *state = (struct wasapi_state *)ao->priv; struct wasapi_state *state = (struct wasapi_state *)ao->priv;
SetEvent(state->hReset);
IAudioClient_Stop(state->pAudioClientProxy);
IAudioClient_Reset(state->pAudioClientProxy);
atomic_store(&state->sample_count, 0);
} }
static void audio_resume(struct ao *ao) static void audio_resume(struct ao *ao)

View File

@ -74,6 +74,7 @@ typedef struct wasapi_state {
HANDLE hFeed; /* wasapi event */ HANDLE hFeed; /* wasapi event */
HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */ HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */
HANDLE hFeedDone; /* set only after a hForceFeed */ HANDLE hFeedDone; /* set only after a hForceFeed */
HANDLE hReset; /* signal audio thread to reset the stream */
HANDLE hTask; /* AV thread */ HANDLE hTask; /* AV thread */
DWORD taskIndex; /* AV task ID */ DWORD taskIndex; /* AV task ID */
WAVEFORMATEXTENSIBLE format; WAVEFORMATEXTENSIBLE format;