[alsa-devel] alsactl adds volume controls?

Colin Guthrie gmane at colin.guthr.ie
Fri Oct 8 17:25:18 CEST 2010


'Twas brillig, and Clemens Ladisch at 08/10/10 15:42 did gyre and gimble:
> Colin Guthrie wrote:
>> Hmm, just thinking about this (as I don't know the volume control logic
>> particularly well in PA), the call snd_mixer_selem_set_playback_dB() is
>> used with a dir argument of +1.
>>
>> From what I understand, this would allow me to say "set the volume to
>> 50dB" and due to the +1 dir, it should select -46.499999 ( because -46.5
>> mutes it).
>>
>> In this case however, the value of -99999.999dB is ultimately selected
>> (aka 0).
>>
>> I'm wondering if the TLV fix actually affects how
>> snd_mixer_selem_set_playback_dB() call works with the dir argument.
> 
> Uh, oh.  snd_tlv_convert_from_dB() ignores the minimum-is-mute flag.

Ahh good, I analysed that kinda correctly then :D

> Please try this hack:
> 
> --- alsa-lib/src/control/tlv.c
> +++ alsa-lib/src/control/tlv.c
> @@ -335,6 +335,9 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
>  			if (xdir > 0)
>  				v += (max - min) - 1;
>  			v = v / (max - min) + rangemin;
> +			if (v == rangemin && xdir > 0 && (tlv[3] & 0x10000) &&
> +			    db_gain > SND_CTL_TLV_DB_GAIN_MUTE)
> +				v++;
>  			*value = v;
>  		}
>  		return 0;


Didn't help sadly, but then looking at the code there it seems a little odd.

Firstly I tried this (extended) patch - I'm not sure it's needed but
when the first one didn't work I tried to experiment a bit:

--- a/src/control/tlv.c
+++ b/src/control/tlv.c
@@ -323,15 +323,20 @@ int snd_tlv_convert_from_dB(unsigned int *tlv,
long rangemin, long rangemax,
                int min, max;
                min = tlv[2];
                max = tlv[3];
-               if (db_gain <= min)
+               if (db_gain <= min) {
                        *value = rangemin;
-               else if (db_gain >= max)
+                       if (xdir > 0 && (tlv[3] & 0x10000) && db_gain >
SND_CTL_TLV_DB_GAIN_MUTE)
+                               *value = rangemin + 1;
+               } else if (db_gain >= max)
                        *value = rangemax;
                else {
                        long v = (db_gain - min) * (rangemax - rangemin);
                        if (xdir > 0)
                                v += (max - min) - 1;
                        v = v / (max - min) + rangemin;
+                       if (v == rangemin && xdir > 0 && (tlv[3] &
0x10000) &&
+                           db_gain > SND_CTL_TLV_DB_GAIN_MUTE)
+                               v++;
                        *value = v;
                }
                return 0;


This also catches the case when I try to set the volume to e.g. -5000
(-50.00dB) as it is < min (which I presume is still -4650, but actually
didn't check) then it will be set to rangemin and no further checks are
done.

What is odd about this tho', is that the flag for min is mute (0x10000)
is checked on tlv[3] which is also used here for the "max" value.

Is the use of position 3 correct (both here and on the kernel side) or
perhaps the max line needs to be:

                max = (tlv[3] & 0xffff);

instead? Either way it didn't help, but I thought the strangeness with
the tlv[3] value was worth pointing out.

Many thanks for debugging this with me :)

Col

PS, happy to chat on IRC if you prefer - coling


-- 

Colin Guthrie
gmane(at)colin.guthr.ie
http://colin.guthr.ie/

Day Job:
  Tribalogic Limited [http://www.tribalogic.net/]
Open Source:
  Mageia Contributor [http://www.mageia.org/]
  PulseAudio Hacker [http://www.pulseaudio.org/]
  Trac Hacker [http://trac.edgewall.org/]



More information about the Alsa-devel mailing list