1
mirror of https://github.com/mpv-player/mpv synced 2024-09-28 17:52:52 +02:00

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.
This commit is contained in:
Diogo Franco (Kovensky) 2014-03-11 00:47:33 -03:00
parent 58011810e5
commit f3e9b94622
4 changed files with 205 additions and 273 deletions

View File

@ -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);
break;
case (WAIT_OBJECT_0 + 6): /* feed */
if (state->is_playing)
feedwatch = 1;
case (WAIT_OBJECT_0 + 1): /* feed */
thread_feed(ao);
break;
case WAIT_TIMEOUT: /* Did our feed die? */
if (feedwatch)
return -1;
case (WAIT_OBJECT_0 + 2): /* force feed */
thread_feed(ao);
SetEvent(state->hFeedDone);
break;
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)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
ResetEvent(state->hPause);
ResetEvent(state->hReset);
SetEvent(state->hPlay);
}
static void audio_pause(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
ResetEvent(state->hPlay);
SetEvent(state->hPause);
IAudioClient_Stop(state->pAudioClientProxy);
IAudioClient_Reset(state->pAudioClientProxy);
state->sample_count = 0;
mp_memory_barrier();
}
static void reset(struct ao *ao)
static void audio_resume(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
ResetEvent(state->hPlay);
SetEvent(state->hReset);
SetEvent(state->hForceFeed);
WaitForSingleObject(state->hFeedDone, INFINITE);
IAudioClient_Start(state->pAudioClientProxy);
}
static void audio_reset(struct ao *ao)
{
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),

View File

@ -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
#endif

View File

@ -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;
}
}
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);
}

View File

@ -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
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