summaryrefslogtreecommitdiffstats
path: root/audio
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
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')
-rw-r--r--audio/out/ao_wasapi.c268
-rwxr-xr-xaudio/out/ao_wasapi.h29
-rwxr-xr-xaudio/out/ao_wasapi_utils.c152
-rwxr-xr-xaudio/out/ao_wasapi_utils.h25
4 files changed, 203 insertions, 271 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),
diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h
index 8df45f042e..a0ce654d4d 100755
--- a/audio/out/ao_wasapi.h
+++ b/audio/out/ao_wasapi.h
@@ -34,25 +34,11 @@ typedef struct wasapi_state {
/* Init phase */
int init_ret;
HANDLE init_done;
- HANDLE fatal_error; /* signal to indicate unrecoverable error */
int share_mode;
- /* Events */
- HANDLE hPause;
-
- /* Play */
- HANDLE hPlay;
- int is_playing;
-
- /* Reset */
- HANDLE hReset;
-
- /* uninit */
HANDLE hUninit;
- LONG immed;
/* volume control */
- HANDLE hGetvol, hSetvol, hDoneVol;
DWORD vol_hw_support, status;
float audio_volume;
@@ -70,10 +56,23 @@ typedef struct wasapi_state {
IAudioRenderClient *pRenderClient;
IAudioEndpointVolume *pEndpointVolume;
HANDLE hFeed; /* wasapi event */
+ HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */
+ HANDLE hFeedDone; /* set only after a hForceFeed */
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;
+ IAudioEndpointVolume *pEndpointVolumeProxy;
+
+ /* 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 *sEndpointVolume;
+
/* WASAPI internal clock information, for estimating delay */
IAudioClock *pAudioClock;
UINT64 clock_frequency; /* scale for the "samples" returned by the clock */
@@ -92,4 +91,4 @@ typedef struct wasapi_state {
} VistaBlob;
} wasapi_state;
-#endif \ No newline at end of file
+#endif
diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c
index dc530820ba..feadfc0631 100755
--- a/audio/out/ao_wasapi_utils.c
+++ b/audio/out/ao_wasapi_utils.c
@@ -20,7 +20,6 @@
#define COBJMACROS 1
#define _WIN32_WINNT 0x600
-#include <process.h>
#include <initguid.h>
#include <audioclient.h>
#include <endpointvolume.h>
@@ -29,15 +28,7 @@
#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"
#define EXIT_ON_ERROR(hres) \
do { if (FAILED(hres)) { goto exit_label; } } while(0)
@@ -343,7 +334,7 @@ static int try_passthrough(struct wasapi_state *state,
return 0;
}
-int wasapi_find_formats(struct ao *const ao)
+static int find_formats(struct ao *const ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
@@ -470,11 +461,10 @@ static int init_clock(struct wasapi_state *state) {
exit_label:
MP_ERR(state, "init_clock failed with %s, unable to obtain the audio device's timing!\n",
wasapi_explain_err(hr));
- SetEvent(state->fatal_error);
return 1;
}
-int wasapi_fix_format(struct wasapi_state *state)
+static int fix_format(struct wasapi_state *state)
{
HRESULT hr;
double offset = 0.5;
@@ -538,7 +528,6 @@ reinit:
exit_label:
MP_ERR(state, "fix_format fails with %s, failed to determine buffer block size!\n",
wasapi_explain_err(hr));
- SetEvent(state->fatal_error);
return 1;
}
@@ -552,7 +541,7 @@ static char* wstring_to_utf8(wchar_t *wstring) {
return NULL;
}
-char* wasapi_get_device_id(IMMDevice *pDevice) {
+static char* get_device_id(IMMDevice *pDevice) {
if (!pDevice) {
return NULL;
}
@@ -576,7 +565,7 @@ exit_label:
return idstr;
}
-char* wasapi_get_device_name(IMMDevice *pDevice) {
+static char* get_device_name(IMMDevice *pDevice) {
if (!pDevice) {
return NULL;
}
@@ -664,7 +653,7 @@ static HRESULT enumerate_with_state(struct mp_log *log, char *header,
&pDevice);
EXIT_ON_ERROR(hr);
- defid = wasapi_get_device_id(pDevice);
+ defid = get_device_id(pDevice);
SAFE_RELEASE(pDevice, IMMDevice_Release(pDevice));
@@ -682,8 +671,8 @@ static HRESULT enumerate_with_state(struct mp_log *log, char *header,
hr = IMMDeviceCollection_Item(pDevices, i, &pDevice);
EXIT_ON_ERROR(hr);
- char *name = wasapi_get_device_name(pDevice);
- char *id = wasapi_get_device_id(pDevice);
+ char *name = get_device_name(pDevice);
+ char *id = get_device_id(pDevice);
char *mark = "";
if (strcmp(id, defid) == 0)
@@ -715,7 +704,7 @@ exit_label:
int wasapi_enumerate_devices(struct mp_log *log)
{
HRESULT hr;
- CoInitialize(NULL);
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
hr = enumerate_with_state(log, "Active devices:", DEVICE_STATE_ACTIVE, 1);
EXIT_ON_ERROR(hr);
@@ -730,7 +719,7 @@ exit_label:
return 1;
}
-HRESULT wasapi_find_and_load_device(struct ao *ao, IMMDevice **ppDevice,
+static HRESULT find_and_load_device(struct ao *ao, IMMDevice **ppDevice,
char *search)
{
HRESULT hr;
@@ -790,7 +779,7 @@ HRESULT wasapi_find_and_load_device(struct ao *ao, IMMDevice **ppDevice,
hr = IMMDeviceCollection_Item(pDevices, i, &pTempDevice);
EXIT_ON_ERROR(hr);
- if (device_id_match(wasapi_get_device_id(pTempDevice), devid)) {
+ if (device_id_match(get_device_id(pTempDevice), devid)) {
hr = IMMDevice_GetId(pTempDevice, &deviceID);
EXIT_ON_ERROR(hr);
break;
@@ -801,12 +790,12 @@ HRESULT wasapi_find_and_load_device(struct ao *ao, IMMDevice **ppDevice,
char *name;
if (!search_err) {
MP_ERR(ao, "multiple matching devices found!\n");
- name = wasapi_get_device_name(prevDevice);
+ name = get_device_name(prevDevice);
MP_ERR(ao, "%s\n", name);
free(name);
search_err = 1;
}
- name = wasapi_get_device_name(pTempDevice);
+ name = get_device_name(pTempDevice);
MP_ERR(ao, "%s\n", name);
free(name);
}
@@ -864,4 +853,119 @@ int wasapi_validate_device(struct mp_log *log, const m_option_t *opt,
mp_dbg(log, "device=%s %svalid\n", param.start, ret == 1 ? "" : "not ");
return ret;
-} \ No newline at end of file
+}
+
+HRESULT wasapi_setup_proxies(struct wasapi_state *state) {
+ HRESULT hr;
+ hr = CoGetInterfaceAndReleaseStream(state->sAudioClient,
+ &IID_IAudioClient,
+ (void**) &state->pAudioClientProxy);
+ state->sAudioClient = NULL;
+ EXIT_ON_ERROR(hr);
+
+ hr = CoGetInterfaceAndReleaseStream(state->sEndpointVolume,
+ &IID_IAudioEndpointVolume,
+ (void**) &state->pEndpointVolumeProxy);
+ state->sEndpointVolume = NULL;
+ EXIT_ON_ERROR(hr);
+
+exit_label:
+ return hr;
+}
+
+void wasapi_release_proxies(wasapi_state *state) {
+ SAFE_RELEASE(state->pAudioClientProxy, IUnknown_Release(state->pAudioClientProxy));
+ SAFE_RELEASE(state->pEndpointVolumeProxy, IUnknown_Release(state->pEndpointVolumeProxy));
+}
+
+static HRESULT create_proxies(struct wasapi_state *state) {
+ HRESULT hr;
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &state->sAudioClient);
+ EXIT_ON_ERROR(hr);
+ hr = CoMarshalInterThreadInterfaceInStream(&IID_IAudioClient,
+ (IUnknown*) state->pAudioClient,
+ &state->sAudioClient);
+ EXIT_ON_ERROR(hr);
+
+ hr = CreateStreamOnHGlobal(NULL, TRUE, &state->sEndpointVolume);
+ EXIT_ON_ERROR(hr);
+ hr = CoMarshalInterThreadInterfaceInStream(&IID_IAudioEndpointVolume,
+ (IUnknown*) state->pEndpointVolume,
+ &state->sEndpointVolume);
+exit_label:
+ return hr;
+}
+
+int wasapi_thread_init(struct ao *ao)
+{
+ struct wasapi_state *state = (struct wasapi_state *)ao->priv;
+ HRESULT hr;
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+
+ 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 = get_device_id(state->pDevice);
+ MP_VERBOSE(ao, "default device ID: %s\n", id);
+ free(id);
+ } else {
+ hr = find_and_load_device(ao, &state->pDevice, state->opt_device);
+ }
+ EXIT_ON_ERROR(hr);
+
+ char *name = 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 = find_formats(ao); /* Probe support formats */
+ if (state->init_ret)
+ goto exit_label;
+ if (!fix_format(state)) { /* now that we're sure what format to use */
+ EXIT_ON_ERROR(create_proxies(state));
+ 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;
+}
+
+void wasapi_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);
+}
diff --git a/audio/out/ao_wasapi_utils.h b/audio/out/ao_wasapi_utils.h
index eb4b56556f..fdc6e4fb7c 100755
--- a/audio/out/ao_wasapi_utils.h
+++ b/audio/out/ao_wasapi_utils.h
@@ -20,37 +20,26 @@
#ifndef MP_AO_WASAPI_UTILS_H_
#define MP_AO_WASAPI_UTILS_H_
-#define COBJMACROS 1
-#define _WIN32_WINNT 0x600
-
#include "audio/out/ao_wasapi.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"
int wasapi_fill_VistaBlob(wasapi_state *state);
const char *wasapi_explain_err(const HRESULT hr);
-char* wasapi_get_device_name(IMMDevice *pDevice);
-char* wasapi_get_device_id(IMMDevice *pDevice);
-
-int wasapi_find_formats(struct ao *const ao);
-int wasapi_fix_format(struct wasapi_state *state);
-
int wasapi_enumerate_devices(struct mp_log *log);
-HRESULT wasapi_find_and_load_device(struct ao *ao, IMMDevice **ppDevice,
- char *search);
-
int wasapi_validate_device(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param);
-#endif \ No newline at end of file
+int wasapi_thread_init(struct ao *ao);
+void wasapi_thread_uninit(wasapi_state *state);
+
+HRESULT wasapi_setup_proxies(wasapi_state *state);
+void wasapi_release_proxies(wasapi_state *state);
+
+#endif