summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDiogo Franco (Kovensky) <diogomfranco@gmail.com>2013-07-21 12:38:01 -0300
committerwm4 <wm4@nowhere>2013-07-22 02:42:38 +0200
commit964341b02df2488712dca540be8a28aa95c5c379 (patch)
tree145dbb51cd8be5a6d4c629be3fa1f346ec40d149
parentd42c3e51b41cc6d421ecefab146b80e9879fcf23 (diff)
downloadmpv-964341b02df2488712dca540be8a28aa95c5c379.tar.bz2
mpv-964341b02df2488712dca540be8a28aa95c5c379.tar.xz
ao_wasapi: Use OPT_STRING_VALIDATE for device suboption
Validates by trying to pick the device using the device enumerator and aborting with out of range on failure. Refactors find_and_load_device to not use the wasapi_state; it might be called during validation. Adds missing CoInitialize/CoUninitialize calls. Remove unused variables (the SAFE_RELEASE macros keep them referenced so compiler warnings don't help finding them...). Remove the IMMDeviceEnumerator from the wasapi_state, it's only needed during initialization and initialization is now well factored enough to get rid of it. Try and connect to unplugged devices as well when using the device ID string.
-rw-r--r--audio/out/ao_wasapi.c104
1 files changed, 82 insertions, 22 deletions
diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c
index 3413d0132f..5350bada30 100644
--- a/audio/out/ao_wasapi.c
+++ b/audio/out/ao_wasapi.c
@@ -108,7 +108,6 @@ typedef struct wasapi_state {
UINT32 bufferFrameCount; /* wasapi buffer block size, number of frames, frame size at format.nBlockAlign */
/* WASAPI handles, owned by other thread */
- IMMDeviceEnumerator *pEnumerator;
IMMDevice *pDevice;
IAudioClient *pAudioClient;
IAudioRenderClient *pRenderClient;
@@ -574,6 +573,10 @@ static char* wstring_to_utf8(wchar_t *wstring) {
}
static char* get_device_id(IMMDevice *pDevice) {
+ if (!pDevice) {
+ return NULL;
+ }
+
LPWSTR devid = NULL;
char *idstr = NULL;
@@ -594,6 +597,10 @@ exit_label:
}
static char* get_device_name(IMMDevice *pDevice) {
+ if (!pDevice) {
+ return NULL;
+ }
+
IPropertyStore *pProps = NULL;
char *namestr = NULL;
@@ -639,10 +646,8 @@ static HRESULT enumerate_with_state(char *header, int status, int with_id) {
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDeviceCollection *pDevices = NULL;
IMMDevice *pDevice = NULL;
- IPropertyStore *pProps = NULL;
char *defid = NULL;
- CoInitialize(NULL);
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
&IID_IMMDeviceEnumerator, (void **)&pEnumerator);
EXIT_ON_ERROR(hr)
@@ -696,7 +701,6 @@ static HRESULT enumerate_with_state(char *header, int status, int with_id) {
exit_label:
free(defid);
- SAFE_RELEASE(pProps, IPropertyStore_Release(pProps));
SAFE_RELEASE(pDevice, IMMDevice_Release(pDevice));
SAFE_RELEASE(pDevices, IMMDeviceCollection_Release(pDevices));
SAFE_RELEASE(pEnumerator, IMMDeviceEnumerator_Release(pEnumerator));
@@ -705,33 +709,41 @@ exit_label:
static int enumerate_devices(void) {
HRESULT hr;
+ CoInitialize(NULL);
hr = enumerate_with_state("Active devices:", DEVICE_STATE_ACTIVE, 1);
EXIT_ON_ERROR(hr)
hr = enumerate_with_state("Unplugged devices:", DEVICE_STATE_UNPLUGGED, 0);
EXIT_ON_ERROR(hr)
+ CoUninitialize();
return 0;
exit_label:
mp_msg(MSGT_AO, MSGL_ERR, "Error enumerating devices: HRESULT %08x \"%s\"\n",
hr, explain_err(hr));
+ CoUninitialize();
return 1;
}
-static HRESULT find_and_load_device(wasapi_state *state, int devno, char *devid) {
+static HRESULT find_and_load_device(IMMDevice **ppDevice, int devno, char *devid) {
HRESULT hr;
+ IMMDeviceEnumerator *pEnumerator = NULL;
IMMDeviceCollection *pDevices = NULL;
IMMDevice *pTempDevice = NULL;
LPWSTR deviceID = NULL;
- hr = IMMDeviceEnumerator_EnumAudioEndpoints(state->pEnumerator, eRender,
- DEVICE_STATE_ACTIVE, &pDevices);
- EXIT_ON_ERROR(hr)
-
- int count;
- IMMDeviceCollection_GetCount(pDevices, &count);
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
+ &IID_IMMDeviceEnumerator, (void**)&pEnumerator);
+ EXIT_ON_ERROR(hr);
if (devid == NULL) {
+ hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eRender,
+ DEVICE_STATE_ACTIVE, &pDevices);
+ EXIT_ON_ERROR(hr);
+
+ int count;
+ IMMDeviceCollection_GetCount(pDevices, &count);
+
if (devno >= count) {
- mp_msg(MSGT_AO, MSGL_ERR, "ao-wasapi: no endpoind #%d!\n", devno);
+ mp_msg(MSGT_AO, MSGL_ERR, "ao-wasapi: no device #%d!\n", devno);
} else {
mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: finding device #%d\n", devno);
hr = IMMDeviceCollection_Item(pDevices, devno, &pTempDevice);
@@ -743,6 +755,14 @@ static HRESULT find_and_load_device(wasapi_state *state, int devno, char *devid)
mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: found device #%d\n", devno);
}
} else {
+ hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eRender,
+ DEVICE_STATE_ACTIVE|DEVICE_STATE_UNPLUGGED,
+ &pDevices);
+ EXIT_ON_ERROR(hr);
+
+ int count;
+ IMMDeviceCollection_GetCount(pDevices, &count);
+
mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: finding device %s\n", devid);
for (int i = 0; i < count; i++) {
@@ -766,11 +786,11 @@ static HRESULT find_and_load_device(wasapi_state *state, int devno, char *devid)
SAFE_RELEASE(pDevices, IMMDeviceCollection_Release(pDevices))
if (deviceID == NULL) {
- mp_msg(MSGT_AO, MSGL_ERR, "ao-wasapi: no device to load!\n");
+ hr = E_NOTFOUND;
} else {
mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: loading device %S\n", deviceID);
- hr = IMMDeviceEnumerator_GetDevice(state->pEnumerator, deviceID, &state->pDevice);
+ hr = IMMDeviceEnumerator_GetDevice(pEnumerator, deviceID, ppDevice);
if (FAILED(hr)) {
mp_msg(MSGT_AO, MSGL_ERR, "ao-wasapi: could not load requested device!\n");
@@ -780,22 +800,64 @@ static HRESULT find_and_load_device(wasapi_state *state, int devno, char *devid)
exit_label:
SAFE_RELEASE(pTempDevice, IMMDevice_Release(pTempDevice));
SAFE_RELEASE(pDevices, IMMDeviceCollection_Release(pDevices));
+ SAFE_RELEASE(pEnumerator, IMMDeviceEnumerator_Release(pEnumerator));
return hr;
}
+static int validate_device(const m_option_t *opt, struct bstr name,
+ struct bstr param) {
+ IMMDevice *pDevice = NULL;
+
+ mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: validating device=%s\n", param.start);
+
+ if (bstr_equals0(param, "help")) {
+ enumerate_devices();
+ return M_OPT_EXIT;
+ }
+
+ CoInitialize(NULL);
+
+ int devno = -1;
+ char *devid = NULL;
+
+ if (bstr_startswith0(param, "{")) { // ID as printed by enumerate_devices
+ devid = param.start;
+ } else {
+ unsigned char *end;
+ devno = (int) strtol(param.start, (char**)&end, 10);
+ if (end == param.start || *end || devno < 0) {
+ mp_msg(MSGT_AO, MSGL_ERR, "ao-wasapi: invalid number \"%s\"!\n", param.start);
+ return M_OPT_INVALID;
+ }
+ }
+ int ret = 1;
+ if (FAILED(find_and_load_device(&pDevice, devno, devid))) {
+ ret = M_OPT_OUT_OF_RANGE;
+ }
+ mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: device=%s %svalid\n",
+ param.start, ret == 1 ? "" : "not ");
+
+ SAFE_RELEASE(pDevice, IMMDevice_Release(pDevice));
+ CoUninitialize();
+ return ret;
+}
+
static int thread_init(struct ao *ao)
{
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
HRESULT hr;
CoInitialize(NULL);
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
- &IID_IMMDeviceEnumerator, (void **)&state->pEnumerator);
- EXIT_ON_ERROR(hr)
if (!state->opt_device) {
- hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(state->pEnumerator,
+ 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_msg(MSGT_AO, MSGL_V, "ao-wasapi: default device ID: %s\n", id);
@@ -815,7 +877,7 @@ static int thread_init(struct ao *ao)
goto exit_label;
}
}
- hr = find_and_load_device(state, devno, devid);
+ hr = find_and_load_device(&state->pDevice, devno, devid);
}
EXIT_ON_ERROR(hr)
@@ -955,8 +1017,6 @@ static void thread_uninit(wasapi_state *state)
IAudioRenderClient_Release(state->pRenderClient);
if (state->pAudioClient)
IAudioClient_Release(state->pAudioClient);
- if (state->pEnumerator)
- IMMDeviceEnumerator_Release(state->pEnumerator);
if (state->pDevice)
IMMDevice_Release(state->pDevice);
if (state->hTask)
@@ -1247,7 +1307,7 @@ const struct ao_driver audio_out_wasapi = {
.options = (const struct m_option[]) {
OPT_FLAG("exclusive", opt_exclusive, 0),
OPT_FLAG("list", opt_list, 0),
- OPT_STRING("device", opt_device, 0),
+ OPT_STRING_VALIDATE("device", opt_device, 0, validate_device),
{NULL},
},
};