summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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