mirror of https://github.com/mpv-player/mpv
ao/wasapi: move resume to audio thread
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 #1529
This commit is contained in:
parent
446fd5a43a
commit
c52833bf16
|
@ -113,6 +113,33 @@ exit_label:
|
|||
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;
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
|
|
@ -72,8 +72,7 @@ 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 */
|
||||
|
@ -81,7 +80,6 @@ typedef struct wasapi_state {
|
|||
|
||||
/* 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;
|
||||
|
@ -89,7 +87,6 @@ typedef struct wasapi_state {
|
|||
/* 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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -973,7 +972,6 @@ exit_label:
|
|||
}
|
||||
|
||||
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));
|
||||
|
@ -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);
|
||||
|
@ -1004,7 +1001,6 @@ exit_label:
|
|||
}
|
||||
|
||||
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));
|
||||
|
|
Loading…
Reference in New Issue