summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_wasapi_utils.c
diff options
context:
space:
mode:
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);
+}