mirror of https://code.videolan.org/videolan/vlc
Merge branch 'mmdevice/vol-per-player' into 'master'
mmdevice: allow to set the volume per player rather than per session See merge request videolan/vlc!3599
This commit is contained in:
commit
b4adbe481e
|
@ -83,7 +83,11 @@ if HAVE_JACK
|
|||
aout_LTLIBRARIES += libjack_plugin.la
|
||||
endif
|
||||
|
||||
libmmdevice_plugin_la_SOURCES = audio_output/mmdevice.c audio_output/mmdevice.h
|
||||
libmmdevice_plugin_la_SOURCES = audio_output/mmdevice.c \
|
||||
audio_output/mmdevice.h \
|
||||
audio_output/mmdevice_volume_control.h \
|
||||
audio_output/mmdevice_session_volume.c \
|
||||
audio_output/mmdevice_player_volume.c
|
||||
libmmdevice_plugin_la_LIBADD = $(LIBCOM) $(LIBM)
|
||||
libwinstore_plugin_la_SOURCES = audio_output/winstore.c audio_output/mmdevice.h
|
||||
libwinstore_plugin_la_LIBADD = $(LIBCOM) -lmmdevapi
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <mmdeviceapi.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include "mmdevice_volume_control.h"
|
||||
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd,
|
||||
0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
|
||||
|
||||
|
@ -89,16 +91,15 @@ typedef struct
|
|||
IMMDevice *dev; /**< Selected output device, NULL if none */
|
||||
|
||||
struct IMMNotificationClient device_events;
|
||||
struct IAudioSessionEvents session_events;
|
||||
struct IAudioVolumeDuckNotification duck;
|
||||
|
||||
float gain;
|
||||
mmdevice_volume_controler_t* volume;
|
||||
|
||||
LONG refs;
|
||||
unsigned ducks;
|
||||
float gain; /**< Current software gain volume */
|
||||
|
||||
wchar_t *requested_device; /**< Requested device identifier, NULL if none */
|
||||
float requested_volume; /**< Requested volume, negative if none */
|
||||
signed char requested_mute; /**< Requested mute, negative if none */
|
||||
wchar_t *acquired_device; /**< Acquired device identifier, NULL if none */
|
||||
bool request_device_restart;
|
||||
HANDLE work_event;
|
||||
|
@ -173,30 +174,20 @@ static void Flush(audio_output_t *aout)
|
|||
static int VolumeSetLocked(audio_output_t *aout, float vol)
|
||||
{
|
||||
aout_sys_t *sys = aout->sys;
|
||||
float gain = 1.f;
|
||||
|
||||
vol = vol * vol * vol; /* ISimpleAudioVolume is tapered linearly. */
|
||||
|
||||
if (vol > 1.f)
|
||||
{
|
||||
gain = vol;
|
||||
vol = 1.f;
|
||||
}
|
||||
|
||||
sys->gain = gain;
|
||||
sys->requested_volume = vol;
|
||||
return 0;
|
||||
return mmdevice_volume_controler_request_volume(sys->volume, vol, &sys->gain);
|
||||
}
|
||||
|
||||
|
||||
static int VolumeSet(audio_output_t *aout, float vol)
|
||||
{
|
||||
aout_sys_t *sys = aout->sys;
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
int ret = VolumeSetLocked(aout, vol);
|
||||
aout_GainRequest(aout, sys->gain);
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
SetEvent(sys->work_event);
|
||||
|
||||
aout_GainRequest(sys->aout, sys->gain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -205,176 +196,11 @@ static int MuteSet(audio_output_t *aout, bool mute)
|
|||
aout_sys_t *sys = aout->sys;
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
sys->requested_mute = mute;
|
||||
int ret = mmdevice_volume_controler_request_mute(sys->volume, mute);
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
SetEvent(sys->work_event);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*** Audio session events ***/
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_QueryInterface(IAudioSessionEvents *this, REFIID riid,
|
||||
void **ppv)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IUnknown)
|
||||
|| IsEqualIID(riid, &IID_IAudioSessionEvents))
|
||||
{
|
||||
*ppv = this;
|
||||
IUnknown_AddRef(this);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG)
|
||||
vlc_AudioSessionEvents_AddRef(IAudioSessionEvents *this)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
return InterlockedIncrement(&sys->refs);
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG)
|
||||
vlc_AudioSessionEvents_Release(IAudioSessionEvents *this)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
return InterlockedDecrement(&sys->refs);
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnDisplayNameChanged(IAudioSessionEvents *this,
|
||||
LPCWSTR wname, LPCGUID ctx)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "display name changed: %ls", wname);
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnIconPathChanged(IAudioSessionEvents *this,
|
||||
LPCWSTR wpath, LPCGUID ctx)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "icon path changed: %ls", wpath);
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnSimpleVolumeChanged(IAudioSessionEvents *this,
|
||||
float vol, BOOL mute,
|
||||
LPCGUID ctx)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "simple volume changed: %f, muting %sabled", vol,
|
||||
mute ? "en" : "dis");
|
||||
SetEvent(sys->work_event); /* implicit state: vol & mute */
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnChannelVolumeChanged(IAudioSessionEvents *this,
|
||||
DWORD count, float *vols,
|
||||
DWORD changed, LPCGUID ctx)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
if (changed != (DWORD)-1)
|
||||
msg_Dbg(aout, "channel volume %lu of %lu changed: %f", changed, count,
|
||||
vols[changed]);
|
||||
else
|
||||
msg_Dbg(aout, "%lu channels volume changed", count);
|
||||
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnGroupingParamChanged(IAudioSessionEvents *this,
|
||||
LPCGUID param, LPCGUID ctx)
|
||||
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "grouping parameter changed");
|
||||
(void) param;
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnStateChanged(IAudioSessionEvents *this,
|
||||
AudioSessionState state)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "state changed: %d", state);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnSessionDisconnected(IAudioSessionEvents *this,
|
||||
AudioSessionDisconnectReason reason)
|
||||
{
|
||||
aout_sys_t *sys = container_of(this, aout_sys_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case DisconnectReasonDeviceRemoval:
|
||||
msg_Warn(aout, "session disconnected: %s", "device removed");
|
||||
break;
|
||||
case DisconnectReasonServerShutdown:
|
||||
msg_Err(aout, "session disconnected: %s", "service stopped");
|
||||
return S_OK;
|
||||
case DisconnectReasonFormatChanged:
|
||||
msg_Warn(aout, "session disconnected: %s", "format changed");
|
||||
break;
|
||||
case DisconnectReasonSessionLogoff:
|
||||
msg_Err(aout, "session disconnected: %s", "user logged off");
|
||||
return S_OK;
|
||||
case DisconnectReasonSessionDisconnected:
|
||||
msg_Err(aout, "session disconnected: %s", "session disconnected");
|
||||
return S_OK;
|
||||
case DisconnectReasonExclusiveModeOverride:
|
||||
msg_Err(aout, "session disconnected: %s", "stream overridden");
|
||||
return S_OK;
|
||||
default:
|
||||
msg_Warn(aout, "session disconnected: unknown reason %d", reason);
|
||||
return S_OK;
|
||||
}
|
||||
/* NOTE: audio decoder thread should get invalidated device and restart */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const struct IAudioSessionEventsVtbl vlc_AudioSessionEvents =
|
||||
{
|
||||
vlc_AudioSessionEvents_QueryInterface,
|
||||
vlc_AudioSessionEvents_AddRef,
|
||||
vlc_AudioSessionEvents_Release,
|
||||
|
||||
vlc_AudioSessionEvents_OnDisplayNameChanged,
|
||||
vlc_AudioSessionEvents_OnIconPathChanged,
|
||||
vlc_AudioSessionEvents_OnSimpleVolumeChanged,
|
||||
vlc_AudioSessionEvents_OnChannelVolumeChanged,
|
||||
vlc_AudioSessionEvents_OnGroupingParamChanged,
|
||||
vlc_AudioSessionEvents_OnStateChanged,
|
||||
vlc_AudioSessionEvents_OnSessionDisconnected,
|
||||
};
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioVolumeDuckNotification_QueryInterface(
|
||||
|
@ -782,61 +608,15 @@ static int DeviceSelect(audio_output_t *aout, const char *id)
|
|||
*
|
||||
* Adjust volume as long as device is unchanged
|
||||
* */
|
||||
static void MMSessionMainloop(audio_output_t *aout, ISimpleAudioVolume *volume)
|
||||
static void MMSessionMainloop(audio_output_t *aout)
|
||||
{
|
||||
aout_sys_t *sys = aout->sys;
|
||||
HRESULT hr;
|
||||
|
||||
bool report_volume = true;
|
||||
bool report_mute = true;
|
||||
mmdevice_volume_controler_t* volume = sys->volume;
|
||||
|
||||
while (sys->requested_device == NULL)
|
||||
{
|
||||
if (volume != NULL)
|
||||
{
|
||||
if (sys->requested_volume >= 0.f)
|
||||
{
|
||||
hr = ISimpleAudioVolume_SetMasterVolume(volume, sys->requested_volume, NULL);
|
||||
if (FAILED(hr))
|
||||
msg_Err(aout, "cannot set master volume (error 0x%lX)",
|
||||
hr);
|
||||
report_volume = true;
|
||||
sys->requested_volume = -1.f;
|
||||
}
|
||||
|
||||
if (report_volume)
|
||||
{
|
||||
float level;
|
||||
hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
|
||||
if (SUCCEEDED(hr))
|
||||
aout_VolumeReport(aout, cbrtf(level * sys->gain));
|
||||
else
|
||||
msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
|
||||
report_volume = false;
|
||||
}
|
||||
|
||||
if (sys->requested_mute >= 0)
|
||||
{
|
||||
BOOL mute = sys->requested_mute ? TRUE : FALSE;
|
||||
|
||||
hr = ISimpleAudioVolume_SetMute(volume, mute, NULL);
|
||||
if (FAILED(hr))
|
||||
msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
|
||||
report_mute = true;
|
||||
sys->requested_mute = -1;
|
||||
}
|
||||
|
||||
if (report_mute)
|
||||
{
|
||||
BOOL mute;
|
||||
hr = ISimpleAudioVolume_GetMute(volume, &mute);
|
||||
if (SUCCEEDED(hr))
|
||||
aout_MuteReport(aout, mute != FALSE);
|
||||
else
|
||||
msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
|
||||
report_mute = false;
|
||||
}
|
||||
}
|
||||
mmdevice_volume_controler_process(volume, sys->stream);
|
||||
|
||||
DWORD wait_ms = INFINITE;
|
||||
DWORD ev_count = 1;
|
||||
|
@ -890,7 +670,6 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
aout_sys_t *sys = aout->sys;
|
||||
IAudioSessionManager *manager;
|
||||
IAudioSessionControl *control;
|
||||
ISimpleAudioVolume *volume;
|
||||
IAudioEndpointVolume *endpoint;
|
||||
void *pv;
|
||||
HRESULT hr;
|
||||
|
@ -961,14 +740,14 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
return hr;
|
||||
}
|
||||
|
||||
LPCGUID guid = var_GetBool(aout, "volume-save") ? &GUID_VLC_AUD_OUT : NULL;
|
||||
|
||||
/* Create session manager (for controls even w/o active audio client) */
|
||||
hr = IMMDevice_Activate(sys->dev, &IID_IAudioSessionManager,
|
||||
CLSCTX_ALL, NULL, &pv);
|
||||
manager = pv;
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
LPCGUID guid = var_GetBool(aout, "volume-save") ? &GUID_VLC_AUD_OUT : NULL;
|
||||
|
||||
/* Register session control */
|
||||
hr = IAudioSessionManager_GetAudioSessionControl(manager, guid, 0,
|
||||
&control);
|
||||
|
@ -985,17 +764,12 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
}
|
||||
free(ua);
|
||||
}
|
||||
|
||||
IAudioSessionControl_RegisterAudioSessionNotification(control,
|
||||
&sys->session_events);
|
||||
}
|
||||
else
|
||||
{
|
||||
control = NULL;
|
||||
msg_Err(aout, "cannot get session control (error 0x%lX)", hr);
|
||||
|
||||
hr = IAudioSessionManager_GetSimpleAudioVolume(manager, guid, FALSE,
|
||||
&volume);
|
||||
if (FAILED(hr))
|
||||
msg_Err(aout, "cannot get simple volume (error 0x%lX)", hr);
|
||||
}
|
||||
|
||||
/* Try to get version 2 (Windows 7) of the manager & control */
|
||||
wchar_t *siid = NULL;
|
||||
|
@ -1031,11 +805,9 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
CoTaskMemFree(siid);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg_Err(aout, "cannot activate session manager (error 0x%lX)", hr);
|
||||
control = NULL;
|
||||
volume = NULL;
|
||||
}
|
||||
|
||||
mmdevice_volume_controler_initialize(sys->volume, manager, guid);
|
||||
|
||||
hr = IMMDevice_Activate(sys->dev, &IID_IAudioEndpointVolume,
|
||||
CLSCTX_ALL, NULL, &pv);
|
||||
|
@ -1054,10 +826,14 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
else
|
||||
msg_Err(aout, "cannot activate endpoint volume (error 0x%lX)", hr);
|
||||
|
||||
MMSessionMainloop(aout, volume);
|
||||
MMSessionMainloop(aout);
|
||||
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
|
||||
if (sys->volume)
|
||||
mmdevice_volume_controler_release(sys->volume);
|
||||
sys->volume = NULL;
|
||||
|
||||
if (endpoint != NULL)
|
||||
IAudioEndpointVolume_Release(endpoint);
|
||||
|
||||
|
@ -1073,15 +849,8 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
|
|||
IAudioSessionManager2_Release(m2);
|
||||
}
|
||||
|
||||
if (volume != NULL)
|
||||
ISimpleAudioVolume_Release(volume);
|
||||
|
||||
if (control != NULL)
|
||||
{
|
||||
IAudioSessionControl_UnregisterAudioSessionNotification(control,
|
||||
&sys->session_events);
|
||||
IAudioSessionControl_Release(control);
|
||||
}
|
||||
|
||||
IAudioSessionManager_Release(manager);
|
||||
}
|
||||
|
@ -1330,20 +1099,12 @@ static int Open(vlc_object_t *obj)
|
|||
sys->it = NULL;
|
||||
sys->dev = NULL;
|
||||
sys->device_events.lpVtbl = &vlc_MMNotificationClient;
|
||||
sys->session_events.lpVtbl = &vlc_AudioSessionEvents;
|
||||
sys->duck.lpVtbl = &vlc_AudioVolumeDuckNotification;
|
||||
sys->refs = 1;
|
||||
sys->ducks = 0;
|
||||
|
||||
sys->gain = 1.f;
|
||||
sys->requested_volume = -1.f;
|
||||
sys->requested_mute = -1;
|
||||
sys->acquired_device = NULL;
|
||||
sys->request_device_restart = false;
|
||||
|
||||
if (!var_CreateGetBool(aout, "volume-save"))
|
||||
VolumeSetLocked(aout, var_InheritFloat(aout, "mmdevice-volume"));
|
||||
|
||||
vlc_mutex_init(&sys->lock);
|
||||
vlc_cond_init(&sys->ready);
|
||||
|
||||
|
@ -1351,6 +1112,17 @@ static int Open(vlc_object_t *obj)
|
|||
if (unlikely(sys->work_event == NULL))
|
||||
goto error;
|
||||
|
||||
if (var_InheritBool(aout, "mmdevice-session-volume"))
|
||||
sys->volume = createMMDeviceSessionVolumeControler(aout, sys->work_event);
|
||||
else
|
||||
sys->volume = createMMDevicePlayerVolumeControler(aout, sys->work_event);
|
||||
|
||||
if (unlikely(sys->volume == NULL))
|
||||
goto error;
|
||||
|
||||
if (!var_CreateGetBool(aout, "volume-save"))
|
||||
VolumeSetLocked(aout, var_InheritFloat(aout, "mmdevice-volume"));
|
||||
|
||||
aout_HotplugReport(aout, default_device_b, _("Default"));
|
||||
|
||||
char *saved_device_b = var_InheritString(aout, "mmdevice-audio-device");
|
||||
|
@ -1535,6 +1307,10 @@ static const char *const ppsz_mmdevice_passthrough_texts[] = {
|
|||
#define VOLUME_TEXT N_("Audio volume")
|
||||
#define VOLUME_LONGTEXT N_("Audio volume in hundredths of decibels (dB).")
|
||||
|
||||
|
||||
#define SESSION_VOLUME_TEXT N_("Use session volume")
|
||||
#define SESSION_VOLUME_LONGTEXT N_("Use session volume, or per player volume when disabled")
|
||||
|
||||
vlc_module_begin()
|
||||
set_shortname("MMDevice")
|
||||
set_description(N_("Windows Multimedia Device output"))
|
||||
|
@ -1550,4 +1326,5 @@ vlc_module_begin()
|
|||
add_string("mmdevice-audio-device", NULL, DEVICE_TEXT, DEVICE_LONGTEXT)
|
||||
add_float("mmdevice-volume", 1.f, VOLUME_TEXT, VOLUME_LONGTEXT)
|
||||
change_float_range( 0.f, 1.25f )
|
||||
add_bool("mmdevice-session-volume", true, SESSION_VOLUME_TEXT, SESSION_VOLUME_LONGTEXT)
|
||||
vlc_module_end()
|
||||
|
|
|
@ -40,6 +40,7 @@ struct aout_stream
|
|||
HRESULT (*play)(aout_stream_t *, block_t *, vlc_tick_t);
|
||||
HRESULT (*pause)(aout_stream_t *, bool);
|
||||
HRESULT (*flush)(aout_stream_t *);
|
||||
HRESULT (*getservice)(aout_stream_t *, REFIID riid, void **ppv);
|
||||
};
|
||||
|
||||
struct aout_stream_owner
|
||||
|
@ -110,6 +111,12 @@ HRESULT aout_stream_owner_Flush(struct aout_stream_owner *owner)
|
|||
return owner->s.flush(&owner->s);
|
||||
}
|
||||
|
||||
static inline HRESULT aout_stream_GetService(struct aout_stream_owner *owner,
|
||||
REFIID riid, void **ppv)
|
||||
{
|
||||
return owner->s.getservice(&owner->s, riid, ppv);
|
||||
}
|
||||
|
||||
static inline
|
||||
void aout_stream_owner_AppendBlock(struct aout_stream_owner *owner,
|
||||
block_t *block, vlc_tick_t date)
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2012-2023 VLC authors and VideoLAN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "mmdevice_volume_control.h"
|
||||
#include <vlc_aout.h>
|
||||
#include "mmdevice.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mmdevice_volume_controler_t iface;
|
||||
|
||||
audio_output_t *aout;
|
||||
|
||||
float requested_volume; /**< volume */
|
||||
signed char requested_mute; /**< mute */
|
||||
|
||||
bool report_mute;
|
||||
bool report_volume;
|
||||
|
||||
float volume;
|
||||
float gain; /**< gain */
|
||||
|
||||
HANDLE work_event;
|
||||
|
||||
} mmdevice_player_volume_controler_t;
|
||||
|
||||
#define VOLUME_CONTROL_IMPL_FROM_IFACE(obj) \
|
||||
container_of((obj), mmdevice_player_volume_controler_t, iface)
|
||||
|
||||
static int RequestMute(mmdevice_volume_controler_t* controler, bool mute)
|
||||
{
|
||||
mmdevice_player_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
sys->requested_mute = mute;
|
||||
SetEvent(sys->work_event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RequestVolume(mmdevice_volume_controler_t* controler, float value, float* outGain)
|
||||
{
|
||||
mmdevice_player_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
|
||||
float gain = 1.f;
|
||||
|
||||
value = value * value * value; /* ISimpleAudioVolume is tapered linearly. */
|
||||
|
||||
if (value > 1.f)
|
||||
{
|
||||
gain = value;
|
||||
value = 1.f;
|
||||
}
|
||||
|
||||
sys->requested_volume = value;
|
||||
sys->gain =gain;
|
||||
if (outGain != NULL)
|
||||
*outGain = gain;
|
||||
SetEvent(sys->work_event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetAllStreamVolume(IAudioStreamVolume *stream_volume, UINT32 chan_count, float volume)
|
||||
{
|
||||
float chan_volumes[chan_count];
|
||||
for (UINT32 i = 0; i < chan_count; ++i)
|
||||
chan_volumes[i] = volume;
|
||||
IAudioStreamVolume_SetAllVolumes(stream_volume, chan_count, chan_volumes);
|
||||
}
|
||||
|
||||
static void Process(mmdevice_volume_controler_t* controler, struct aout_stream_owner *stream)
|
||||
{
|
||||
mmdevice_player_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
|
||||
if (!stream
|
||||
|| (sys->requested_mute < 0 && sys->requested_volume < 0))
|
||||
return;
|
||||
|
||||
IAudioStreamVolume *stream_volume = NULL;
|
||||
|
||||
void* pv;
|
||||
HRESULT hr = aout_stream_GetService(stream, &IID_IAudioStreamVolume, &pv);
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
stream_volume = pv;
|
||||
|
||||
UINT32 chan_count;
|
||||
hr = IAudioStreamVolume_GetChannelCount(stream_volume, &chan_count);
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
assert(chan_count <= 64);
|
||||
|
||||
if (chan_count == 0)
|
||||
goto error;
|
||||
|
||||
if (sys->requested_mute >= 0)
|
||||
{
|
||||
if (sys->requested_mute)
|
||||
SetAllStreamVolume(stream_volume, chan_count, 0.f);
|
||||
else
|
||||
SetAllStreamVolume(stream_volume, chan_count, sys->volume);
|
||||
|
||||
sys->report_mute = true;
|
||||
sys->requested_mute = -1;
|
||||
}
|
||||
|
||||
if (sys->requested_volume >= 0.f)
|
||||
{
|
||||
SetAllStreamVolume(stream_volume, chan_count, sys->requested_volume);
|
||||
|
||||
sys->volume = sys->requested_volume;
|
||||
sys->report_volume = true;
|
||||
sys->requested_volume = -1.f;
|
||||
}
|
||||
|
||||
float currentVolume;
|
||||
hr = IAudioStreamVolume_GetChannelVolume(stream_volume, 0,
|
||||
¤tVolume);
|
||||
if (FAILED(hr))
|
||||
goto error;
|
||||
|
||||
if (sys->report_mute)
|
||||
{
|
||||
aout_MuteReport(sys->aout, currentVolume == 0.f);
|
||||
sys->report_mute =false;
|
||||
}
|
||||
|
||||
if (sys->report_volume)
|
||||
{
|
||||
aout_VolumeReport(sys->aout, cbrtf(currentVolume * sys->gain));
|
||||
sys->report_volume =false;
|
||||
}
|
||||
|
||||
error:
|
||||
if (stream_volume)
|
||||
IAudioStreamVolume_Release(stream_volume);
|
||||
|
||||
}
|
||||
|
||||
static bool Initialize(struct mmdevice_volume_controler_t* controler, IAudioSessionManager *manager, LPCGUID guid)
|
||||
{
|
||||
VLC_UNUSED(controler);
|
||||
VLC_UNUSED(manager);
|
||||
VLC_UNUSED(guid);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void Release(mmdevice_volume_controler_t* controler)
|
||||
{
|
||||
mmdevice_player_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
free(sys);
|
||||
}
|
||||
|
||||
mmdevice_volume_controler_t* createMMDevicePlayerVolumeControler(audio_output_t *aout, HANDLE work_event)
|
||||
{
|
||||
mmdevice_player_volume_controler_t* sys = malloc(sizeof(mmdevice_player_volume_controler_t));
|
||||
if (!sys)
|
||||
return NULL;
|
||||
|
||||
sys->aout = aout;
|
||||
|
||||
sys->requested_mute = -1;
|
||||
sys->requested_volume = -1.f;
|
||||
//report initial volume and mute state
|
||||
sys->report_mute = true;
|
||||
sys->report_volume = true;
|
||||
|
||||
sys->volume = 1.f;
|
||||
sys->gain = 1.f;
|
||||
sys->work_event = work_event;
|
||||
|
||||
sys->iface.release = Release;
|
||||
|
||||
sys->iface.initialize = Initialize;
|
||||
sys->iface.process = Process;
|
||||
|
||||
sys->iface.requestMute = RequestMute;
|
||||
sys->iface.requestVolume = RequestVolume;
|
||||
|
||||
return &sys->iface;
|
||||
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
/*****************************************************************************
|
||||
* mmdevice_session_volume.c : Windows Multimedia Device API audio output plugin for VLC
|
||||
*****************************************************************************
|
||||
* Copyright (C) 2012-2017 Rémi Denis-Courmont
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "mmdevice_volume_control.h"
|
||||
|
||||
#include <vlc_aout.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mmdevice_volume_controler_t iface;
|
||||
|
||||
audio_output_t *aout;
|
||||
struct IAudioSessionEvents session_events;
|
||||
ISimpleAudioVolume *volume;
|
||||
IAudioSessionControl *control;
|
||||
LONG refs;
|
||||
HANDLE work_event;
|
||||
vlc_mutex_t lock;
|
||||
|
||||
float gain; /**< Current software gain volume */
|
||||
bool report_volume;
|
||||
bool report_mute;
|
||||
float requested_volume; /**< Requested volume, negative if none */
|
||||
signed char requested_mute; /**< Requested mute, negative if none */
|
||||
|
||||
|
||||
} mmdevice_session_volume_controler_t;
|
||||
|
||||
#define VOLUME_CONTROL_IMPL_FROM_IFACE(obj) \
|
||||
container_of((obj), mmdevice_session_volume_controler_t, iface)
|
||||
|
||||
/*** Audio session events ***/
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_QueryInterface(IAudioSessionEvents *this, REFIID riid,
|
||||
void **ppv)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IUnknown)
|
||||
|| IsEqualIID(riid, &IID_IAudioSessionEvents))
|
||||
{
|
||||
*ppv = this;
|
||||
IUnknown_AddRef(this);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG)
|
||||
vlc_AudioSessionEvents_AddRef(IAudioSessionEvents *this)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
return InterlockedIncrement(&sys->refs);
|
||||
}
|
||||
|
||||
static STDMETHODIMP_(ULONG)
|
||||
vlc_AudioSessionEvents_Release(IAudioSessionEvents *this)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
return InterlockedDecrement(&sys->refs);
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnDisplayNameChanged(IAudioSessionEvents *this,
|
||||
LPCWSTR wname, LPCGUID ctx)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "display name changed: %ls", wname);
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnIconPathChanged(IAudioSessionEvents *this,
|
||||
LPCWSTR wpath, LPCGUID ctx)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "icon path changed: %ls", wpath);
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnSimpleVolumeChanged(IAudioSessionEvents *this,
|
||||
float vol, BOOL mute,
|
||||
LPCGUID ctx)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "simple volume changed: %f, muting %sabled", vol,
|
||||
mute ? "en" : "dis");
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
sys->report_volume = true;
|
||||
sys->report_mute = true;
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
SetEvent(sys->work_event);
|
||||
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnChannelVolumeChanged(IAudioSessionEvents *this,
|
||||
DWORD count, float *vols,
|
||||
DWORD changed, LPCGUID ctx)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
if (changed != (DWORD)-1)
|
||||
msg_Dbg(aout, "channel volume %lu of %lu changed: %f", changed, count,
|
||||
vols[changed]);
|
||||
else
|
||||
msg_Dbg(aout, "%lu channels volume changed", count);
|
||||
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnGroupingParamChanged(IAudioSessionEvents *this,
|
||||
LPCGUID param, LPCGUID ctx)
|
||||
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "grouping parameter changed");
|
||||
(void) param;
|
||||
(void) ctx;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnStateChanged(IAudioSessionEvents *this,
|
||||
AudioSessionState state)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
msg_Dbg(aout, "state changed: %d", state);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static STDMETHODIMP
|
||||
vlc_AudioSessionEvents_OnSessionDisconnected(IAudioSessionEvents *this,
|
||||
AudioSessionDisconnectReason reason)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = container_of(this, mmdevice_session_volume_controler_t, session_events);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case DisconnectReasonDeviceRemoval:
|
||||
msg_Warn(aout, "session disconnected: %s", "device removed");
|
||||
break;
|
||||
case DisconnectReasonServerShutdown:
|
||||
msg_Err(aout, "session disconnected: %s", "service stopped");
|
||||
return S_OK;
|
||||
case DisconnectReasonFormatChanged:
|
||||
msg_Warn(aout, "session disconnected: %s", "format changed");
|
||||
break;
|
||||
case DisconnectReasonSessionLogoff:
|
||||
msg_Err(aout, "session disconnected: %s", "user logged off");
|
||||
return S_OK;
|
||||
case DisconnectReasonSessionDisconnected:
|
||||
msg_Err(aout, "session disconnected: %s", "session disconnected");
|
||||
return S_OK;
|
||||
case DisconnectReasonExclusiveModeOverride:
|
||||
msg_Err(aout, "session disconnected: %s", "stream overridden");
|
||||
return S_OK;
|
||||
default:
|
||||
msg_Warn(aout, "session disconnected: unknown reason %d", reason);
|
||||
return S_OK;
|
||||
}
|
||||
/* NOTE: audio decoder thread should get invalidated device and restart */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const struct IAudioSessionEventsVtbl vlc_AudioSessionEvents =
|
||||
{
|
||||
vlc_AudioSessionEvents_QueryInterface,
|
||||
vlc_AudioSessionEvents_AddRef,
|
||||
vlc_AudioSessionEvents_Release,
|
||||
|
||||
vlc_AudioSessionEvents_OnDisplayNameChanged,
|
||||
vlc_AudioSessionEvents_OnIconPathChanged,
|
||||
vlc_AudioSessionEvents_OnSimpleVolumeChanged,
|
||||
vlc_AudioSessionEvents_OnChannelVolumeChanged,
|
||||
vlc_AudioSessionEvents_OnGroupingParamChanged,
|
||||
vlc_AudioSessionEvents_OnStateChanged,
|
||||
vlc_AudioSessionEvents_OnSessionDisconnected,
|
||||
};
|
||||
|
||||
static void Process(mmdevice_volume_controler_t *controler, struct aout_stream_owner * stream)
|
||||
{
|
||||
VLC_UNUSED(stream);
|
||||
HRESULT hr;
|
||||
mmdevice_session_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
audio_output_t *aout = sys->aout;
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
|
||||
if (sys->requested_volume >= 0.f)
|
||||
{
|
||||
hr = ISimpleAudioVolume_SetMasterVolume(sys->volume, sys->requested_volume, NULL);
|
||||
if (FAILED(hr))
|
||||
msg_Err(aout, "cannot set master volume (error 0x%lX)", hr);
|
||||
sys->requested_volume = -1.f;
|
||||
}
|
||||
|
||||
|
||||
if (sys->report_volume)
|
||||
{
|
||||
float level;
|
||||
hr = ISimpleAudioVolume_GetMasterVolume(sys->volume, &level);
|
||||
if (SUCCEEDED(hr))
|
||||
aout_VolumeReport(aout, cbrtf(level * sys->gain));
|
||||
else
|
||||
msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
|
||||
|
||||
sys->report_volume = false;
|
||||
}
|
||||
|
||||
if (sys->requested_mute >= 0)
|
||||
{
|
||||
BOOL mute = sys->requested_mute ? TRUE : FALSE;
|
||||
|
||||
hr = ISimpleAudioVolume_SetMute(sys->volume, mute, NULL);
|
||||
if (FAILED(hr))
|
||||
msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
|
||||
sys->requested_mute = -1;
|
||||
}
|
||||
|
||||
if (sys->report_mute)
|
||||
{
|
||||
BOOL mute;
|
||||
hr = ISimpleAudioVolume_GetMute(sys->volume, &mute);
|
||||
if (SUCCEEDED(hr))
|
||||
aout_MuteReport(aout, mute != FALSE);
|
||||
else
|
||||
msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
|
||||
|
||||
sys->report_mute = false;
|
||||
}
|
||||
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
}
|
||||
|
||||
static int RequestMute(mmdevice_volume_controler_t *controler, bool mute)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
{
|
||||
sys->requested_mute = mute;
|
||||
sys->report_mute = true;
|
||||
}
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
|
||||
SetEvent(sys->work_event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int RequestVolume(mmdevice_volume_controler_t *controler, float vol, float* outGain)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
|
||||
float gain = 1.f;
|
||||
|
||||
vol = vol * vol * vol; /* ISimpleAudioVolume is tapered linearly. */
|
||||
|
||||
if (vol > 1.f)
|
||||
{
|
||||
gain = vol;
|
||||
vol = 1.f;
|
||||
}
|
||||
|
||||
vlc_mutex_lock(&sys->lock);
|
||||
{
|
||||
sys->requested_volume = vol;
|
||||
sys->report_volume = true;
|
||||
sys->gain =gain;
|
||||
}
|
||||
vlc_mutex_unlock(&sys->lock);
|
||||
|
||||
if (outGain != NULL)
|
||||
*outGain = gain;
|
||||
SetEvent(sys->work_event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Release(mmdevice_volume_controler_t *controler)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
if (!sys)
|
||||
return;
|
||||
|
||||
if (sys->volume != NULL)
|
||||
ISimpleAudioVolume_Release(sys->volume);
|
||||
|
||||
if (sys->control)
|
||||
{
|
||||
IAudioSessionControl_UnregisterAudioSessionNotification(sys->control,
|
||||
&sys->session_events);
|
||||
IAudioSessionControl_Release(sys->control);
|
||||
}
|
||||
|
||||
free(sys);
|
||||
}
|
||||
|
||||
static bool Initialize(struct mmdevice_volume_controler_t* controler, IAudioSessionManager *manager, LPCGUID guid)
|
||||
{
|
||||
mmdevice_session_volume_controler_t *sys = VOLUME_CONTROL_IMPL_FROM_IFACE(controler);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
IAudioSessionControl *control;
|
||||
hr = IAudioSessionManager_GetAudioSessionControl(manager, guid, 0,
|
||||
&control);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
sys->control = control;
|
||||
|
||||
IAudioSessionControl_RegisterAudioSessionNotification(control,
|
||||
&sys->session_events);
|
||||
|
||||
|
||||
hr = IAudioSessionManager_GetSimpleAudioVolume(manager, guid, FALSE,
|
||||
&sys->volume);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
msg_Err(sys->aout, "cannot get simple volume (error 0x%lx)", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mmdevice_volume_controler_t* createMMDeviceSessionVolumeControler(audio_output_t *aout, HANDLE workevent)
|
||||
{
|
||||
|
||||
mmdevice_session_volume_controler_t* sys = malloc(sizeof(mmdevice_session_volume_controler_t));
|
||||
if (!sys)
|
||||
return NULL;
|
||||
|
||||
sys->aout = aout;
|
||||
sys->refs = 1;
|
||||
sys->volume = NULL;
|
||||
sys->control = NULL;
|
||||
sys->gain = 1.f;
|
||||
sys->work_event = workevent;
|
||||
vlc_mutex_init(&sys->lock);
|
||||
|
||||
sys->report_volume = true;
|
||||
sys->report_mute = true;
|
||||
sys->requested_volume = -1.f;
|
||||
sys->requested_mute = -1;
|
||||
|
||||
sys->session_events.lpVtbl = &vlc_AudioSessionEvents;
|
||||
|
||||
sys->iface.release = Release;
|
||||
sys->iface.requestMute = RequestMute;
|
||||
sys->iface.requestVolume = RequestVolume;
|
||||
|
||||
sys->iface.initialize = Initialize;
|
||||
sys->iface.process = Process;
|
||||
|
||||
return &sys->iface;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (C) 2012-2023 VLC authors and VideoLAN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MMDEVICE_VOLUME_H
|
||||
#define MMDEVICE_VOLUME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <vlc_common.h>
|
||||
|
||||
#define INITGUID
|
||||
#define COBJMACROS
|
||||
#define CONST_VTABLE
|
||||
|
||||
#include <endpointvolume.h>
|
||||
#include <audiopolicy.h>
|
||||
|
||||
struct aout_stream_owner;
|
||||
|
||||
struct mmdevice_volume_controler_t
|
||||
{
|
||||
void (*release)(struct mmdevice_volume_controler_t* volume);
|
||||
|
||||
int (*requestMute)(struct mmdevice_volume_controler_t* volume, bool mute);
|
||||
int (*requestVolume)(struct mmdevice_volume_controler_t* volume, float vol, float* gain);
|
||||
|
||||
//initialize is called from the MM Thread
|
||||
bool (*initialize)(struct mmdevice_volume_controler_t* volume, IAudioSessionManager *manager, LPCGUID guid);
|
||||
//process is called from the MM Thread
|
||||
void (*process)(struct mmdevice_volume_controler_t* volume, struct aout_stream_owner * stream);
|
||||
};
|
||||
|
||||
typedef struct mmdevice_volume_controler_t mmdevice_volume_controler_t;
|
||||
|
||||
inline static void mmdevice_volume_controler_release(mmdevice_volume_controler_t* controler)
|
||||
{
|
||||
controler->release(controler);
|
||||
}
|
||||
|
||||
inline static int mmdevice_volume_controler_request_mute(mmdevice_volume_controler_t* controler, bool mute)
|
||||
{
|
||||
return controler->requestMute(controler, mute);
|
||||
}
|
||||
|
||||
inline static int mmdevice_volume_controler_request_volume(mmdevice_volume_controler_t* controler, float vol, float* gain)
|
||||
{
|
||||
return controler->requestVolume(controler, vol, gain);
|
||||
}
|
||||
|
||||
inline static bool mmdevice_volume_controler_initialize(mmdevice_volume_controler_t* controler, IAudioSessionManager *manager, LPCGUID guid)
|
||||
{
|
||||
return controler->initialize(controler, manager, guid);
|
||||
}
|
||||
|
||||
inline static void mmdevice_volume_controler_process(mmdevice_volume_controler_t* controler, struct aout_stream_owner * stream)
|
||||
{
|
||||
controler->process(controler, stream);
|
||||
}
|
||||
|
||||
mmdevice_volume_controler_t* createMMDeviceSessionVolumeControler(audio_output_t *aout, HANDLE work_event);
|
||||
|
||||
mmdevice_volume_controler_t* createMMDevicePlayerVolumeControler(audio_output_t *aout, HANDLE work_event);
|
||||
|
||||
#endif /* MMDEVICE_VOLUME_H */
|
|
@ -365,6 +365,12 @@ static HRESULT Flush(aout_stream_t *s)
|
|||
}
|
||||
|
||||
|
||||
static HRESULT GetService(aout_stream_t *s, REFIID riid, void **ppv)
|
||||
{
|
||||
aout_stream_sys_t *sys = s->sys;
|
||||
return IAudioClient_GetService(sys->client, riid, ppv);
|
||||
}
|
||||
|
||||
/*** Initialization / deinitialization **/
|
||||
static const uint32_t chans_out[] = {
|
||||
SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT,
|
||||
|
@ -930,6 +936,7 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
|
|||
s->play = Play;
|
||||
s->pause = Pause;
|
||||
s->flush = Flush;
|
||||
s->getservice = GetService;
|
||||
s->stop = Stop;
|
||||
return S_OK;
|
||||
error:
|
||||
|
|
Loading…
Reference in New Issue