[pulseaudio-discuss] An raop2 support
Hajime Fujita
crisp.fujita at nifty.com
Fri Sep 20 18:15:47 PDT 2013
Tanu Kaskinen wrote:
> On Thu, 2013-09-19 at 22:47 -0500, Hajime Fujita wrote:
>> Hi Tanu,
>>
>> Tanu Kaskinen wrote:
>>> On Wed, 2013-09-18 at 23:09 -0500, Hajime Fujita wrote:
>>>> Hi Tanu,
>>>>
>>>> Thank you so much for your advice.
>>>>
>>>> Tanu Kaskinen wrote:
>>>>> On Sun, 2013-09-15 at 00:24 -0500, Hajime Fujita wrote:
>>>>>> For those who are interested in raop2 experiments,
>>>>>>
>>>>>> As Matthias pointed out [1], current volume calculation is incorrect.
>>>>>> https://bugs.freedesktop.org/show_bug.cgi?id=42804#c43
>>>>>>
>>>>>> I have uploaded a patch which calculates volume in more reasonable way.
>>>>>> https://github.com/hfujita/pulseaudio-raop2/commit/69f3ce883dfb93eb7b24f98b9664e14071672475
>>>>>>
>>>>>> First I have to confess that this is the first time for me to deal with
>>>>>> the unit 'dB', so maybe I'm doing totally stupid. I'd be very happy if I
>>>>>> could have any suggestions from who is more experienced in this field.
>>>>>>
>>>>>> I started looking at pa_raop_client_set_volume() in
>>>>>> src/modules/raop/raop_client.c. It was using pa_sw_volume_to_dB to
>>>>>> calculate dB from a linear scale.
>>>>>
>>>>> Correction: pa_volume_t doesn't use a linear scale, it uses a cubic
>>>>> scale (see pa_sw_volume_from_linear() and pa_sw_volume_to_linear()).
>>>>
>>>> I see. I should have noticed some comments about cubic scale.
>>>> http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/src/pulse/volume.c#n251
>>>>
>>>>>
>>>>>> Then I learned from code reading that pa_sw_volume_to_dB essentially
>>>>>> calculates the following:
>>>>>> 20 * log10((v/MAXVOLUME)^3) = 60 * log10(v/MAXVOLUME)
>>>>>> This does not fit into the volume scale which RAOP is expecting, where
>>>>>> -30.0 db is a kind of minimum [2].
>>>>>>
>>>>>> [2]: http://git.zx2c4.com/Airtunes2/about/#id29
>>>>>>
>>>>>> Also I looked at packet dumps from iPad and guessed how it calculated dB
>>>>>> from a linear scale. It looked like iPad was using the following formula.
>>>>>> db = 10 * log10(volume/MAXVOLUME/30)
>>>>>> So for the time being I decided to follow this way.
>>>>>
>>>>> The way to convert pa_volume_t to dB is to use pa_sw_volume_to_dB().
>>>>> Doing anything else means that the result is not dB, it's something
>>>>> different.
>>>>>
>>>>> The way to handle this is to ensure that the volume that is given to
>>>>> pa_raop_client_set_volume() is never outside the supported range. In
>>>>> module-raop-sink.c there's sink_set_volume_cb(), which calls
>>>>> pa_raop_client_set_volume(). In sink_set_volume_cb() there's this line:
>>>>>
>>>>> pa_cvolume_set(&hw, s->sample_spec.channels, v);
>>>>>
>>>>> Before that line you should check what dB value v corresponds to, and if
>>>>> it's outside the supported range, then you should modify v to fall into
>>>>> the supported range. Any modification that you make to v will be
>>>>> compensated with software volume, so the modifications shouldn't affect
>>>>> the resulting volume at all, assuming that the RAOP device actually
>>>>> attenuates the signal by the dB amount that you send to it.
>>>>>
>>>>
>>>> According to your advice, I inserted an adjustment to v before
>>>> pa_cvolume_set. Here's the patch.
>>>> https://github.com/hfujita/pulseaudio-raop2/commit/c6337c0fef7710ee20b42ed3fb87ec12910ce35a
>>>>
>>>> Adjustment goes like this (pa_raop_client_adjust_volume()):
>>>> adj(v) = v * (1 - minv/maxv) + minv;
>>>> where pa_sw_volume_to_dB(minv) = -30.0,
>>>> and pa_sw_volume_to_dB(maxv) = 0.0
>>>>
>>>> The idea is that when the original v is 0, adj(0) = minv. And when the
>>>> original v is maxv, adj(maxv) = maxv;
>>>>
>>>> Does this make sense?
>>>
>>> The idea was to simply adjust v to -30 dB if the original v is less than
>>> that. There's no need to do any complicated calculations.
>>
>> Do you mean something like
>> v = max(minv, v); /* where minv corresponds to -30.0dB */ ?
>
> Yes.
>
>> If I do that, resulted volume will be almost muted in the range of 0% <=
>> v <= 31%, then suddenly goes up beyond 31%. (31% is where dB becomes -30.0)
>> I was afraid that this was not an intuitive behavior to users.
>
> It sounds like the RAOP device doesn't apply the attenuation as it
> should. Could you verify this? If you don't apply any software volume
> (set s->soft_volume to PA_VOLUME_NORM), and you tell the RAOP device to
> use volume -30.0, do you get very quiet (but not silent) audio? And if
> you then tell the RAOP device to use volume -29.9, do you get much
> louder audio? This shouldn't happen. A change of 0.1 dB should have very
> small effect.
I actually did it. At -30.0, the device shows "MIN" in the volume
indicator and I did not hear any sound. Same in -29.9.
If it becomes -29.79, I recognize sound from the speaker. At this moment
the volume indicator shows "1".
>>>> As you noted, this also affects the software volume, and in my
>>>> environment, the actual volume (volume heard from the speaker) may be
>>>> way too small.
>>>
>>> What do you mean by way too small? The maximum volume will be the same
>>> as before, but the minimum volume will be quieter than before. With the
>>> original code you complained that you need to keep the volume at rather
>>> low levels, so extending the scale towards low volumes should help with
>>> this.
>>
>> Well, this could be just my personal feeling. Since it was a bit loud
>> before (however it was almost the same volume level as iPad), this time
>> I felt it was way too small.
>>
>> I wonder if it makes sense to 1) adjust v as
>> adj(v) = v * (1 - minv/maxv) + minv;
>> and 2) use the original v for pa_cvolume_set(), then 3) use adj(v) for
>> setting the actual RAOP device volume.
>> Under this condition, the calculated software volume always becomes
>> 100%, as in the current (mainline) raop module.
>
> Yes, that sounds like a reasonable approach, if you can't trust that the
> RAOP device will handle the volume correctly. Note that the the current
> raop module does use software volume when all channels don't have the
> same volume. With the adjustment that you suggest, you can't do this any
> more, because the volume is not any more convertible to dB, and thus you
> can't use pa_sw_volume_divide(). You should then force all channels to
> have the same volume, which can be done by modifying s->real_volume:
>
> pa_cvolume_set(&s->real_volume, s->sample_spec.channels, v_orig);
>
Thanks. I'll also try this.
Thanks,
Hajime
More information about the pulseaudio-discuss
mailing list