bluetooth: Move attenuation decision to shared function

Generalize the distinction between local and peer-attenuated volumes
into a function, paving the way for future changes where this needs to
be checked in more places and when A2DP Absolute Volume support is
added.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>
This commit is contained in:
Marijn Suijten 2021-03-04 11:30:42 +01:00
parent d84ca03080
commit 9c847b16a8
4 changed files with 64 additions and 16 deletions

View file

@ -145,6 +145,23 @@ static uint16_t volume_to_hsp_gain(pa_volume_t volume) {
return gain;
}
static bool is_peer_audio_gateway(pa_bluetooth_profile_t peer_profile) {
switch(peer_profile) {
case PA_BLUETOOTH_PROFILE_HFP_HF:
case PA_BLUETOOTH_PROFILE_HSP_HS:
return false;
case PA_BLUETOOTH_PROFILE_HFP_AG:
case PA_BLUETOOTH_PROFILE_HSP_AG:
return true;
default:
pa_assert_not_reached();
}
}
static bool is_pulseaudio_audio_gateway(pa_bluetooth_profile_t peer_profile) {
return !is_peer_audio_gateway(peer_profile);
}
static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_backend *backend, DBusMessage *m,
DBusPendingCallNotifyFunction func, void *call_data) {
@ -595,10 +612,11 @@ static pa_volume_t set_sink_volume(pa_bluetooth_transport *t, pa_volume_t volume
t->sink_volume = volume;
/* If we are in the AG role, we send a command to the head set to change
* the speaker gain. In the HS role, source and sink are swapped, so
* in this case we notify the AG that the microphone gain has changed */
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
/* If we are in the AG role, we send an unsolicited result-code to the headset
* to change the speaker gain. In the HS role, source and sink are swapped,
* so in this case we notify the AG that the microphone gain has changed
* by sending a command. */
if (is_pulseaudio_audio_gateway(t->profile)) {
rfcomm_write_response(trd->rfcomm_fd, "+VGS=%d", gain);
} else {
rfcomm_write_command(trd->rfcomm_fd, "AT+VGM=%d", gain);
@ -619,10 +637,11 @@ static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volu
t->source_volume = volume;
/* If we are in the AG role, we send a command to the head set to change
* the microphone gain. In the HS role, source and sink are swapped, so
* in this case we notify the AG that the speaker gain has changed */
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
/* If we are in the AG role, we send an unsolicited result-code to the headset
* to change the microphone gain. In the HS role, source and sink are swapped,
* so in this case we notify the AG that the speaker gain has changed
* by sending a command. */
if (is_pulseaudio_audio_gateway(t->profile)) {
rfcomm_write_response(trd->rfcomm_fd, "+VGM=%d", gain);
} else {
rfcomm_write_command(trd->rfcomm_fd, "AT+VGS=%d", gain);

View file

@ -1738,6 +1738,34 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) {
return NULL;
}
/* Returns true when PA has to perform attenuation, false if this is the
* responsibility of the peer.
*
* `peer_profile` is the profile of the peer.
*
* When the peer is in the HFP/HSP Audio Gateway role (PA is in headset role) PA
* has to perform attenuation on both the incoming and outgoing stream. In the
* HandsFree/HeadSet role both are attenuated on the peer.
*/
bool pa_bluetooth_profile_should_attenuate_volume(pa_bluetooth_profile_t peer_profile) {
switch(peer_profile) {
case PA_BLUETOOTH_PROFILE_A2DP_SINK:
/* Will be set to false when A2DP absolute volume is supported */
return true;
case PA_BLUETOOTH_PROFILE_A2DP_SOURCE:
return true;
case PA_BLUETOOTH_PROFILE_HFP_HF:
case PA_BLUETOOTH_PROFILE_HSP_HS:
return false;
case PA_BLUETOOTH_PROFILE_HFP_AG:
case PA_BLUETOOTH_PROFILE_HSP_AG:
return true;
case PA_BLUETOOTH_PROFILE_OFF:
pa_assert_not_reached();
}
pa_assert_not_reached();
}
static const pa_a2dp_codec *a2dp_endpoint_to_a2dp_codec(const char *endpoint) {
const char *codec_name;

View file

@ -191,6 +191,7 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_d
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y, pa_bluetooth_hook_t hook);
const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile);
bool pa_bluetooth_profile_should_attenuate_volume(pa_bluetooth_profile_t profile);
static inline bool pa_bluetooth_uuid_is_hsp_hs(const char *uuid) {
return pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS_ALT);

View file

@ -982,7 +982,7 @@ static void source_set_volume_cb(pa_source *s) {
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
/* Set soft volume when in headset role */
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
if (pa_bluetooth_profile_should_attenuate_volume(u->profile))
pa_cvolume_set(&s->soft_volume, u->decoder_sample_spec.channels, volume);
}
@ -1162,7 +1162,7 @@ static void sink_set_volume_cb(pa_sink *s) {
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
/* Set soft volume when in headset role */
if (u->profile == PA_BLUETOOTH_PROFILE_HFP_AG || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG)
if (pa_bluetooth_profile_should_attenuate_volume(u->profile))
pa_cvolume_set(&s->soft_volume, u->encoder_sample_spec.channels, volume);
}
@ -2257,10 +2257,10 @@ static pa_hook_result_t transport_sink_volume_changed_cb(pa_bluetooth_discovery
volume = t->sink_volume;
pa_cvolume_set(&v, u->encoder_sample_spec.channels, volume);
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
pa_sink_volume_changed(u->sink, &v);
else
if (pa_bluetooth_profile_should_attenuate_volume(t->profile))
pa_sink_set_volume(u->sink, &v, true, true);
else
pa_sink_volume_changed(u->sink, &v);
return PA_HOOK_OK;
}
@ -2279,10 +2279,10 @@ static pa_hook_result_t transport_source_volume_changed_cb(pa_bluetooth_discover
pa_cvolume_set(&v, u->decoder_sample_spec.channels, volume);
if (t->profile == PA_BLUETOOTH_PROFILE_HSP_HS || t->profile == PA_BLUETOOTH_PROFILE_HFP_HF)
pa_source_volume_changed(u->source, &v);
else
if (pa_bluetooth_profile_should_attenuate_volume(t->profile))
pa_source_set_volume(u->source, &v, true, true);
else
pa_source_volume_changed(u->source, &v);
return PA_HOOK_OK;
}