bluetooth: Synchronize AVRCP Absolute Volume with A2DP sink

Like the previous commit this handles `Volume` property changes but
applies them to an A2DP sink instead of source stream.  As mentioned in
the AVRCP spec v1.6.2 §5.8 the rendering device (A2DP sink) is
responsible for performing volume attenuation meaning PulseAudio should
pass through audio as-is without performing any attenuation in SW.
Setting a valid pointer to `set_sink_volume` and returning `true` from
`should_attenuate_volume` attaches a hardware callback to `pa_sink` such
that no volume attenuation is performed anymore.

In addition to receiving volume change notifications it is also possible
to control remote volume by writing a new value to the DBus property.
This is especially useful when playing back to in-ear audio devices
which usually lack physical buttons to adjust the final volume on the
sink.

While software volume (used before this patch) is generally fine it is
annoying to crank it up all the way to 100% when a previous connection
to a different device left saved volume on the peer at a low volume.
Providing this bidirectional synchronization is most natural to users
who wish to use physical controls on their headphones, are used to this
from their smartphone, or aforementioned volume mismatches where both PA
as source and the peer as sink/rendering device are performing
attenutation.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/239>
This commit is contained in:
Marijn Suijten 2020-01-16 02:49:01 +01:00 committed by PulseAudio Marge Bot
parent 710a35cdc3
commit ac21b07ad6
2 changed files with 102 additions and 15 deletions

View file

@ -1126,6 +1126,13 @@ static void sink_setup_volume_callback(pa_sink *s) {
return;
if (pa_bluetooth_profile_should_attenuate_volume(u->profile)) {
/* It is yet unknown how (if at all) volume is synchronized for bidirectional
* A2DP codecs. Disallow attaching hooks to a pa_sink if the peer is in
* A2DP_SOURCE role. This assert should be replaced with the proper logic
* when bidirectional codecs are implemented.
*/
pa_assert(u->profile != PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
if (u->sink_volume_changed_slot)
return;
@ -1146,7 +1153,11 @@ static void sink_setup_volume_callback(pa_sink *s) {
pa_sink_set_soft_volume(s, NULL);
pa_sink_set_set_volume_callback(s, sink_set_volume_cb);
s->n_volume_steps = HSP_MAX_GAIN + 1;
if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK)
s->n_volume_steps = A2DP_MAX_GAIN + 1;
else
s->n_volume_steps = HSP_MAX_GAIN + 1;
}
}