0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 12:02:23 +02:00

ao_wasapi: Implement AOCONTROL_UPDATE_STREAM_TITLE

This commit is contained in:
Diogo Franco (Kovensky) 2014-03-11 03:46:22 -03:00
parent f8bdada77f
commit c5012946ee
3 changed files with 89 additions and 34 deletions

View File

@ -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;
}

View File

@ -24,6 +24,7 @@
#define _WIN32_WINNT 0x600
#include <audioclient.h>
#include <audiopolicy.h>
#include <mmdeviceapi.h>
#include <avrt.h>
@ -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;

View File

@ -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));