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:
parent
36011c7f6d
commit
446fd5a43a
@ -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)
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user