]> code.delx.au - pulseaudio/commitdiff
alsa-mixer: When setting hw volume, always round up with playback and down with capture.
authorColin Guthrie <colin@mageia.org>
Sun, 8 May 2011 11:44:50 +0000 (12:44 +0100)
committerColin Guthrie <colin@mageia.org>
Wed, 22 Jun 2011 21:45:27 +0000 (22:45 +0100)
The previous logic in ade0a6f88464d8aecf83982d400ccfc402341920
does not work with for input volumes.

This was discussed on the mailing list:

https://tango.0pointer.de/pipermail/pulseaudio-discuss/2011-May/010091.html

This approach can introduce a problem when setting the volumes
for sources. What follows is Tanu Kaskinen's analysis:

[quote]
I'll quote the log:

D: protocol-native.c: Client pavucontrol changes volume of source alsa_input.pci-0000_00_1b.0.analog-stereo.
D: alsa-source.c: Requested volume: 0:  45% 1:  45%
D: alsa-source.c:            in dB: 0: -20.71 dB 1: -20.71 dB
D: alsa-source.c: Got hardware volume: 0:  45% 1:  45%
D: alsa-source.c:               in dB: 0: -21.00 dB 1: -21.00 dB
D: alsa-source.c: Calculated software volume: 0: 101% 1: 101% (accurate-enough=no)
D: alsa-source.c:                      in dB: 0: 0.29 dB 1: 0.29 dB
D: source.c: Volume going up to 29273 at 270475970821
D: source.c: Volume change to 29273 at 270475970821 was written 34 usec late
D: alsa-source.c: Written HW volume did not match with the request: 0: 45% 1:  45% (request) != 0:  42% 1:  42%
D: alsa-source.c:                                            in dB: 0: -21.00 dB 1: -21.00 dB (request) != 0: -22.50 dB 1: -22.50 dB

Looking at the last line, the requested volume seems to hit exactly the
right step (-21.00dB), but for some reason Alsa decides to choose
something else. I'm pretty sure that this happens because of rounding
errors. In the first phase we ask Alsa what dB value we should set, and
it returns -21.00 dB. The value is given as a long int, but we convert
that to pa_cvolume. Then when we set the volume, we convert the
pa_cvolume value back to a long integer. At this point I believe it gets
converted to -2101. This is not visible in the debug message for some
reason - the rounding algorithm must be different from what was used
with the pa_cvolume -> long conversion.
[/quote]

The commit after this contains a patch that addresses this issue.

src/modules/alsa/alsa-mixer.c

index 03a5312a2a1a0726bc0016983cf6b17006296f65..e3673f8c4974c4b0e1e89ce9f775fff81568f1d0 100644 (file)
@@ -893,7 +893,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
 
         if (e->has_dB) {
             long value = to_alsa_dB(f);
-            int rounding = value > 0 ? -1 : +1;
+            int rounding;
 
             if (e->volume_limit >= 0 && value > (e->max_dB * 100))
                 value = e->max_dB * 100;
@@ -903,6 +903,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
                  * if the channel is available, ALSA behaves very
                  * strangely and doesn't fail the call */
                 if (snd_mixer_selem_has_playback_channel(me, c)) {
+                    rounding = +1;
                     if (e->db_fix) {
                         if (write_to_hw)
                             r = snd_mixer_selem_set_playback_volume(me, c, decibel_fix_get_step(e->db_fix, &value, rounding));
@@ -925,6 +926,7 @@ static int element_set_volume(pa_alsa_element *e, snd_mixer_t *m, const pa_chann
                     r = -1;
             } else {
                 if (snd_mixer_selem_has_capture_channel(me, c)) {
+                    rounding = -1;
                     if (e->db_fix) {
                         if (write_to_hw)
                             r = snd_mixer_selem_set_capture_volume(me, c, decibel_fix_get_step(e->db_fix, &value, rounding));