bluetooth: show negotiated HFP codec
authorIgor V. Kovalenko <igor.v.kovalenko@gmail.com>
Mon, 22 Feb 2021 20:14:37 +0000 (23:14 +0300)
committerPulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org>
Mon, 5 Apr 2021 15:43:32 +0000 (15:43 +0000)
While codec switching for HFP is not implemented, show current codec via
messaging api.

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

src/modules/bluetooth/a2dp-codec-util.c
src/modules/bluetooth/a2dp-codec-util.h
src/modules/bluetooth/module-bluez5-device.c

index 355e19c..ca8df46 100644 (file)
@@ -80,6 +80,15 @@ const pa_a2dp_codec *pa_bluetooth_a2dp_codec_iter(unsigned int i) {
     return pa_a2dp_codecs[i];
 }
 
+unsigned int pa_bluetooth_hf_codec_count(void) {
+    return PA_ELEMENTSOF(pa_hf_codecs);
+}
+
+const pa_a2dp_codec *pa_bluetooth_hf_codec_iter(unsigned int i) {
+    pa_assert(i < pa_bluetooth_hf_codec_count());
+    return pa_hf_codecs[i];
+}
+
 const pa_a2dp_codec *pa_bluetooth_get_hf_codec(const char *name) {
     unsigned int i;
 
index 6330fd8..57a15c7 100644 (file)
@@ -37,6 +37,12 @@ bool pa_bluetooth_a2dp_codec_is_available(const pa_a2dp_codec_id *id, bool is_a2
 /* Initialise GStreamer */
 void pa_bluetooth_a2dp_codec_gst_init(void);
 
+/* Get number of supported HSP/HFP codecs */
+unsigned int pa_bluetooth_hf_codec_count(void);
+
+/* Get i-th codec. Codec with higher number has higher priority */
+const pa_a2dp_codec *pa_bluetooth_hf_codec_iter(unsigned int i);
+
 /* Get HSP/HFP codec by name */
 const pa_a2dp_codec *pa_bluetooth_get_hf_codec(const char *name);
 
index 6e75bfc..4d3d0c9 100644 (file)
@@ -2361,31 +2361,49 @@ static char *list_codecs(struct userdata *u) {
     bool is_a2dp_sink;
     void *state;
 
-    is_a2dp_sink = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK;
-
-    a2dp_endpoints = is_a2dp_sink ? u->device->a2dp_sink_endpoints : u->device->a2dp_source_endpoints;
-
     encoder = pa_json_encoder_new();
 
     pa_json_encoder_begin_element_array(encoder);
 
-    PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, a2dp_endpoints, state) {
-        for (i = 0; i < pa_bluetooth_a2dp_codec_count(); i++) {
-            const pa_a2dp_codec *a2dp_codec;
+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
+        is_a2dp_sink = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK;
+
+        a2dp_endpoints = is_a2dp_sink ? u->device->a2dp_sink_endpoints : u->device->a2dp_source_endpoints;
+
+        PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, a2dp_endpoints, state) {
+            for (i = 0; i < pa_bluetooth_a2dp_codec_count(); i++) {
+                const pa_a2dp_codec *a2dp_codec;
 
-            a2dp_codec = pa_bluetooth_a2dp_codec_iter(i);
+                a2dp_codec = pa_bluetooth_a2dp_codec_iter(i);
 
-            if (memcmp(key, &a2dp_codec->id, sizeof(pa_a2dp_codec_id)) == 0) {
-                if (a2dp_codec->can_be_supported(is_a2dp_sink)) {
-                    pa_json_encoder_begin_element_object(encoder);
+                if (memcmp(key, &a2dp_codec->id, sizeof(pa_a2dp_codec_id)) == 0) {
+                    if (a2dp_codec->can_be_supported(is_a2dp_sink)) {
+                        pa_json_encoder_begin_element_object(encoder);
 
-                    pa_json_encoder_add_member_string(encoder, "name", a2dp_codec->name);
-                    pa_json_encoder_add_member_string(encoder, "description", a2dp_codec->description);
+                        pa_json_encoder_add_member_string(encoder, "name", a2dp_codec->name);
+                        pa_json_encoder_add_member_string(encoder, "description", a2dp_codec->description);
 
-                    pa_json_encoder_end_object(encoder);
+                        pa_json_encoder_end_object(encoder);
+                    }
                 }
             }
         }
+    } else {
+        /* find out active codec selection from device profile */
+        for (i = 0; i < pa_bluetooth_hf_codec_count(); i++) {
+            const pa_a2dp_codec *hf_codec;
+
+            hf_codec = pa_bluetooth_hf_codec_iter(i);
+
+            if (true) {
+                pa_json_encoder_begin_element_object(encoder);
+
+                pa_json_encoder_add_member_string(encoder, "name", hf_codec->name);
+                pa_json_encoder_add_member_string(encoder, "description", hf_codec->description);
+
+                pa_json_encoder_end_object(encoder);
+            }
+        }
     }
 
     pa_json_encoder_end_array(encoder);
@@ -2428,13 +2446,15 @@ static int bluez5_device_message_handler(const char *object_path, const char *me
     if (u->profile == PA_BLUETOOTH_PROFILE_OFF) {
         pa_log_info("Bluetooth profile is off. Message cannot be handled.");
         return -PA_ERR_INVALID;
-    } else if (u->profile != PA_BLUETOOTH_PROFILE_A2DP_SINK &&
-            u->profile != PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
-        pa_log_info("Listing or switching codecs only allowed for A2DP sink or source");
-        return -PA_ERR_INVALID;
     }
 
     if (pa_streq(message, "switch-codec")) {
+        if (u->profile != PA_BLUETOOTH_PROFILE_A2DP_SINK &&
+            u->profile != PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
+            pa_log_info("Switching codecs only allowed for A2DP sink or source");
+            return -PA_ERR_INVALID;
+        }
+
         if (!parameters) {
             pa_log_info("Codec switching operation requires codec name string parameter");
             return -PA_ERR_INVALID;