[pulseaudio-commits] [Git][pulseaudio/pulseaudio][master] 7 commits: bluetooth: switch_codec should start with pa_blueooth_device_

PulseAudio Marge Bot gitlab at gitlab.freedesktop.org
Tue Mar 16 10:04:08 UTC 2021



PulseAudio Marge Bot pushed to branch master at PulseAudio / pulseaudio


Commits:
cefee393 by Marijn Suijten at 2021-03-15T21:44:12+01:00
bluetooth: switch_codec should start with pa_blueooth_device_

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -
a575006a by Marijn Suijten at 2021-03-16T00:04:50+01:00
bluetooth: Move HSP gain conversions into backend-native

For the upcoming A2DP AVRCP Absolute Volume feature the code in BlueZ5
has to be generic to be reusable. Move this conversion so that it
becomes possible to implement A2DP volume - which uses different values
- on top without duplicating existing callback functionality.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -
bfb3aeac by Marijn Suijten at 2021-03-16T00:04:51+01:00
bluetooth: backend-native: Round volume to closest instead of up

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -
d84ca030 by Marijn Suijten at 2021-03-16T00:19:45+01:00
bluetooth: Generalize speaker/microphone naming to sink/source

Sink and source naming is more generic when dealing with audio that is
directional in the sense that it either goes to or comes from the other
device, but not necessarily a microphone or speaker. A concrete example
is the swapped meaning when the current device is in the HeadSet
profile. The incoming audio can come from any source, not necessarily a
microphone. Likewise, audio captured by the microphone of the headset is
not necessarily played back by a speaker on the AG, it is merely acting
as a sink for the data: further handling is irrelevant to the naming.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -
9c847b16 by Marijn Suijten at 2021-03-16T10:48:58+01:00
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>

- - - - -
d510ddc7 by Marijn Suijten at 2021-03-16T10:48:59+01:00
bluetooth: Perform software attenuation until HF/HS reports gain control

HF/HS hardware attenuation is optional on HFP: the peer indicates
support with the AT+BRSF command, when bit 4 is set.  That does not
explicitly mandate speaker or microphone gain control; either is
dynamically detected as soon as `AT+VG[MS]=` is received.  Otherwise
software attenuation is performed.

It is also optional on HSP but nothing is mentioned about feature
detection, assume it is the same as HFP: perform software attenuation
until the HF/HS peer sends an `AT+VG[MS]=` command.

When PA is a HS/HF (and the peer the AG) we attenuate both channels in
software and unconditionally keep the peer up to date with
`AT+VGM/AT+VGS` commands.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -
f553afd2 by Igor V. Kovalenko at 2021-03-16T10:48:59+01:00
bluetooth: accept +VGM/+VGS unsolicited reply with '=' and ':' separator

HFP specs states both '=' and ':' should be accepted as a valid
separator for +VGM and +VGS unsolicited result codes.

This change is cherry-picked from Rodrigo Araujo's work here:
https://lists.freedesktop.org/archives/pulseaudio-discuss/2017-September/028820.html

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/521>

- - - - -


4 changed files:

- src/modules/bluetooth/backend-native.c
- src/modules/bluetooth/bluez5-util.c
- src/modules/bluetooth/bluez5-util.h
- src/modules/bluetooth/module-bluez5-device.c


Changes:

=====================================
src/modules/bluetooth/backend-native.c
=====================================
@@ -36,6 +36,8 @@
 
 #include "bluez5-util.h"
 
+#define HSP_MAX_GAIN 15
+
 struct pa_bluetooth_backend {
   pa_core *core;
   pa_dbus_connection *connection;
@@ -121,6 +123,45 @@ static uint32_t hfp_features =
     " </interface>"                                                     \
     "</node>"
 
+static pa_volume_t hsp_gain_to_volume(uint16_t gain) {
+    pa_volume_t volume = (pa_volume_t) ((
+        gain * PA_VOLUME_NORM
+        /* Round to closest by adding half the denominator */
+        + HSP_MAX_GAIN / 2
+    ) / HSP_MAX_GAIN);
+
+    if (volume > PA_VOLUME_NORM)
+        volume = PA_VOLUME_NORM;
+
+    return volume;
+}
+
+static uint16_t volume_to_hsp_gain(pa_volume_t volume) {
+    uint16_t gain = volume * HSP_MAX_GAIN / PA_VOLUME_NORM;
+
+    if (gain > HSP_MAX_GAIN)
+        gain = HSP_MAX_GAIN;
+
+    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) {
 
@@ -432,6 +473,9 @@ static void transport_put(pa_bluetooth_transport *t)
     pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile));
 }
 
+static pa_volume_t set_sink_volume(pa_bluetooth_transport *t, pa_volume_t volume);
+static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volume);
+
 static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf)
 {
     struct hfp_config *c = t->config;
@@ -439,11 +483,12 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf
 
     /* stateful negotiation */
     if (c->state == 0 && sscanf(buf, "AT+BRSF=%d", &val) == 1) {
-          c->capabilities = val;
-          pa_log_info("HFP capabilities returns 0x%x", val);
-          rfcomm_write_response(fd, "+BRSF: %d", hfp_features);
-          c->state = 1;
-          return true;
+        c->capabilities = val;
+        pa_log_info("HFP capabilities returns 0x%x", val);
+        rfcomm_write_response(fd, "+BRSF: %d", hfp_features);
+        c->state = 1;
+
+        return true;
     } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) {
           /* we declare minimal no indicators */
         rfcomm_write_response(fd, "+CIND: "
@@ -515,14 +560,24 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i
          * AT+CKPD=200: Sent by HS when headset button is pressed.
          * RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because
          * it does not expect a reply. */
-        if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM=%d\r\n", &gain) == 1) {
-            t->speaker_gain = gain;
-            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), t);
+        if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM%*[=:]%d\r\n", &gain) == 1) {
+            if (!t->set_sink_volume) {
+                pa_log_debug("HS/HF peer supports speaker gain control");
+                t->set_sink_volume = set_sink_volume;
+            }
+
+            t->sink_volume = hsp_gain_to_volume(gain);
+            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED), t);
             do_reply = true;
 
-        } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS=%d\r\n", &gain) == 1) {
-            t->microphone_gain = gain;
-            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), t);
+        } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS%*[=:]%d\r\n", &gain) == 1) {
+            if (!t->set_source_volume) {
+                pa_log_debug("HS/HF peer supports microphone gain control");
+                t->set_source_volume = set_source_volume;
+            }
+
+            t->source_volume = hsp_gain_to_volume(gain);
+            pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED), t);
             do_reply = true;
         } else if (sscanf(buf, "AT+CKPD=%d", &dummy) == 1) {
             do_reply = true;
@@ -559,40 +614,54 @@ static void transport_destroy(pa_bluetooth_transport *t) {
     pa_xfree(trd);
 }
 
-static void set_speaker_gain(pa_bluetooth_transport *t, uint16_t gain) {
+static pa_volume_t set_sink_volume(pa_bluetooth_transport *t, pa_volume_t volume) {
     struct transport_data *trd = t->userdata;
+    uint16_t gain = volume_to_hsp_gain(volume);
 
-    if (t->speaker_gain == gain)
-      return;
+    /* Propagate rounding and bound checks */
+    volume = hsp_gain_to_volume(gain);
 
-    t->speaker_gain = gain;
+    if (t->sink_volume == volume)
+        return 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) {
+    t->sink_volume = volume;
+
+    /* 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);
     }
+
+    return volume;
 }
 
-static void set_microphone_gain(pa_bluetooth_transport *t, uint16_t gain) {
+static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volume) {
     struct transport_data *trd = t->userdata;
+    uint16_t gain = volume_to_hsp_gain(volume);
 
-    if (t->microphone_gain == gain)
-      return;
+    /* Propagate rounding and bound checks */
+    volume = hsp_gain_to_volume(gain);
 
-    t->microphone_gain = gain;
+    if (t->source_volume == volume)
+        return 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) {
+    t->source_volume = volume;
+
+    /* 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);
     }
+
+    return volume;
 }
 
 static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, void *userdata) {
@@ -662,8 +731,25 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m,
     t->acquire = sco_acquire_cb;
     t->release = sco_release_cb;
     t->destroy = transport_destroy;
-    t->set_speaker_gain = set_speaker_gain;
-    t->set_microphone_gain = set_microphone_gain;
+
+    /* If PA is the HF/HS we are in control of volume attenuation and
+     * can always send volume commands (notifications) to keep the peer
+     * updated on actual volume value.
+     *
+     * If the peer is the HF/HS it is responsible for attenuation of both
+     * speaker and microphone gain.
+     * On HFP speaker/microphone gain support is reported by bit 4 in the
+     * `AT+BRSF=` command. Since it isn't explicitly documented whether this
+     * applies to speaker or microphone gain but the peer is required to send
+     * an initial value with `AT+VG[MS]=` either callback is hooked
+     * independently as soon as this command is received.
+     * On HSP this is not specified and is assumed to be dynamic for both
+     * speaker and microphone.
+     */
+    if (is_peer_audio_gateway(p)) {
+        t->set_sink_volume = set_sink_volume;
+        t->set_source_volume = set_source_volume;
+    }
 
     trd = pa_xnew0(struct transport_data, 1);
     trd->rfcomm_fd = fd;


=====================================
src/modules/bluetooth/bluez5-util.c
=====================================
@@ -305,7 +305,7 @@ struct switch_codec_data {
     void *userdata;
 };
 
-static void pa_bluetooth_switch_codec_reply(DBusPendingCall *pending, void *userdata) {
+static void pa_bluetooth_device_switch_codec_reply(DBusPendingCall *pending, void *userdata) {
     DBusMessage *r;
     pa_dbus_pending *p;
     pa_bluetooth_discovery *y;
@@ -345,7 +345,7 @@ static void pa_bluetooth_switch_codec_reply(DBusPendingCall *pending, void *user
     device->codec_switching_in_progress = false;
 }
 
-bool pa_bluetooth_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile_t profile,
+bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile_t profile,
         pa_hashmap *capabilities_hashmap, const pa_a2dp_codec *a2dp_codec,
         void (*codec_switch_cb)(bool, pa_bluetooth_profile_t profile, void *), void *userdata) {
     DBusMessageIter iter, dict;
@@ -409,7 +409,7 @@ bool pa_bluetooth_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile
     data->cb = codec_switch_cb;
     data->userdata = userdata;
 
-    send_and_add_to_pending(device->discovery, m, pa_bluetooth_switch_codec_reply, data);
+    send_and_add_to_pending(device->discovery, m, pa_bluetooth_device_switch_codec_reply, data);
 
     return true;
 }
@@ -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;
 


=====================================
src/modules/bluetooth/bluez5-util.h
=====================================
@@ -59,11 +59,11 @@ typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;
 typedef struct pa_bluetooth_backend pa_bluetooth_backend;
 
 typedef enum pa_bluetooth_hook {
-    PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,          /* Call data: pa_bluetooth_device */
-    PA_BLUETOOTH_HOOK_DEVICE_UNLINK,                      /* Call data: pa_bluetooth_device */
-    PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,            /* Call data: pa_bluetooth_transport */
-    PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED,  /* Call data: pa_bluetooth_transport */
-    PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED,     /* Call data: pa_bluetooth_transport */
+    PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,        /* Call data: pa_bluetooth_device */
+    PA_BLUETOOTH_HOOK_DEVICE_UNLINK,                    /* Call data: pa_bluetooth_device */
+    PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,          /* Call data: pa_bluetooth_transport */
+    PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED,  /* Call data: pa_bluetooth_transport */
+    PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED,    /* Call data: pa_bluetooth_transport */
     PA_BLUETOOTH_HOOK_MAX
 } pa_bluetooth_hook_t;
 
@@ -87,8 +87,7 @@ typedef enum pa_bluetooth_transport_state {
 typedef int (*pa_bluetooth_transport_acquire_cb)(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu);
 typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);
 typedef void (*pa_bluetooth_transport_destroy_cb)(pa_bluetooth_transport *t);
-typedef void (*pa_bluetooth_transport_set_speaker_gain_cb)(pa_bluetooth_transport *t, uint16_t gain);
-typedef void (*pa_bluetooth_transport_set_microphone_gain_cb)(pa_bluetooth_transport *t, uint16_t gain);
+typedef pa_volume_t (*pa_bluetooth_transport_set_volume_cb)(pa_bluetooth_transport *t, pa_volume_t volume);
 
 struct pa_bluetooth_transport {
     pa_bluetooth_device *device;
@@ -103,16 +102,16 @@ struct pa_bluetooth_transport {
 
     const pa_a2dp_codec *a2dp_codec;
 
-    uint16_t microphone_gain;
-    uint16_t speaker_gain;
+    pa_volume_t source_volume;
+    pa_volume_t sink_volume;
 
     pa_bluetooth_transport_state_t state;
 
     pa_bluetooth_transport_acquire_cb acquire;
     pa_bluetooth_transport_release_cb release;
     pa_bluetooth_transport_destroy_cb destroy;
-    pa_bluetooth_transport_set_speaker_gain_cb set_speaker_gain;
-    pa_bluetooth_transport_set_microphone_gain_cb set_microphone_gain;
+    pa_bluetooth_transport_set_volume_cb set_sink_volume;
+    pa_bluetooth_transport_set_volume_cb set_source_volume;
     void *userdata;
 };
 
@@ -184,6 +183,7 @@ void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t);
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t);
 
 bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d);
+bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile_t profile, pa_hashmap *capabilities_hashmap, const pa_a2dp_codec *a2dp_codec, void (*codec_switch_cb)(bool, pa_bluetooth_profile_t profile, void *), void *userdata);
 
 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_discovery *y, const char *path);
 pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local);
@@ -191,7 +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_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile_t profile, pa_hashmap *capabilities_hashmap, const pa_a2dp_codec *a2dp_codec, void (*codec_switch_cb)(bool, pa_bluetooth_profile_t profile, void *), void *userdata);
+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);


=====================================
src/modules/bluetooth/module-bluez5-device.c
=====================================
@@ -67,8 +67,6 @@ PA_MODULE_USAGE(
 #define FIXED_LATENCY_RECORD_A2DP   (25 * PA_USEC_PER_MSEC)
 #define FIXED_LATENCY_RECORD_SCO    (25 * PA_USEC_PER_MSEC)
 
-#define HSP_MAX_GAIN 15
-
 static const char* const valid_modargs[] = {
     "path",
     "autodetect_mtu",
@@ -104,8 +102,8 @@ struct userdata {
 
     pa_hook_slot *device_connection_changed_slot;
     pa_hook_slot *transport_state_changed_slot;
-    pa_hook_slot *transport_speaker_gain_changed_slot;
-    pa_hook_slot *transport_microphone_gain_changed_slot;
+    pa_hook_slot *transport_sink_volume_changed_slot;
+    pa_hook_slot *transport_source_volume_changed_slot;
 
     pa_bluetooth_discovery *discovery;
     pa_bluetooth_device *device;
@@ -962,7 +960,6 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
 
 /* Run from main thread */
 static void source_set_volume_cb(pa_source *s) {
-    uint16_t gain;
     pa_volume_t volume;
     struct userdata *u;
 
@@ -974,30 +971,19 @@ static void source_set_volume_cb(pa_source *s) {
     pa_assert(u);
     pa_assert(u->source == s);
 
-    if (u->transport->set_microphone_gain == NULL)
+    if (u->transport->set_source_volume == NULL)
       return;
 
-    gain = (pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN) / PA_VOLUME_NORM;
-
-    if (gain > HSP_MAX_GAIN)
-        gain = HSP_MAX_GAIN;
-
-    volume = (pa_volume_t) (gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    /* increment volume by one to correct rounding errors */
-    if (volume < PA_VOLUME_NORM)
-        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 */
+    volume = u->transport->set_source_volume(u->transport, pa_cvolume_max(&s->real_volume));
 
     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);
-
-    /* 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 */
-    u->transport->set_microphone_gain(u->transport, gain);
 }
 
 /* Run from main thread */
@@ -1055,10 +1041,8 @@ static int add_source(struct userdata *u) {
     u->source->parent.process_msg = source_process_msg;
     u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
 
-    if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
-        || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
-        || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
-        || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
+    if (u->transport->set_source_volume) {
+        pa_log_debug("Peer supports microphone gain control");
         pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
         u->source->n_volume_steps = 16;
     }
@@ -1154,7 +1138,6 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
 
 /* Run from main thread */
 static void sink_set_volume_cb(pa_sink *s) {
-    uint16_t gain;
     pa_volume_t volume;
     struct userdata *u;
 
@@ -1166,30 +1149,19 @@ static void sink_set_volume_cb(pa_sink *s) {
     pa_assert(u);
     pa_assert(u->sink == s);
 
-    if (u->transport->set_speaker_gain == NULL)
+    if (u->transport->set_sink_volume == NULL)
       return;
 
-    gain = (pa_cvolume_max(&s->real_volume) * HSP_MAX_GAIN) / PA_VOLUME_NORM;
-
-    if (gain > HSP_MAX_GAIN)
-        gain = HSP_MAX_GAIN;
-
-    volume = (pa_volume_t) (gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    /* increment volume by one to correct rounding errors */
-    if (volume < PA_VOLUME_NORM)
-        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 */
+    volume = u->transport->set_sink_volume(u->transport, pa_cvolume_max(&s->real_volume));
 
     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);
-
-    /* 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 */
-    u->transport->set_speaker_gain(u->transport, gain);
 }
 
 /* Run from main thread */
@@ -1248,10 +1220,8 @@ static int add_sink(struct userdata *u) {
     u->sink->parent.process_msg = sink_process_msg;
     u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
 
-    if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS
-        || u->profile == PA_BLUETOOTH_PROFILE_HSP_AG
-        || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG
-        || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) {
+    if (u->transport->set_sink_volume) {
+        pa_log_debug("Peer supports speaker gain control");
         pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
         u->sink->n_volume_steps = 16;
     }
@@ -2270,10 +2240,9 @@ static pa_hook_result_t transport_state_changed_cb(pa_bluetooth_discovery *y, pa
     return PA_HOOK_OK;
 }
 
-static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
+static pa_hook_result_t transport_sink_volume_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
     pa_volume_t volume;
     pa_cvolume v;
-    uint16_t gain;
 
     pa_assert(t);
     pa_assert(u);
@@ -2281,26 +2250,20 @@ static pa_hook_result_t transport_speaker_gain_changed_cb(pa_bluetooth_discovery
     if (t != u->transport)
       return PA_HOOK_OK;
 
-    gain = t->speaker_gain;
-    volume = (pa_volume_t) (gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    /* increment volume by one to correct rounding errors */
-    if (volume < PA_VOLUME_NORM)
-        volume++;
+    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;
 }
 
-static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
+static pa_hook_result_t transport_source_volume_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
     pa_volume_t volume;
     pa_cvolume v;
-    uint16_t gain;
 
     pa_assert(t);
     pa_assert(u);
@@ -2308,19 +2271,14 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov
     if (t != u->transport)
       return PA_HOOK_OK;
 
-    gain = t->microphone_gain;
-    volume = (pa_volume_t) (gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
-
-    /* increment volume by one to correct rounding errors */
-    if (volume < PA_VOLUME_NORM)
-        volume++;
+    volume = t->source_volume;
 
     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;
 }
@@ -2494,7 +2452,7 @@ static int bluez5_device_message_handler(const char *object_path, const char *me
 
         stop_thread(u);
 
-        if (!pa_bluetooth_switch_codec(u->device, profile, capabilities_hashmap, codec, switch_codec_cb_handler, userdata)
+        if (!pa_bluetooth_device_switch_codec(u->device, profile, capabilities_hashmap, codec, switch_codec_cb_handler, userdata)
                 && !u->device->codec_switching_in_progress)
             goto profile_off;
 
@@ -2620,11 +2578,11 @@ int pa__init(pa_module* m) {
         pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED),
                         PA_HOOK_NORMAL, (pa_hook_cb_t) transport_state_changed_cb, u);
 
-    u->transport_speaker_gain_changed_slot =
-        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_speaker_gain_changed_cb, u);
+    u->transport_sink_volume_changed_slot =
+        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_sink_volume_changed_cb, u);
 
-    u->transport_microphone_gain_changed_slot =
-        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_microphone_gain_changed_cb, u);
+    u->transport_source_volume_changed_slot =
+        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_source_volume_changed_cb, u);
 
     if (add_card(u) < 0)
         goto fail;
@@ -2695,11 +2653,11 @@ void pa__done(pa_module *m) {
     if (u->transport_state_changed_slot)
         pa_hook_slot_free(u->transport_state_changed_slot);
 
-    if (u->transport_speaker_gain_changed_slot)
-        pa_hook_slot_free(u->transport_speaker_gain_changed_slot);
+    if (u->transport_sink_volume_changed_slot)
+        pa_hook_slot_free(u->transport_sink_volume_changed_slot);
 
-    if (u->transport_microphone_gain_changed_slot)
-        pa_hook_slot_free(u->transport_microphone_gain_changed_slot);
+    if (u->transport_source_volume_changed_slot)
+        pa_hook_slot_free(u->transport_source_volume_changed_slot);
 
     if (u->encoder_buffer)
         pa_xfree(u->encoder_buffer);



View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/compare/a82e019de91ea988c67555fd1b342e8e91e85ed5...f553afd2df413a9dd4e07165c193afa474e25f9d

-- 
View it on GitLab: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/compare/a82e019de91ea988c67555fd1b342e8e91e85ed5...f553afd2df413a9dd4e07165c193afa474e25f9d
You're receiving this email because of your account on gitlab.freedesktop.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-commits/attachments/20210316/1481e830/attachment-0001.htm>


More information about the pulseaudio-commits mailing list