Skip to content

Commit

Permalink
ao/wasapi: move resume to audio thread
Browse files Browse the repository at this point in the history
This echanges the two events hForceFeed/hFeedDone for hResume. This
like the last commit makes things more deterministic.

Importantly, the forcefeed is only done if there is not already a full
buffer yet to be played by the device. This should fix some of the
problems with exclusive mode.

This commit also removes the necessity to have a proxy to the
AudioClient object in the main thread.

fixes mpv-player#1529
  • Loading branch information
kevmitch authored and olifre committed Feb 28, 2015
1 parent dad1838 commit 1a85e14
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 24 deletions.
53 changes: 37 additions & 16 deletions audio/out/ao_wasapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,33 @@ static void thread_feed(struct ao *ao)
return;
}

static void thread_resume(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_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 (0x%"PRIx32")\n",
wasapi_explain_err(hr), (uint32_t) 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);

hr = IAudioClient_Start(state->pAudioClient);
if (hr != S_OK) {
MP_ERR(state, "IAudioClient_Start returned %s (0x%"PRIx32")\n",
wasapi_explain_err(hr), (uint32_t) hr);
}

return;
}

static void thread_reset(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
Expand Down Expand Up @@ -151,7 +178,7 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)

DWORD waitstatus;
HANDLE playcontrol[] =
{state->hUninit, state->hFeed, state->hForceFeed, state->hReset, NULL};
{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,
Expand All @@ -163,13 +190,12 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)
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): /* reset */
case (WAIT_OBJECT_0 + 2): /* reset */
thread_reset(ao);
break;
break;
case (WAIT_OBJECT_0 + 3): /* resume */
thread_resume(ao);
break;
case (WAIT_OBJECT_0 + 4): /* messages to dispatch (COM marshalling) */
MP_DBG(ao, "Dispatch\n");
wasapi_dispatch();
Expand All @@ -193,8 +219,7 @@ static void closehandles(struct ao *ao)
if (state->init_done) CloseHandle(state->init_done);
if (state->hUninit) CloseHandle(state->hUninit);
if (state->hFeed) CloseHandle(state->hFeed);
if (state->hForceFeed) CloseHandle(state->hForceFeed);
if (state->hFeedDone) CloseHandle(state->hFeedDone);
if (state->hResume) CloseHandle(state->hResume);
if (state->hReset) CloseHandle(state->hReset);
if (state->threadLoop) CloseHandle(state->threadLoop);
}
Expand Down Expand Up @@ -249,11 +274,10 @@ static int init(struct ao *ao)
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->hForceFeed = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hFeedDone = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hResume = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hReset = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!state->init_done || !state->hFeed || !state->hUninit ||
!state->hForceFeed || !state->hFeedDone || !state->hReset)
!state->hResume || !state->hReset)
{
MP_ERR(ao, "Error initing events\n");
uninit(ao);
Expand Down Expand Up @@ -371,10 +395,7 @@ static void audio_reset(struct ao *ao)
static void audio_resume(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;

SetEvent(state->hForceFeed);
WaitForSingleObject(state->hFeedDone, INFINITE);
IAudioClient_Start(state->pAudioClientProxy);
SetEvent(state->hResume);
}

static void list_devs(struct ao *ao, struct ao_device_list *list)
Expand Down
5 changes: 1 addition & 4 deletions audio/out/ao_wasapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,24 +72,21 @@ typedef struct wasapi_state {
IMMDeviceEnumerator *pEnumerator;

HANDLE hFeed; /* wasapi event */
HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */
HANDLE hFeedDone; /* set only after a hForceFeed */
HANDLE hResume; /* signal audio thread to resume the stream */
HANDLE hReset; /* signal audio thread to reset the stream */
HANDLE hTask; /* AV thread */
DWORD taskIndex; /* AV task ID */
WAVEFORMATEXTENSIBLE format;

/* WASAPI proxy handles, for Single-Threaded Apartment communication.
One is needed for each object that's accessed by a different thread. */
IAudioClient *pAudioClientProxy;
ISimpleAudioVolume *pAudioVolumeProxy;
IAudioEndpointVolume *pEndpointVolumeProxy;
IAudioSessionControl *pSessionControlProxy;

/* Streams used to marshal the proxy objects. The thread owning the actual objects
needs to marshal proxy objects into these streams, and the thread that wants the
proxies unmarshals them from here. */
IStream *sAudioClient;
IStream *sAudioVolume;
IStream *sEndpointVolume;
IStream *sSessionControl;
Expand Down
4 changes: 0 additions & 4 deletions audio/out/ao_wasapi_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,6 @@ HRESULT wasapi_setup_proxies(struct wasapi_state *state) {
EXIT_ON_ERROR(hr); \
} while (0)

UNMARSHAL(IID_IAudioClient, state->pAudioClientProxy, state->sAudioClient);
UNMARSHAL(IID_ISimpleAudioVolume, state->pAudioVolumeProxy, state->sAudioVolume);
UNMARSHAL(IID_IAudioEndpointVolume, state->pEndpointVolumeProxy, state->sEndpointVolume);
UNMARSHAL(IID_IAudioSessionControl, state->pSessionControlProxy, state->sSessionControl);
Expand All @@ -973,7 +972,6 @@ HRESULT wasapi_setup_proxies(struct wasapi_state *state) {
}

void wasapi_release_proxies(wasapi_state *state) {
SAFE_RELEASE(state->pAudioClientProxy, IUnknown_Release(state->pAudioClientProxy));
SAFE_RELEASE(state->pAudioVolumeProxy, IUnknown_Release(state->pAudioVolumeProxy));
SAFE_RELEASE(state->pEndpointVolumeProxy, IUnknown_Release(state->pEndpointVolumeProxy));
SAFE_RELEASE(state->pSessionControlProxy, IUnknown_Release(state->pSessionControlProxy));
Expand All @@ -991,7 +989,6 @@ static HRESULT create_proxies(struct wasapi_state *state) {
EXIT_ON_ERROR(hr); \
} while (0)

MARSHAL(IID_IAudioClient, state->sAudioClient, state->pAudioClient);
MARSHAL(IID_ISimpleAudioVolume, state->sAudioVolume, state->pAudioVolume);
MARSHAL(IID_IAudioEndpointVolume, state->sEndpointVolume, state->pEndpointVolume);
MARSHAL(IID_IAudioSessionControl, state->sSessionControl, state->pSessionControl);
Expand All @@ -1004,7 +1001,6 @@ static HRESULT create_proxies(struct wasapi_state *state) {
}

static void destroy_proxies(struct wasapi_state *state) {
SAFE_RELEASE(state->sAudioClient, IUnknown_Release(state->sAudioClient));
SAFE_RELEASE(state->sAudioVolume, IUnknown_Release(state->sAudioVolume));
SAFE_RELEASE(state->sEndpointVolume, IUnknown_Release(state->sEndpointVolume));
SAFE_RELEASE(state->sSessionControl, IUnknown_Release(state->sSessionControl));
Expand Down

0 comments on commit 1a85e14

Please sign in to comment.