[pulseaudio-discuss] [PATCH] Implement event Volume has changed (org.bluez.MediaTransport1) in order to take into account volume changes of A2DP sources.

Mathieu Tournier mathieutournier at gmail.com
Fri Mar 11 10:16:18 UTC 2016


Using A2DP and a bluetooth audio source, Pulseaudio doesn't take into account the volume modification (for device sending the event via AVRCP (ex:Apple devices))
This work aims to integrate bluez event Volume (org.bluez.MediaTransport1) for A2DP source in pulseaudio.
This permits to take into account A2DP source volume changes (sent using AVRCP protocol).

Change has been tested with an iphone and an ipad and is fully working.
---
 src/modules/bluetooth/bluez5-util.c          | 15 ++++++++++++++
 src/modules/bluetooth/bluez5-util.h          | 13 ++++++++----
 src/modules/bluetooth/module-bluez5-device.c | 30 ++++++++++++++++++++++++++++
 3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c
index 03c76bf..c216c6e 100644
--- a/src/modules/bluetooth/bluez5-util.c
+++ b/src/modules/bluetooth/bluez5-util.c
@@ -185,6 +185,14 @@ void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_tr
         pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);
 }
 
+void pa_bluetooth_transport_set_source_volume(pa_bluetooth_transport *t,uint16_t volume) {
+
+    pa_assert(t);
+    t->source_volume = volume;
+    pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_SOURCE_VOLUME_CHANGED], t);
+
+}
+
 void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {
     pa_assert(t);
 
@@ -340,6 +348,13 @@ static void parse_transport_property(pa_bluetooth_transport *t, DBusMessageIter
 
                 pa_bluetooth_transport_set_state(t, state);
             }
+        case DBUS_TYPE_UINT16: {
+            uint16_t uintValue;
+            dbus_message_iter_get_basic(&variant_i, &uintValue);
+
+                if (pa_streq(key, "Volume"))
+                    pa_bluetooth_transport_set_source_volume(t,uintValue);
+            }
 
             break;
         }
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h
index d66e8a3..3380074 100644
--- a/src/modules/bluetooth/bluez5-util.h
+++ b/src/modules/bluetooth/bluez5-util.h
@@ -36,10 +36,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_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_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_TRANSPORT_A2DP_SOURCE_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */
     PA_BLUETOOTH_HOOK_MAX
 } pa_bluetooth_hook_t;
 
@@ -63,6 +64,7 @@ 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 void (*pa_bluetooth_transport_set_a2dp_source_volume_cb)(pa_bluetooth_transport *t, uint16_t volume);
 
 struct pa_bluetooth_transport {
     pa_bluetooth_device *device;
@@ -77,6 +79,7 @@ struct pa_bluetooth_transport {
 
     uint16_t microphone_gain;
     uint16_t speaker_gain;
+    uint16_t source_volume;
 
     pa_bluetooth_transport_state_t state;
 
@@ -85,6 +88,7 @@ struct pa_bluetooth_transport {
     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_a2dp_source_volume_cb set_source_volume;
     void *userdata;
 };
 
@@ -139,6 +143,7 @@ pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const
                                                    pa_bluetooth_profile_t p, const uint8_t *config, size_t size);
 
 void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_transport_state_t state);
+void pa_bluetooth_transport_set_source_volume(pa_bluetooth_transport *t, uint16_t volume);
 void pa_bluetooth_transport_put(pa_bluetooth_transport *t);
 void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t);
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t);
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index 84e6d55..2aa7277 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -65,6 +65,7 @@ PA_MODULE_USAGE("path=<device object path>");
 #define BITPOOL_DEC_LIMIT 32
 #define BITPOOL_DEC_STEP 5
 #define HSP_MAX_GAIN 15
+#define A2DP_MAX_VOLUME 127
 
 static const char* const valid_modargs[] = {
     "path",
@@ -104,6 +105,7 @@ struct userdata {
     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_a2dp_source_volume_changed_slot;
 
     pa_bluetooth_discovery *discovery;
     pa_bluetooth_device *device;
@@ -2102,6 +2104,29 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t transport_a2dp_source_volume_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {
+    pa_volume_t volume;
+    pa_cvolume v;
+
+    pa_assert(t);
+    pa_assert(u);
+
+    if (t != u->transport)
+      return PA_HOOK_OK;
+
+    volume = (pa_volume_t) (t->source_volume * PA_VOLUME_NORM / A2DP_MAX_VOLUME);
+
+    /* increment volume by one to correct rounding errors */
+    if (volume < PA_VOLUME_NORM)
+        volume++;
+
+    pa_cvolume_set(&v, u->sample_spec.channels, volume);
+    pa_source_set_volume(u->source, &v, true, true);
+    pa_source_volume_changed(u->source, &v);
+
+    return PA_HOOK_OK;
+}
+
 /* Run from main thread context */
 static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {
     struct bluetooth_msg *m = BLUETOOTH_MSG(obj);
@@ -2172,6 +2197,8 @@ int pa__init(pa_module* m) {
     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_a2dp_source_volume_changed_slot =
+        pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_SOURCE_VOLUME_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_a2dp_source_volume_changed_cb, u);
 
     if (add_card(u) < 0)
         goto fail;
@@ -2231,6 +2258,9 @@ void pa__done(pa_module *m) {
     if (u->transport_microphone_gain_changed_slot)
         pa_hook_slot_free(u->transport_microphone_gain_changed_slot);
 
+    if (u->transport_a2dp_source_volume_changed_slot)
+        pa_hook_slot_free(u->transport_a2dp_source_volume_changed_slot);
+
     if (u->sbc_info.buffer)
         pa_xfree(u->sbc_info.buffer);
 
-- 
2.1.4



More information about the pulseaudio-discuss mailing list