<div dir="ltr">Hi all,<div><br><div>I just remembered i forgot to add some infos to that patch : </div><div><br><div>Here is a copy and paste of the bluez signal generated when the volume of the a2dp source is changed.</div><div><br></div><div><span style="font-family:monospace">signal sender=:1.2 -> dest=(null destination) serial=154 path=/org/bluez/hci0/dev_B4_18_D1_9C_2B_B6/fd3; interface=org.freede<br>sktop.DBus.Properties; member=PropertiesChanged
<br>   string "org.bluez.MediaTransport1"
<br>   array [
<br>      dict entry(
<br>         string "Volume"
<br>         variant             uint16 31
<br>      )
<br>   ]
<br>   array [
<br>   ]<br></span></div><div><span style="font-family:monospace"><br></span></div><div>I hope this attachment will make the review easier.</div><div><br></div><div>Thanks a lot and regards,</div><div>Mathieu Tournier</div></div><br><div class="gmail_quote"><div dir="ltr">On Fri, 11 Mar 2016 at 11:16 Mathieu Tournier <<a href="mailto:mathieutournier@gmail.com" target="_blank">mathieutournier@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">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))<br>
This work aims to integrate bluez event Volume (org.bluez.MediaTransport1) for A2DP source in pulseaudio.<br>
This permits to take into account A2DP source volume changes (sent using AVRCP protocol).<br>
<br>
Change has been tested with an iphone and an ipad and is fully working.<br>
---<br>
 src/modules/bluetooth/bluez5-util.c          | 15 ++++++++++++++<br>
 src/modules/bluetooth/bluez5-util.h          | 13 ++++++++----<br>
 src/modules/bluetooth/module-bluez5-device.c | 30 ++++++++++++++++++++++++++++<br>
 3 files changed, 54 insertions(+), 4 deletions(-)<br>
<br>
diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c<br>
index 03c76bf..c216c6e 100644<br>
--- a/src/modules/bluetooth/bluez5-util.c<br>
+++ b/src/modules/bluetooth/bluez5-util.c<br>
@@ -185,6 +185,14 @@ void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_tr<br>
         pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED], t->device);<br>
 }<br>
<br>
+void pa_bluetooth_transport_set_source_volume(pa_bluetooth_transport *t,uint16_t volume) {<br>
+<br>
+    pa_assert(t);<br>
+    t->source_volume = volume;<br>
+    pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_SOURCE_VOLUME_CHANGED], t);<br>
+<br>
+}<br>
+<br>
 void pa_bluetooth_transport_put(pa_bluetooth_transport *t) {<br>
     pa_assert(t);<br>
<br>
@@ -340,6 +348,13 @@ static void parse_transport_property(pa_bluetooth_transport *t, DBusMessageIter<br>
<br>
                 pa_bluetooth_transport_set_state(t, state);<br>
             }<br>
+        case DBUS_TYPE_UINT16: {<br>
+            uint16_t uintValue;<br>
+            dbus_message_iter_get_basic(&variant_i, &uintValue);<br>
+<br>
+                if (pa_streq(key, "Volume"))<br>
+                    pa_bluetooth_transport_set_source_volume(t,uintValue);<br>
+            }<br>
<br>
             break;<br>
         }<br>
diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h<br>
index d66e8a3..3380074 100644<br>
--- a/src/modules/bluetooth/bluez5-util.h<br>
+++ b/src/modules/bluetooth/bluez5-util.h<br>
@@ -36,10 +36,11 @@ typedef struct pa_bluetooth_discovery pa_bluetooth_discovery;<br>
 typedef struct pa_bluetooth_backend pa_bluetooth_backend;<br>
<br>
 typedef enum pa_bluetooth_hook {<br>
-    PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,          /* Call data: pa_bluetooth_device */<br>
-    PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,            /* Call data: pa_bluetooth_transport */<br>
-    PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED,  /* Call data: pa_bluetooth_transport */<br>
-    PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED,     /* Call data: pa_bluetooth_transport */<br>
+    PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED,            /* Call data: pa_bluetooth_device */<br>
+    PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED,              /* Call data: pa_bluetooth_transport */<br>
+    PA_BLUETOOTH_HOOK_TRANSPORT_MICROPHONE_GAIN_CHANGED,    /* Call data: pa_bluetooth_transport */<br>
+    PA_BLUETOOTH_HOOK_TRANSPORT_SPEAKER_GAIN_CHANGED,       /* Call data: pa_bluetooth_transport */<br>
+    PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_SOURCE_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */<br>
     PA_BLUETOOTH_HOOK_MAX<br>
 } pa_bluetooth_hook_t;<br>
<br>
@@ -63,6 +64,7 @@ typedef void (*pa_bluetooth_transport_release_cb)(pa_bluetooth_transport *t);<br>
 typedef void (*pa_bluetooth_transport_destroy_cb)(pa_bluetooth_transport *t);<br>
 typedef void (*pa_bluetooth_transport_set_speaker_gain_cb)(pa_bluetooth_transport *t, uint16_t gain);<br>
 typedef void (*pa_bluetooth_transport_set_microphone_gain_cb)(pa_bluetooth_transport *t, uint16_t gain);<br>
+typedef void (*pa_bluetooth_transport_set_a2dp_source_volume_cb)(pa_bluetooth_transport *t, uint16_t volume);<br>
<br>
 struct pa_bluetooth_transport {<br>
     pa_bluetooth_device *device;<br>
@@ -77,6 +79,7 @@ struct pa_bluetooth_transport {<br>
<br>
     uint16_t microphone_gain;<br>
     uint16_t speaker_gain;<br>
+    uint16_t source_volume;<br>
<br>
     pa_bluetooth_transport_state_t state;<br>
<br>
@@ -85,6 +88,7 @@ struct pa_bluetooth_transport {<br>
     pa_bluetooth_transport_destroy_cb destroy;<br>
     pa_bluetooth_transport_set_speaker_gain_cb set_speaker_gain;<br>
     pa_bluetooth_transport_set_microphone_gain_cb set_microphone_gain;<br>
+    pa_bluetooth_transport_set_a2dp_source_volume_cb set_source_volume;<br>
     void *userdata;<br>
 };<br>
<br>
@@ -139,6 +143,7 @@ pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const<br>
                                                    pa_bluetooth_profile_t p, const uint8_t *config, size_t size);<br>
<br>
 void pa_bluetooth_transport_set_state(pa_bluetooth_transport *t, pa_bluetooth_transport_state_t state);<br>
+void pa_bluetooth_transport_set_source_volume(pa_bluetooth_transport *t, uint16_t volume);<br>
 void pa_bluetooth_transport_put(pa_bluetooth_transport *t);<br>
 void pa_bluetooth_transport_unlink(pa_bluetooth_transport *t);<br>
 void pa_bluetooth_transport_free(pa_bluetooth_transport *t);<br>
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c<br>
index 84e6d55..2aa7277 100644<br>
--- a/src/modules/bluetooth/module-bluez5-device.c<br>
+++ b/src/modules/bluetooth/module-bluez5-device.c<br>
@@ -65,6 +65,7 @@ PA_MODULE_USAGE("path=<device object path>");<br>
 #define BITPOOL_DEC_LIMIT 32<br>
 #define BITPOOL_DEC_STEP 5<br>
 #define HSP_MAX_GAIN 15<br>
+#define A2DP_MAX_VOLUME 127<br>
<br>
 static const char* const valid_modargs[] = {<br>
     "path",<br>
@@ -104,6 +105,7 @@ struct userdata {<br>
     pa_hook_slot *transport_state_changed_slot;<br>
     pa_hook_slot *transport_speaker_gain_changed_slot;<br>
     pa_hook_slot *transport_microphone_gain_changed_slot;<br>
+    pa_hook_slot *transport_a2dp_source_volume_changed_slot;<br>
<br>
     pa_bluetooth_discovery *discovery;<br>
     pa_bluetooth_device *device;<br>
@@ -2102,6 +2104,29 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov<br>
     return PA_HOOK_OK;<br>
 }<br>
<br>
+static pa_hook_result_t transport_a2dp_source_volume_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) {<br>
+    pa_volume_t volume;<br>
+    pa_cvolume v;<br>
+<br>
+    pa_assert(t);<br>
+    pa_assert(u);<br>
+<br>
+    if (t != u->transport)<br>
+      return PA_HOOK_OK;<br>
+<br>
+    volume = (pa_volume_t) (t->source_volume * PA_VOLUME_NORM / A2DP_MAX_VOLUME);<br>
+<br>
+    /* increment volume by one to correct rounding errors */<br>
+    if (volume < PA_VOLUME_NORM)<br>
+        volume++;<br>
+<br>
+    pa_cvolume_set(&v, u->sample_spec.channels, volume);<br>
+    pa_source_set_volume(u->source, &v, true, true);<br>
+    pa_source_volume_changed(u->source, &v);<br>
+<br>
+    return PA_HOOK_OK;<br>
+}<br>
+<br>
 /* Run from main thread context */<br>
 static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t offset, pa_memchunk *chunk) {<br>
     struct bluetooth_msg *m = BLUETOOTH_MSG(obj);<br>
@@ -2172,6 +2197,8 @@ int pa__init(pa_module* m) {<br>
     u->transport_microphone_gain_changed_slot =<br>
         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);<br>
<br>
+    u->transport_a2dp_source_volume_changed_slot =<br>
+        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);<br>
<br>
     if (add_card(u) < 0)<br>
         goto fail;<br>
@@ -2231,6 +2258,9 @@ void pa__done(pa_module *m) {<br>
     if (u->transport_microphone_gain_changed_slot)<br>
         pa_hook_slot_free(u->transport_microphone_gain_changed_slot);<br>
<br>
+    if (u->transport_a2dp_source_volume_changed_slot)<br>
+        pa_hook_slot_free(u->transport_a2dp_source_volume_changed_slot);<br>
+<br>
     if (u->sbc_info.buffer)<br>
         pa_xfree(u->sbc_info.buffer);<br>
<br>
--<br>
2.1.4<br>
<br>
</blockquote></div></div></div>