[vlc-commits] mmdevice: implement audio policy callback (fixes #7204)

Rémi Denis-Courmont git at videolan.org
Sun Mar 2 14:22:34 CET 2014


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Mar  2 15:20:26 2014 +0200| [508d92f2f8168ac9def51eea59f133af50352d07] | committer: Rémi Denis-Courmont

mmdevice: implement audio policy callback (fixes #7204)

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=508d92f2f8168ac9def51eea59f133af50352d07
---

 modules/audio_output/mmdevice.c |  122 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 121 insertions(+), 1 deletion(-)

diff --git a/modules/audio_output/mmdevice.c b/modules/audio_output/mmdevice.c
index ec44c5c..6735cec 100644
--- a/modules/audio_output/mmdevice.c
+++ b/modules/audio_output/mmdevice.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * mmdevice.c : Windows Multimedia Device API audio output plugin for VLC
  *****************************************************************************
- * Copyright (C) 2012-2013 Rémi Denis-Courmont
+ * Copyright (C) 2012-2014 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
@@ -114,8 +114,10 @@ struct aout_sys_t
     struct IMMNotificationClient device_events;
     struct IAudioEndpointVolumeCallback endpoint_callback;
     struct IAudioSessionEvents session_events;
+    struct IAudioVolumeDuckNotification duck;
 
     LONG refs;
+    unsigned ducks;
 
     wchar_t *device; /**< Requested device identifier, NULL if none */
     float volume; /**< Requested volume, negative if none */
@@ -385,6 +387,79 @@ static const struct IAudioSessionEventsVtbl vlc_AudioSessionEvents =
     vlc_AudioSessionEvents_OnSessionDisconnected,
 };
 
+static inline aout_sys_t *vlc_AudioVolumeDuckNotification_sys(IAudioVolumeDuckNotification *this)
+{
+    return (void *)(((char *)this) - offsetof(aout_sys_t, duck));
+}
+
+static STDMETHODIMP
+vlc_AudioVolumeDuckNotification_QueryInterface(
+    IAudioVolumeDuckNotification *this, REFIID riid, void **ppv)
+{
+    if (IsEqualIID(riid, &IID_IUnknown)
+     || IsEqualIID(riid, &IID_IAudioVolumeDuckNotification))
+    {
+        *ppv = this;
+        IUnknown_AddRef(this);
+        return S_OK;
+    }
+    else
+    {
+       *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+}
+
+static STDMETHODIMP_(ULONG)
+vlc_AudioVolumeDuckNotification_AddRef(IAudioVolumeDuckNotification *this)
+{
+    aout_sys_t *sys = vlc_AudioVolumeDuckNotification_sys(this);
+    return InterlockedIncrement(&sys->refs);
+}
+
+static STDMETHODIMP_(ULONG)
+vlc_AudioVolumeDuckNotification_Release(IAudioVolumeDuckNotification *this)
+{
+    aout_sys_t *sys = vlc_AudioVolumeDuckNotification_sys(this);
+    return InterlockedDecrement(&sys->refs);
+}
+
+static STDMETHODIMP
+vlc_AudioVolumeDuckNotification_OnVolumeDuckNotification(
+    IAudioVolumeDuckNotification *this, LPCWSTR sid, UINT32 count)
+{
+    aout_sys_t *sys = vlc_AudioVolumeDuckNotification_sys(this);
+    audio_output_t *aout = sys->aout;
+
+    msg_Dbg(aout, "volume ducked by %ls of %u sessions", sid, count);
+    sys->ducks++;
+    aout_PolicyReport(aout, true);
+    return S_OK;
+}
+
+static STDMETHODIMP
+vlc_AudioVolumeDuckNotification_OnVolumeUnduckNotification(
+    IAudioVolumeDuckNotification *this, LPCWSTR sid)
+{
+    aout_sys_t *sys = vlc_AudioVolumeDuckNotification_sys(this);
+    audio_output_t *aout = sys->aout;
+
+    msg_Dbg(aout, "volume unducked by %ls", sid);
+    sys->ducks--;
+    aout_PolicyReport(aout, sys->ducks != 0);
+    return S_OK;
+}
+
+static const struct IAudioVolumeDuckNotificationVtbl vlc_AudioVolumeDuckNotification =
+{
+    vlc_AudioVolumeDuckNotification_QueryInterface,
+    vlc_AudioVolumeDuckNotification_AddRef,
+    vlc_AudioVolumeDuckNotification_Release,
+
+    vlc_AudioVolumeDuckNotification_OnVolumeDuckNotification,
+    vlc_AudioVolumeDuckNotification_OnVolumeUnduckNotification,
+};
+
 
 /*** Audio endpoint volume ***/
 static inline aout_sys_t *vlc_AudioEndpointVolumeCallback_sys(IAudioEndpointVolumeCallback *this)
@@ -843,6 +918,39 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
                                                        &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;
+
+        hr = IAudioSessionManager_QueryInterface(manager,
+                                              &IID_IAudioSessionControl2, &pv);
+        if (SUCCEEDED(hr))
+        {
+            IAudioSessionControl2 *c2 = pv;
+
+            IAudioSessionControl2_SetDuckingPreference(c2, FALSE);
+            hr = IAudioSessionControl2_GetSessionInstanceIdentifier(c2, &siid);
+            if (FAILED(hr))
+                siid = NULL;
+            IAudioSessionControl2_Release(c2);
+        }
+        else
+            msg_Dbg(aout, "version 2 session control unavailable");
+
+        hr = IAudioSessionManager_QueryInterface(manager,
+                                              &IID_IAudioSessionManager2, &pv);
+        if (SUCCEEDED(hr))
+        {
+            IAudioSessionManager2 *m2 = pv;
+
+            IAudioSessionManager2_RegisterDuckNotification(m2, siid,
+                                                           &sys->duck);
+            IAudioSessionManager2_Release(m2);
+        }
+        else
+            msg_Dbg(aout, "version 2 session management unavailable");
+
+        CoTaskMemFree(siid);
     }
     else
     {
@@ -976,6 +1084,16 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
 
     if (manager != NULL)
     {   /* Deregister callbacks *without* the lock */
+        hr = IAudioSessionManager_QueryInterface(manager,
+                                              &IID_IAudioSessionManager2, &pv);
+        if (SUCCEEDED(hr))
+        {
+            IAudioSessionManager2 *m2 = pv;
+
+            IAudioSessionManager2_UnregisterDuckNotification(m2, &sys->duck);
+            IAudioSessionManager2_Release(m2);
+        }
+
         if (volume != NULL)
             ISimpleAudioVolume_Release(volume);
 
@@ -1121,7 +1239,9 @@ static int Open(vlc_object_t *obj)
     sys->device_events.lpVtbl = &vlc_MMNotificationClient;
     sys->endpoint_callback.lpVtbl = &vlc_AudioEndpointVolumeCallback;
     sys->session_events.lpVtbl = &vlc_AudioSessionEvents;
+    sys->duck.lpVtbl = &vlc_AudioVolumeDuckNotification;
     sys->refs = 1;
+    sys->ducks = 0;
 
     sys->device = default_device;
     sys->volume = -1.f;



More information about the vlc-commits mailing list