summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi.c
diff options
context:
space:
mode:
authorDiogo Franco (Kovensky) <diogomfranco@gmail.com>2014-03-11 00:47:33 -0300
committerDiogo Franco (Kovensky) <diogomfranco@gmail.com>2014-03-11 16:37:02 -0300
commitf3e9b9462210021286bfbe98eef228ab74c8b490 (patch)
tree07c2b6691a37f220717dd88cd7579a1f2b46851f /audio/out/ao_wasapi.c
parent58011810e5dad7c89a0123434fe9fe7cdaa26fac (diff)
downloadmpv-f3e9b9462210021286bfbe98eef228ab74c8b490.tar.bz2
mpv-f3e9b9462210021286bfbe98eef228ab74c8b490.tar.xz
ao_wasapi: Move non-critical code outside of the event thread
Due to the COM Single-Threaded Apartment model, the thread owning the objects will still do all the actual method calls (in the form of message dispatches), but at least this will be COM's problem rather than having to set up several handles and adding extra code to the event thread. Since the event thread still needs to own the WASAPI handles to avoid waiting on another thread to dispatch the messages, the init and uninit code still has to run in the thread. This also removes a broken drain implementation and removes unused headers from each of the files split from the original ao_wasapi.c.
Diffstat (limited to 'audio/out/ao_wasapi.c')
-rw-r--r--audio/out/ao_wasapi.c268
1 files changed, 54 insertions, 214 deletions
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index 79f8dcf665..a496ff9aa6 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -32,13 +32,7 @@
#include "audio/out/ao_wasapi.h"
#include "audio/out/ao_wasapi_utils.h"
-#include "options/m_option.h"
-#include "options/m_config.h"
#include "audio/format.h"
-#include "common/msg.h"
-#include "misc/ring.h"
-#include "ao.h"
-#include "internal.h"
#include "compat/atomics.h"
#include "osdep/timer.h"
@@ -47,61 +41,6 @@
#define SAFE_RELEASE(unk, release) \
do { if ((unk) != NULL) { release; (unk) = NULL; } } while(0)
-static int thread_init(struct ao *ao)
-{
- struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- HRESULT hr;
- CoInitialize(NULL);
-
- if (!state->opt_device) {
- IMMDeviceEnumerator *pEnumerator;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
- &IID_IMMDeviceEnumerator, (void**)&pEnumerator);
- EXIT_ON_ERROR(hr);
-
- hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator,
- eRender, eConsole,
- &state->pDevice);
- SAFE_RELEASE(pEnumerator, IMMDeviceEnumerator_Release(pEnumerator));
-
- char *id = wasapi_get_device_id(state->pDevice);
- MP_VERBOSE(ao, "default device ID: %s\n", id);
- free(id);
- } else {
- hr = wasapi_find_and_load_device(ao, &state->pDevice, state->opt_device);
- }
- EXIT_ON_ERROR(hr);
-
- char *name = wasapi_get_device_name(state->pDevice);
- MP_VERBOSE(ao, "device loaded: %s\n", name);
- free(name);
-
- hr = IMMDeviceActivator_Activate(state->pDevice, &IID_IAudioClient,
- CLSCTX_ALL, NULL, (void **)&state->pAudioClient);
- EXIT_ON_ERROR(hr);
-
- hr = IMMDeviceActivator_Activate(state->pDevice, &IID_IAudioEndpointVolume,
- CLSCTX_ALL, NULL,
- (void **)&state->pEndpointVolume);
- EXIT_ON_ERROR(hr);
- IAudioEndpointVolume_QueryHardwareSupport(state->pEndpointVolume,
- &state->vol_hw_support);
-
- state->init_ret = wasapi_find_formats(ao); /* Probe support formats */
- if (state->init_ret)
- goto exit_label;
- if (!wasapi_fix_format(state)) { /* now that we're sure what format to use */
- MP_VERBOSE(ao, "thread_init OK!\n");
- SetEvent(state->init_done);
- return state->init_ret;
- }
-exit_label:
- state->init_ret = -1;
- SetEvent(state->init_done);
- return -1;
-}
-
-
static double get_device_delay(struct wasapi_state *state) {
UINT64 sample_count = state->sample_count;
UINT64 position, qpc_position;
@@ -160,7 +99,8 @@ static void thread_feed(struct ao *ao)
frame_count, 0);
EXIT_ON_ERROR(hr);
- state->sample_count += frame_count;
+ mp_atomic_add_and_fetch(&state->sample_count, frame_count);
+ mp_memory_barrier();
return;
exit_label:
@@ -168,131 +108,48 @@ exit_label:
return;
}
-static void thread_pause(struct ao *ao)
-{
- struct wasapi_state *state = (struct wasapi_state *)ao->priv;
-
- state->is_playing = 0;
- IAudioClient_Stop(state->pAudioClient);
- IAudioClient_Reset(state->pAudioClient);
- state->sample_count = 0;
- mp_memory_barrier();
-}
-
-static void thread_resume(struct ao *ao)
-{
- struct wasapi_state *state = (struct wasapi_state *)ao->priv;
-
- state->is_playing = 1;
- thread_feed(ao);
- IAudioClient_Start(state->pAudioClient);
-}
-
-static void thread_reset(struct ao *ao)
-{
- thread_pause(ao);
-}
-
-static void thread_getVol(wasapi_state *state)
-{
- IAudioEndpointVolume_GetMasterVolumeLevelScalar(state->pEndpointVolume,
- &state->audio_volume);
- SetEvent(state->hDoneVol);
-}
-
-static void thread_setVol(wasapi_state *state)
-{
- IAudioEndpointVolume_SetMasterVolumeLevelScalar(state->pEndpointVolume,
- state->audio_volume, NULL);
- SetEvent(state->hDoneVol);
-}
-
-static void thread_uninit(wasapi_state *state)
-{
- if (state->pAudioClient)
- IAudioClient_Stop(state->pAudioClient);
- if (state->pRenderClient)
- IAudioRenderClient_Release(state->pRenderClient);
- if (state->pAudioClock)
- IAudioClock_Release(state->pAudioClock);
- if (state->pAudioClient)
- IAudioClient_Release(state->pAudioClient);
- if (state->pDevice)
- IMMDevice_Release(state->pDevice);
- if (state->hTask)
- state->VistaBlob.pAvRevertMmThreadCharacteristics(state->hTask);
- CoUninitialize();
- ExitThread(0);
-}
-
-static void audio_drain(struct ao *ao)
-{
- struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- while (1) {
- if (WaitForSingleObject(state->hFeed,2000) == WAIT_OBJECT_0 &&
- ao->api->get_delay(ao))
- {
- thread_feed(ao);
- } else
- break;
- }
-}
-
static DWORD __stdcall ThreadLoop(void *lpParameter)
{
struct ao *ao = lpParameter;
- int feedwatch = 0;
if (!ao || !ao->priv)
return -1;
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- if (thread_init(ao))
+ if (wasapi_thread_init(ao))
goto exit_label;
+ MSG msg;
DWORD waitstatus = WAIT_FAILED;
HANDLE playcontrol[] =
- {state->hUninit, state->hPause, state->hReset, state->hGetvol,
- state->hSetvol, state->hPlay, state->hFeed, NULL};
+ {state->hUninit, state->hFeed, state->hForceFeed, NULL};
MP_VERBOSE(ao, "Entering dispatch loop!\n");
- while (1) { /* watch events, poll at least every 2 seconds */
- waitstatus = WaitForMultipleObjects(7, playcontrol, FALSE, 2000);
+ while (1) { /* watch events */
+ waitstatus = MsgWaitForMultipleObjects(3, playcontrol, FALSE, INFINITE,
+ QS_POSTMESSAGE | QS_SENDMESSAGE);
switch (waitstatus) {
case WAIT_OBJECT_0: /*shutdown*/
- feedwatch = 0;
- thread_uninit(state);
+ wasapi_thread_uninit(state);
goto exit_label;
- case (WAIT_OBJECT_0 + 1): /* pause */
- feedwatch = 0;
- thread_pause(ao);
- break;
- case (WAIT_OBJECT_0 + 2): /* reset */
- feedwatch = 0;
- thread_reset(ao);
- break;
- case (WAIT_OBJECT_0 + 3): /* getVolume */
- thread_getVol(state);
- break;
- case (WAIT_OBJECT_0 + 4): /* setVolume */
- thread_setVol(state);
- break;
- case (WAIT_OBJECT_0 + 5): /* play */
- feedwatch = 0;
- thread_resume(ao);
+ case (WAIT_OBJECT_0 + 1): /* feed */
+ thread_feed(ao);
break;
- case (WAIT_OBJECT_0 + 6): /* feed */
- if (state->is_playing)
- feedwatch = 1;
+ case (WAIT_OBJECT_0 + 2): /* force feed */
thread_feed(ao);
+ SetEvent(state->hFeedDone);
break;
- case WAIT_TIMEOUT: /* Did our feed die? */
- if (feedwatch)
- return -1;
+ case (WAIT_OBJECT_0 + 3): /* messages to dispatch (COM marshalling) */
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ DispatchMessage(&msg);
+ }
break;
- default:
case WAIT_FAILED: /* ??? */
return -1;
}
}
exit_label:
+ /* dispatch any possible pending messages */
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ DispatchMessage(&msg);
+ }
return state->init_ret;
}
@@ -301,33 +158,21 @@ static void closehandles(struct ao *ao)
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
if (state->init_done)
CloseHandle(state->init_done);
- if (state->hPlay)
- CloseHandle(state->hPlay);
- if (state->hPause)
- CloseHandle(state->hPause);
- if (state->hReset)
- CloseHandle(state->hReset);
if (state->hUninit)
CloseHandle(state->hUninit);
if (state->hFeed)
CloseHandle(state->hFeed);
- if (state->hGetvol)
- CloseHandle(state->hGetvol);
- if (state->hSetvol)
- CloseHandle(state->hSetvol);
- if (state->hDoneVol)
- CloseHandle(state->hDoneVol);
}
static void uninit(struct ao *ao)
{
MP_VERBOSE(ao, "uninit!\n");
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- state->immed = 1;
+ wasapi_release_proxies(state);
SetEvent(state->hUninit);
/* wait up to 10 seconds */
if (WaitForSingleObject(state->threadLoop, 10000) == WAIT_TIMEOUT)
- SetEvent(state->fatal_error);
+ MP_ERR(ao, "audio loop thread refuses to abort!");
if (state->VistaBlob.hAvrt)
FreeLibrary(state->VistaBlob.hAvrt);
closehandles(ao);
@@ -357,18 +202,12 @@ static int init(struct ao *ao)
}
state->init_done = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hPlay = CreateEventW(NULL, FALSE, FALSE, NULL); /* kick start audio feed */
- state->hPause = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hReset = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hGetvol = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hSetvol = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->hDoneVol = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hUninit = CreateEventW(NULL, FALSE, FALSE, NULL);
- state->fatal_error = CreateEventW(NULL, TRUE, FALSE, NULL);
- state->hFeed = CreateEvent(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */
- if (!state->init_done || !state->fatal_error || !state->hPlay ||
- !state->hPause || !state->hFeed || !state->hReset || !state->hGetvol ||
- !state->hSetvol || !state->hDoneVol)
+ 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);
+ if (!state->init_done || !state->hFeed || !state->hUninit ||
+ !state->hForceFeed || !state->hFeedDone)
{
closehandles(ao);
/* failed to init events */
@@ -388,57 +227,59 @@ static int init(struct ao *ao)
}
} else
MP_VERBOSE(ao, "Init Done!\n");
+
+ wasapi_setup_proxies(state);
return state->init_ret;
}
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- if (!(state->vol_hw_support & ENDPOINT_HARDWARE_SUPPORT_VOLUME))
+ if (!state->share_mode && !(state->vol_hw_support & ENDPOINT_HARDWARE_SUPPORT_VOLUME)) {
return CONTROL_UNKNOWN; /* hw does not support volume controls in exclusive mode */
+ }
ao_control_vol_t *vol = (ao_control_vol_t *)arg;
- ResetEvent(state->hDoneVol);
switch (cmd) {
case AOCONTROL_GET_VOLUME:
- SetEvent(state->hGetvol);
- if (WaitForSingleObject(state->hDoneVol, 100) == WAIT_OBJECT_0) {
- vol->left = vol->right = 100.0f * state->audio_volume;
- return CONTROL_OK;
- }
- return CONTROL_UNKNOWN;
+ IAudioEndpointVolume_GetMasterVolumeLevelScalar(state->pEndpointVolumeProxy,
+ &state->audio_volume);
+ vol->left = vol->right = 100.0f * state->audio_volume;
+ return CONTROL_OK;
case AOCONTROL_SET_VOLUME:
state->audio_volume = vol->left / 100.f;
- SetEvent(state->hSetvol);
- if (WaitForSingleObject(state->hDoneVol, 100) == WAIT_OBJECT_0)
- return CONTROL_OK;
- return CONTROL_UNKNOWN;
+ IAudioEndpointVolume_SetMasterVolumeLevelScalar(state->pEndpointVolumeProxy,
+ state->audio_volume, NULL);
+ return CONTROL_OK;
default:
return CONTROL_UNKNOWN;
}
}
-static void audio_resume(struct ao *ao)
+
+static void audio_pause(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- ResetEvent(state->hPause);
- ResetEvent(state->hReset);
- SetEvent(state->hPlay);
+
+ IAudioClient_Stop(state->pAudioClientProxy);
+ IAudioClient_Reset(state->pAudioClientProxy);
+ state->sample_count = 0;
+ mp_memory_barrier();
}
-static void audio_pause(struct ao *ao)
+static void audio_resume(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- ResetEvent(state->hPlay);
- SetEvent(state->hPause);
+
+ SetEvent(state->hForceFeed);
+ WaitForSingleObject(state->hFeedDone, INFINITE);
+ IAudioClient_Start(state->pAudioClientProxy);
}
-static void reset(struct ao *ao)
+static void audio_reset(struct ao *ao)
{
- struct wasapi_state *state = (struct wasapi_state *)ao->priv;
- ResetEvent(state->hPlay);
- SetEvent(state->hReset);
+ audio_pause(ao);
}
#define OPT_BASE_STRUCT struct wasapi_state
@@ -451,8 +292,7 @@ const struct ao_driver audio_out_wasapi = {
.control = control,
.pause = audio_pause,
.resume = audio_resume,
- .reset = reset,
- .drain = audio_drain,
+ .reset = audio_reset,
.priv_size = sizeof(wasapi_state),
.options = (const struct m_option[]) {
OPT_FLAG("exclusive", opt_exclusive, 0),