[RFC,1/2] bluetooth: Add message to get/set A2DP codec configs

Submitted by Frédéric Danis on May 17, 2019, 1:45 p.m.

Details

Message ID 20190517134512.13399-2-frederic.danis@collabora.com
State New
Headers show
Series "Add dynamic configuration of SBC bitpool" ( rev: 1 ) in PulseAudio

Not browsing as part of any series.

Commit Message

Frédéric Danis May 17, 2019, 1:45 p.m.
This patch introduces 2 new messages to retrieve and set codec specific
configuration information.
It is up to each codec to define which information can be retrieved or set.
Message path is based on the remote device address (replacing ":" by "_").

 Get configuration command:
 pacmd send-message /bluetooth/bluez_sink.<device address> get-a2dp-config

 Set configuration command:
 pacmd send-message /bluetooth/bluez_sink.<device address> set-a2dp-config
  <parameters>

To avoid breaking buffer encoding, I split set-a2dp-config in 2 functions.
set_encoder_config() is called to pass the new configuration to the
encoder.
apply_encoder_config() is called when no buffer needs to be encoded.
---
 src/modules/bluetooth/a2dp-codec-api.h       | 10 ++++
 src/modules/bluetooth/module-bluez5-device.c | 54 ++++++++++++++++++++
 src/pulsecore/core-util.h                    |  7 +++
 3 files changed, 71 insertions(+)

Patch hide | download patch | download mbox

diff --git a/src/modules/bluetooth/a2dp-codec-api.h b/src/modules/bluetooth/a2dp-codec-api.h
index 55bb9ff70..23fbfe912 100644
--- a/src/modules/bluetooth/a2dp-codec-api.h
+++ b/src/modules/bluetooth/a2dp-codec-api.h
@@ -90,6 +90,16 @@  typedef struct pa_a2dp_codec {
      * returns size of filled ouput_buffer and set processed to size of
      * processed input_buffer */
     size_t (*decode_buffer)(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed);
+
+    /* Get encoder codec configuration, returns Message API string specific to
+     * each codec */
+    char *(*get_encoder_config)(void *codec_info);
+    /* Set encoder codec configuration. new_config string is codec specific and
+     * in Message API format. returns PA error code */
+    int (*set_encoder_config)(void *codec_info, char *new_config);
+    /* Apply new config to encoder codec, returns new write block size or zero
+     * if not changed, called after set_encoder_config success */
+    size_t (*apply_encoder_config)(void *codec_info, size_t write_link_mtu);
 } pa_a2dp_codec;
 
 #endif
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 56c96054d..3ab4be508 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -45,6 +45,8 @@ 
 #include <pulsecore/thread.h>
 #include <pulsecore/thread-mq.h>
 #include <pulsecore/time-smoother.h>
+#include <pulsecore/message-handler.h>
+#include <pulsecore/namereg.h>
 
 #include "a2dp-codecs.h"
 #include "a2dp-codec-util.h"
@@ -133,6 +135,7 @@  struct userdata {
     pa_memchunk write_memchunk;
 
     const pa_a2dp_codec *a2dp_codec;
+    bool a2dp_codec_config_pending;
 
     void *encoder_info;
     pa_sample_spec encoder_sample_spec;
@@ -1444,6 +1447,14 @@  static void thread_func(void *userdata) {
                                     handle_sink_block_size_change(u);
                                 }
                             }
+                        } else if (u->a2dp_codec_config_pending && u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK &&
+                                    u->a2dp_codec->apply_encoder_config) {
+                            size_t new_write_block_size = u->a2dp_codec->apply_encoder_config(u->encoder_info, u->write_link_mtu);
+                            if (new_write_block_size) {
+                                u->write_block_size = new_write_block_size;
+                                handle_sink_block_size_change(u);
+                            }
+                            u->a2dp_codec_config_pending = false;
                         }
 
                         blocks_to_write = 1;
@@ -1517,6 +1528,33 @@  finish:
     pa_log_debug("IO thread shutting down");
 }
 
+static int bluetooth_handler(const char *object_path, const char *message, char *message_parameters, char **response, void *userdata) {
+    struct userdata *u;
+
+    pa_assert(u = (struct userdata *) userdata);
+    pa_assert(message);
+    pa_assert(response);
+    pa_assert(pa_safe_strneq(object_path, "/bluetooth/bluez_", 17));
+
+    if (pa_streq(message, "get-a2dp-config")) {
+        if (u->a2dp_codec->get_encoder_config) {
+            *response = u->a2dp_codec->get_encoder_config(u->encoder_info);
+            return PA_OK;
+        }
+        return -PA_ERR_NOTSUPPORTED;
+    } else if (pa_streq(message, "set-a2dp-config")) {
+        if (u->a2dp_codec->set_encoder_config) {
+            int res = u->a2dp_codec->set_encoder_config(u->encoder_info, message_parameters);
+            if (res == PA_OK)
+                u->a2dp_codec_config_pending = true;
+            return res;
+        }
+        return -PA_ERR_NOTSUPPORTED;
+    }
+
+    return -PA_ERR_NOTIMPLEMENTED;
+}
+
 /* Run from main thread */
 static int start_thread(struct userdata *u) {
     pa_assert(u);
@@ -1567,6 +1605,14 @@  static int start_thread(struct userdata *u) {
             u->source->set_volume(u->source);
     }
 
+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
+        char *address = pa_namereg_make_valid_name(u->device->address);
+        char *path = pa_sprintf_malloc("/bluetooth/bluez_sink.%s", address);
+        pa_xfree(address);
+        pa_message_handler_register(u->core, path, "Bluetooth handler", bluetooth_handler, u);
+        pa_xfree(path);
+    }
+
     return 0;
 }
 
@@ -1574,6 +1620,14 @@  static int start_thread(struct userdata *u) {
 static void stop_thread(struct userdata *u) {
     pa_assert(u);
 
+    if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
+        char *address = pa_namereg_make_valid_name(u->device->address);
+        char *path = pa_sprintf_malloc("/bluetooth/bluez_sink.%s", address);
+        pa_xfree(address);
+        pa_message_handler_unregister(u->core, path);
+        pa_xfree(path);
+    }
+
     if (u->sink)
         pa_sink_unlink(u->sink);
 
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index 55059dbbd..9a2a30f50 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -230,6 +230,13 @@  static inline bool pa_safe_streq(const char *a, const char *b) {
     return pa_streq(a, b);
 }
 
+/* Like pa_strneq, but does not blow up on NULL pointers. */
+static inline bool pa_safe_strneq(const char *a, const char *b, size_t n) {
+    if (a == NULL || b == NULL)
+        return a == b;
+    return pa_strneq(a, b, n);
+}
+
 bool pa_str_in_list_spaces(const char *needle, const char *haystack);
 bool pa_str_in_list(const char *haystack, const char *delimiters, const char *needle);