summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-04-18 11:53:56 +0200
committerwm4 <wm4@nowhere>2017-04-20 07:46:10 +0200
commite6db75d314fe871562db4ef26c17410253394c5e (patch)
treea58deb22507a2350338babfaf932bb6e322bc9f6
parent5a33242854e2f2cb5fb2f5a2395998d0b5b147f0 (diff)
downloadmpv-wasapi-attempt.tar.bz2
mpv-wasapi-attempt.tar.xz
-rw-r--r--audio/out/ao_wasapi.c7
-rw-r--r--audio/out/ao_wasapi_utils.c192
2 files changed, 190 insertions, 9 deletions
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index 3a4c341387..1062a4cc50 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -278,12 +278,13 @@ static int init(struct ao *ao)
state->opt_exclusive |= ao->init_flags & AO_INIT_EXCLUSIVE;
state->deviceID = wasapi_find_deviceID(ao);
- if (!state->deviceID) {
+ /*if (!state->deviceID) {
uninit(ao);
return -1;
- }
+ }*/
- wasapi_change_init(ao, false);
+ if (state->deviceID)
+ wasapi_change_init(ao, false);
state->hInitDone = CreateEventW(NULL, FALSE, FALSE, NULL);
state->hWake = CreateEventW(NULL, FALSE, FALSE, NULL);
diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c
index f1895eb49e..539ea983cf 100644
--- a/audio/out/ao_wasapi_utils.c
+++ b/audio/out/ao_wasapi_utils.c
@@ -25,6 +25,8 @@
#include <ksmedia.h>
#include <avrt.h>
+#include <semaphore.h>
+
#include "audio/format.h"
#include "osdep/timer.h"
#include "osdep/io.h"
@@ -935,20 +937,198 @@ exit_label:
return deviceID;
}
+
+DEFINE_GUID(DEVINTERFACE_AUDIO_RENDER, 0xe6327cad, 0xdcec, 0x4949, 0xae, 0x8a, 0x99, 0x1e, 0x97, 0x6a, 0x79, 0xd2);
+
+DEFINE_GUID(IID_IActivateAudioInterfaceCompletionHandler, 0x41D949AB, 0x9862, 0x444A, 0x80, 0xF6, 0xC2, 0x61, 0x33, 0x4D, 0xA5, 0xEB);
+
+typedef struct IActivateAudioInterfaceAsyncOperation IActivateAudioInterfaceAsyncOperation;
+typedef struct IActivateAudioInterfaceCompletionHandler IActivateAudioInterfaceCompletionHandler;
+
+// MSDN
+typedef HRESULT WINAPI P_ActivateAudioInterfaceAsync(
+ _In_ LPCWSTR deviceInterfacePath,
+ _In_ REFIID riid,
+ _In_ PROPVARIANT *activationParams,
+ _In_ IActivateAudioInterfaceCompletionHandler *completionHandler,
+ _COM_Outptr_ IActivateAudioInterfaceAsyncOperation **createAsync
+);
+
+#undef INTERFACE
+#define INTERFACE IActivateAudioInterfaceAsyncOperation
+DECLARE_INTERFACE_(IActivateAudioInterfaceAsyncOperation,IUnknown)
+{
+ BEGIN_INTERFACE
+
+#ifndef __cplusplus
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+#endif
+
+ /* IActivateAudioInterfaceAsyncOperation methods */
+ STDMETHOD(GetActivateResult)(THIS_
+ HRESULT *activateResult,
+ IUnknown **activatedInterface);
+
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IActivateAudioInterfaceAsyncOperation_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#define IActivateAudioInterfaceAsyncOperation_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IActivateAudioInterfaceAsyncOperation_Release(This) (This)->lpVtbl->Release(This)
+#define IActivateAudioInterfaceAsyncOperation_GetActivateResult(This,a,b) (This)->lpVtbl->GetActivateResult(This,a,b)
+#endif /*COBJMACROS*/
+
+#undef INTERFACE
+#define INTERFACE IActivateAudioInterfaceCompletionHandler
+DECLARE_INTERFACE_(IActivateAudioInterfaceCompletionHandler,IUnknown)
+{
+ BEGIN_INTERFACE
+
+#ifndef __cplusplus
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppvObject) PURE;
+ STDMETHOD_(ULONG, AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG, Release)(THIS) PURE;
+#endif
+
+ /* IActivateAudioInterfaceCompletionHandler methods */
+ STDMETHOD(ActivateCompleted)(THIS_
+ IActivateAudioInterfaceAsyncOperation *activateOperation);
+
+ END_INTERFACE
+};
+#ifdef COBJMACROS
+#define IActivateAudioInterfaceCompletionHandler_QueryInterface(This,riid,ppvObject) (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
+#define IActivateAudioInterfaceCompletionHandler_AddRef(This) (This)->lpVtbl->AddRef(This)
+#define IActivateAudioInterfaceCompletionHandler_Release(This) (This)->lpVtbl->Release(This)
+#define IActivateAudioInterfaceCompletionHandler_ActivateCompleted(This,a) (This)->lpVtbl->ActivateCompleted(This,a)
+#endif /*COBJMACROS*/
+
+typedef struct AICompletionHandler
+{
+ IActivateAudioInterfaceCompletionHandler handler; // must be the first field
+ struct ao *ao;
+ sem_t sem;
+} AICompletionHandler;
+
+static HRESULT STDMETHODCALLTYPE AICompletionHandler_QueryInterface(
+ IActivateAudioInterfaceCompletionHandler* This, REFIID riid, void **ppvObject)
+{
+ // Compatible with IActivateAudioInterfaceCompletionHandler and IUnknown
+ // Also, include the IID_IAgileObject marker interface.
+ if (IsEqualGUID(&IID_IActivateAudioInterfaceCompletionHandler, riid) ||
+ IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IAgileObject, riid))
+ {
+ *ppvObject = (void *)This;
+ return S_OK;
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+// these are required, but not actually used
+static ULONG STDMETHODCALLTYPE AICompletionHandler_AddRef(
+ IActivateAudioInterfaceCompletionHandler *This)
+{
+ return 1;
+}
+
+// MSDN says it should free itself, but we're static
+static ULONG STDMETHODCALLTYPE AICompletionHandler_Release(
+ IActivateAudioInterfaceCompletionHandler *This)
+{
+ return 1;
+}
+
+static HRESULT STDMETHODCALLTYPE AICompletionHandler_ActivateCompleted(
+ IActivateAudioInterfaceCompletionHandler *This,
+ IActivateAudioInterfaceAsyncOperation *activateOperation)
+{
+ AICompletionHandler *handler = (AICompletionHandler *)This;
+
+ MP_VERBOSE(handler->ao, "waiting for device done\n");
+ sem_post(&handler->sem);
+
+ return S_OK;
+}
+
+static CONST_VTBL IActivateAudioInterfaceCompletionHandlerVtbl AICompletionHandlerVtbl = {
+ .QueryInterface = AICompletionHandler_QueryInterface,
+ .AddRef = AICompletionHandler_AddRef,
+ .Release = AICompletionHandler_Release,
+ .ActivateCompleted = AICompletionHandler_ActivateCompleted,
+};
+
HRESULT wasapi_thread_init(struct ao *ao)
{
struct wasapi_state *state = ao->priv;
MP_DBG(ao, "Init wasapi thread\n");
int64_t retry_wait = 1;
+ HRESULT hr;
+
retry: ;
- HRESULT hr = load_device(ao->log, &state->pDevice, state->deviceID);
- EXIT_ON_ERROR(hr);
+ if (state->deviceID) {
+ hr = load_device(ao->log, &state->pDevice, state->deviceID);
+ EXIT_ON_ERROR(hr);
- MP_DBG(ao, "Activating pAudioClient interface\n");
- hr = IMMDeviceActivator_Activate(state->pDevice, &IID_IAudioClient,
- CLSCTX_ALL, NULL,
+ MP_DBG(ao, "Activating pAudioClient interface\n");
+ hr = IMMDeviceActivator_Activate(state->pDevice, &IID_IAudioClient,
+ CLSCTX_ALL, NULL,
+ (void **)&state->pAudioClient);
+ EXIT_ON_ERROR(hr);
+ } else {
+ HANDLE dll = LoadLibraryW(L"mmdevapi.dll");
+ if (!dll) {
+ MP_FATAL(ao, "Could not load DLL.\n");
+ hr = S_FALSE;
+ goto exit_label;
+ }
+ P_ActivateAudioInterfaceAsync *ActivateAudioInterfaceAsync =
+ (void *)GetProcAddress(dll, "ActivateAudioInterfaceAsync");
+ if (!ActivateAudioInterfaceAsync) {
+ MP_FATAL(ao, "Could not load function.\n");
+ hr = S_FALSE;
+ goto exit_label;
+ }
+ wchar_t *s = NULL;
+ hr = StringFromIID(&DEVINTERFACE_AUDIO_RENDER, &s);
+ if (FAILED(hr))
+ goto exit_label;
+ AICompletionHandler compl = {.ao = ao};
+ compl.handler.lpVtbl = &AICompletionHandlerVtbl;
+ sem_init(&compl.sem, 0, 0);
+ IActivateAudioInterfaceAsyncOperation *asyncop = NULL;
+ hr = ActivateAudioInterfaceAsync(s, &IID_IAudioClient, NULL,
+ &compl.handler, &asyncop);
+ if (FAILED(hr))
+ goto exit_label;
+ MP_VERBOSE(ao, "waiting for device...\n");
+ sem_wait(&compl.sem);
+ HRESULT res_hr;
+ IUnknown *res_intf;
+ hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(asyncop,
+ &res_hr,
+ &res_intf);
+ if (FAILED(hr))
+ goto exit_label;
+ MP_VERBOSE(ao, "successfully got result\n");
+ if (!res_intf) {
+ hr = res_hr;
+ goto exit_label;
+ }
+
+ hr = IUnknown_QueryInterface(res_intf, &IID_IAudioClient,
(void **)&state->pAudioClient);
- EXIT_ON_ERROR(hr);
+ IUnknown_Release(res_intf);
+ IActivateAudioInterfaceAsyncOperation_Release(asyncop);
+ if (FAILED(hr))
+ goto exit_label;
+ }
MP_DBG(ao, "Probing formats\n");
if (!find_formats(ao)) {