From c5012946ee8273cb1c2879c9299e5959e7766ffc Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Tue, 11 Mar 2014 03:46:22 -0300 Subject: ao_wasapi: Implement AOCONTROL_UPDATE_STREAM_TITLE --- audio/out/ao_wasapi.c | 30 +++++++++++++++ audio/out/ao_wasapi.h | 4 ++ audio/out/ao_wasapi_utils.c | 89 ++++++++++++++++++++++++++++----------------- 3 files changed, 89 insertions(+), 34 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index ec04cedcd6..2353fc4cc2 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -233,6 +233,16 @@ static int init(struct ao *ao) return state->init_ret; } +static wchar_t* utf8_to_wstring(char *string) { + if (string) { + int len = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); + wchar_t *ret = malloc(len * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, string, -1, ret, len); + return ret; + } + return NULL; +} + static int control(struct ao *ao, enum aocontrol cmd, void *arg) { struct wasapi_state *state = (struct wasapi_state *)ao->priv; @@ -285,6 +295,26 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) ISimpleAudioVolume_SetMute(state->pAudioVolumeProxy, mute, NULL); return CONTROL_OK; + case AOCONTROL_UPDATE_STREAM_TITLE: { + MP_VERBOSE(state, "Updating stream title to \"%s\"\n", (char*)arg); + wchar_t *title = utf8_to_wstring((char*)arg); + + wchar_t *tmp = NULL; + + /* There is a weird race condition in the IAudioSessionControl itself -- + it seems that *sometimes* the SetDisplayName does not take effect and it still shows + the old title. Use this loop to insist until it works. */ + do { + IAudioSessionControl_SetDisplayName(state->pSessionControlProxy, title, NULL); + + SAFE_RELEASE(tmp, CoTaskMemFree(tmp)); + IAudioSessionControl_GetDisplayName(state->pSessionControlProxy, &tmp); + } while (lstrcmpW(title, tmp)); + SAFE_RELEASE(tmp, CoTaskMemFree(tmp)); + free(title); + + return CONTROL_OK; + } default: return CONTROL_UNKNOWN; } diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index d17b2504a0..4fe80a6c8f 100755 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -24,6 +24,7 @@ #define _WIN32_WINNT 0x600 #include +#include #include #include @@ -58,6 +59,7 @@ typedef struct wasapi_state { IAudioRenderClient *pRenderClient; ISimpleAudioVolume *pAudioVolume; IAudioEndpointVolume *pEndpointVolume; + IAudioSessionControl *pSessionControl; HANDLE hFeed; /* wasapi event */ HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */ HANDLE hFeedDone; /* set only after a hForceFeed */ @@ -70,6 +72,7 @@ typedef struct wasapi_state { IAudioClient *pAudioClientProxy; ISimpleAudioVolume *pAudioVolumeProxy; IAudioEndpointVolume *pEndpointVolumeProxy; + IAudioSessionControl *pSessionControlProxy; /* 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 @@ -77,6 +80,7 @@ typedef struct wasapi_state { IStream *sAudioClient; IStream *sAudioVolume; IStream *sEndpointVolume; + IStream *sSessionControl; /* WASAPI internal clock information, for estimating delay */ IAudioClock *pAudioClock; diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index f5336cbebf..7baf169c32 100755 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -30,6 +30,8 @@ #include "audio/format.h" +#define MIXER_DEFAULT_LABEL L"mpv - video player" + #define EXIT_ON_ERROR(hres) \ do { if (FAILED(hres)) { goto exit_label; } } while(0) #define SAFE_RELEASE(unk, release) \ @@ -464,6 +466,31 @@ exit_label: return 1; } +static int init_session_display(struct wasapi_state *state) { + HRESULT hr; + wchar_t path[MAX_PATH+12] = {0}; + + hr = IAudioClient_GetService(state->pAudioClient, + &IID_IAudioSessionControl, + (void **) &state->pSessionControl); + EXIT_ON_ERROR(hr); + + GetModuleFileNameW(NULL, path, MAX_PATH); + lstrcatW(path, L",-IDI_ICON1"); + + hr = IAudioSessionControl_SetDisplayName(state->pSessionControl, MIXER_DEFAULT_LABEL, NULL); + EXIT_ON_ERROR(hr); + hr = IAudioSessionControl_SetIconPath(state->pSessionControl, path, NULL); + EXIT_ON_ERROR(hr); + + return 0; + +exit_label: + MP_ERR(state, "init_session_display failed with %s.\n", + wasapi_explain_err(hr)); + return 1; +} + static int fix_format(struct wasapi_state *state) { HRESULT hr; @@ -524,6 +551,8 @@ reinit: if (init_clock(state)) return 1; + if (init_session_display(state)) + return 1; state->hTask = state->VistaBlob.pAvSetMmThreadCharacteristicsW(L"Pro Audio", &state->taskIndex); @@ -865,23 +894,18 @@ HRESULT wasapi_setup_proxies(struct wasapi_state *state) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - hr = CoGetInterfaceAndReleaseStream(state->sAudioClient, - &IID_IAudioClient, - (void**) &state->pAudioClientProxy); - state->sAudioClient = NULL; - EXIT_ON_ERROR(hr); +#define UNMARSHAL(type, to, from) do { \ + hr = CoGetInterfaceAndReleaseStream((from), &(type), (void**) &(to)); \ + (from) = NULL; \ + EXIT_ON_ERROR(hr); \ +} while (0) - hr = CoGetInterfaceAndReleaseStream(state->sAudioVolume, - &IID_ISimpleAudioVolume, - (void**) &state->pAudioVolumeProxy); - state->sAudioVolume = NULL; - EXIT_ON_ERROR(hr); + UNMARSHAL(IID_IAudioClient, state->pAudioClientProxy, state->sAudioClient); + UNMARSHAL(IID_ISimpleAudioVolume, state->pAudioVolumeProxy, state->sAudioVolume); + UNMARSHAL(IID_IAudioEndpointVolume, state->pEndpointVolumeProxy, state->sEndpointVolume); + UNMARSHAL(IID_IAudioSessionControl, state->pSessionControlProxy, state->sSessionControl); - hr = CoGetInterfaceAndReleaseStream(state->sEndpointVolume, - &IID_IAudioEndpointVolume, - (void**) &state->pEndpointVolumeProxy); - state->sEndpointVolume = NULL; - EXIT_ON_ERROR(hr); +#undef UNMARSHAL exit_label: if (hr != S_OK) { @@ -891,9 +915,10 @@ exit_label: } void wasapi_release_proxies(wasapi_state *state) { - SAFE_RELEASE(state->pAudioClientProxy, IUnknown_Release(state->pAudioClientProxy)); - SAFE_RELEASE(state->pAudioVolumeProxy, IUnknown_Release(state->pAudioVolumeProxy)); + SAFE_RELEASE(state->pAudioClientProxy, IUnknown_Release(state->pAudioClientProxy)); + SAFE_RELEASE(state->pAudioVolumeProxy, IUnknown_Release(state->pAudioVolumeProxy)); SAFE_RELEASE(state->pEndpointVolumeProxy, IUnknown_Release(state->pEndpointVolumeProxy)); + SAFE_RELEASE(state->pSessionControlProxy, IUnknown_Release(state->pSessionControlProxy)); CoUninitialize(); } @@ -901,25 +926,20 @@ void wasapi_release_proxies(wasapi_state *state) { 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); +#define MARSHAL(type, to, from) do { \ + hr = CreateStreamOnHGlobal(NULL, TRUE, &(to)); \ + EXIT_ON_ERROR(hr); \ + hr = CoMarshalInterThreadInterfaceInStream(&(type), \ + (IUnknown*) (from), \ + &(to)); \ + EXIT_ON_ERROR(hr); \ +} while (0) - hr = CreateStreamOnHGlobal(NULL, TRUE, &state->sAudioVolume); - EXIT_ON_ERROR(hr); - hr = CoMarshalInterThreadInterfaceInStream(&IID_ISimpleAudioVolume, - (IUnknown*) state->pAudioVolume, - &state->sAudioVolume); - EXIT_ON_ERROR(hr); + MARSHAL(IID_IAudioClient, state->sAudioClient, state->pAudioClient); + MARSHAL(IID_ISimpleAudioVolume, state->sAudioVolume, state->pAudioVolume); + MARSHAL(IID_IAudioEndpointVolume, state->sEndpointVolume, state->pEndpointVolume); + MARSHAL(IID_IAudioSessionControl, state->sSessionControl, state->pSessionControl); - hr = CreateStreamOnHGlobal(NULL, TRUE, &state->sEndpointVolume); - EXIT_ON_ERROR(hr); - hr = CoMarshalInterThreadInterfaceInStream(&IID_IAudioEndpointVolume, - (IUnknown*) state->pEndpointVolume, - &state->sEndpointVolume); exit_label: return hr; } @@ -1002,6 +1022,7 @@ void wasapi_thread_uninit(wasapi_state *state) SAFE_RELEASE(state->pAudioClock, IAudioClock_Release(state->pAudioClock)); SAFE_RELEASE(state->pAudioVolume, ISimpleAudioVolume_Release(state->pAudioVolume)); SAFE_RELEASE(state->pEndpointVolume, IAudioEndpointVolume_Release(state->pEndpointVolume)); + SAFE_RELEASE(state->pSessionControl, IAudioSessionControl_Release(state->pSessionControl)); SAFE_RELEASE(state->pAudioClient, IAudioClient_Release(state->pAudioClient)); SAFE_RELEASE(state->pDevice, IMMDevice_Release(state->pDevice)); -- cgit v1.2.3