summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi_utils.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_utils.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_utils.c')
-rwxr-xr-xaudio/out/ao_wasapi_utils.c152
1 files changed, 128 insertions, 24 deletions
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);
+}