[vlc-devel] [RFC PATCH 1/2] mmdevice: reflect the state of Sndvol slider

Thomas Guillem thomas at gllm.fr
Thu Apr 5 11:24:13 CEST 2018

Lot of confusions when reading the MSDN documentation about volume change.

Cf. "Session Volume Controls" [1], "Audio-Tapered Volume Controls" [2] and
"Endpoint Volume Controls" [3].

By reading the following [1]:

> To produce a linear relationship between perceived loudness and slider
> position, the application must define a nonlinear relationship between the
> volume level v and the slider position.

We can conclude that VLC should use the IAudioEndpointVolume API to control the
volume in an audio-tapered way.

But [3]:

> As a general rule, applications should avoid using the IAudioEndpointVolume
> interface to control the volume levels of shared-mode streams.

And [1]:

> As an option, an application window can display a volume slider. The
> application slider should reflect the state of the corresponding Sndvol
> slider at all times.

> To support this behavior, WASAPI implements the ISimpleAudioVolume interface.
> When the user moves the application slider, the application calls the
> ISimpleAudioVolume::SetMasterVolume method to adjust the session volume level
> accordingly.

This means that our application should use the ISimpleAudioVolume API and have
a linear relation between the slider and the volume API (therefore, we should
remove the vol * vol * vol that this patch is doing).

But [2]:

> The following interfaces use linear-tapered curves for their volume settings:
> ISimpleAudioVolume

So ISimpleAudioVolume is linear-tapered and IAudioEndpointVolume is
audio-tapered. For the user, we would prefer a audio-tapered volume.

Then, we have 4 choices:

 - a/ Keep the code as it is. I don't like it because it doesn't respect the
   Sndvol slider, and the first 60% on the slider doesn't change the loudness
   much (very hard to hear an audible difference with low % values).

 - b/ Do what this patch is doing. the relation between the slider and the
   loudness is still not linear but it respect the Sndvol slider. I tested with
   few samples: changing volume feels way more natural (the loudness change a
   lot between 0 and 50% and much less after 90%).

 - c/ Use IAudioEndpointVolume, but it's not recommended for shared streams as
   it changes the volume for every apps using a shared stream.

 - d/ Keep using ISimpleAudioVolume but with the volume table added from
   Windows XP SP2, cf. [4]. The slider will be linear with the loudness but
   won't respect the Sndvol slider.

[1] https://msdn.microsoft.com/fr-fr/library/windows/desktop/dd316769(v=vs.85).aspx
[2] https://msdn.microsoft.com/fr-fr/library/windows/desktop/dd370798(v=vs.85).aspx
[3] https://msdn.microsoft.com/en-us/library/windows/desktop/dd370839(v=vs.85).aspx
[4] https://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/voltable.docx
 modules/audio_output/mmdevice.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/modules/audio_output/mmdevice.c b/modules/audio_output/mmdevice.c
index c2f190f01f..c8b48fde41 100644
--- a/modules/audio_output/mmdevice.c
+++ b/modules/audio_output/mmdevice.c
@@ -178,15 +178,13 @@ 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;
-    aout_GainRequest(aout, gain);
+    aout_GainRequest(aout, gain * gain * gain);
     sys->gain = gain;
     sys->requested_volume = vol;
@@ -982,7 +980,7 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
             hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
             if (SUCCEEDED(hr))
-                aout_VolumeReport(aout, cbrtf(level * sys->gain));
+                aout_VolumeReport(aout, level * sys->gain);
                 msg_Err(aout, "cannot get master volume (error 0x%lx)", hr);

More information about the vlc-devel mailing list