[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
Tue Mar 29 07:34:30 UTC 2016
Hi all,
I just remembered i forgot to add some infos to that patch :
Here is a copy and paste of the bluez signal generated when the volume of
the a2dp source is changed.
signal sender=:1.2 -> dest=(null destination) serial=154
path=/org/bluez/hci0/dev_B4_18_D1_9C_2B_B6/fd3; interface=org.freede
sktop.DBus.Properties; member=PropertiesChanged
string "org.bluez.MediaTransport1"
array [
dict entry(
string "Volume"
variant uint16 31
)
]
array [
]
I hope this attachment will make the review easier.
Thanks a lot and regards,
Mathieu Tournier
On Fri, 11 Mar 2016 at 11:16 Mathieu Tournier <mathieutournier at gmail.com>
wrote:
> 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-discuss/attachments/20160329/50196d56/attachment-0001.html>
-------------- next part --------------
MediaTransport1 hierarchy
=========================
Service org.bluez
Interface org.bluez.MediaTransport1
Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX
Methods fd, uint16, uint16 Acquire()
Acquire transport file descriptor and the MTU for read
and write respectively.
Possible Errors: org.bluez.Error.NotAuthorized
org.bluez.Error.Failed
fd, uint16, uint16 TryAcquire()
Acquire transport file descriptor only if the transport
is in "pending" state at the time the message is
received by BlueZ. Otherwise no request will be sent
to the remote device and the function will just fail
with org.bluez.Error.NotAvailable.
Possible Errors: org.bluez.Error.NotAuthorized
org.bluez.Error.Failed
org.bluez.Error.NotAvailable
void Release()
Releases file descriptor.
Properties object Device [readonly]
Device object which the transport is connected to.
string UUID [readonly]
UUID of the profile which the transport is for.
byte Codec [readonly]
Assigned number of codec that the transport support.
The values should match the profile specification which
is indicated by the UUID.
array{byte} Configuration [readonly]
Configuration blob, it is used as it is so the size and
byte order must match.
string State [readonly]
Indicates the state of the transport. Possible
values are:
"idle": not streaming
"pending": streaming but not acquired
"active": streaming and acquired
uint16 Delay [readwrite]
Optional. Transport delay in 1/10 of millisecond, this
property is only writeable when the transport was
acquired by the sender.
boolean NREC [readwrite]
Optional and HFP specific (external to BlueZ).
Indicates if echo cancelling and noise reduction
functions are active in the transport, this
property is only writeable when the transport
was acquired by the sender.
boolean InbandRingtone [readwrite]
Optional and HFP specific (external to BlueZ).
Indicates if the transport support sending
ringtones, this property is only writeable when
the transport was acquired by the sender.
string Routing [readonly]
Optional and HFP specific (external to BlueZ).
Indicates where is the transport being routed.
Possible Values: "HCI" or "PCM"
uint16 Volume [readwrite]
Optional. Indicates volume level of the transport,
this property is only writeable when the transport was
acquired by the sender.
Note: the property will not be present for HSP/HFP
transports and MicrophoneGain/SpeakerGain should be
used instead.
Possible Values: 0-127
byte MicrophoneGain [readwrite]
Optional. Indicates volume level of the transport's
incoming audio stream for HSP/HFP transports. This
property is only writeable when the transport was
acquired by the sender.
Possible Values: 0-15
byte SpeakerGain [readwrite]
Optional. Indicates volume level of the transport's
outgoing audio stream for HSP/HFP transports. This
property is only writeable when the transport was
acquired by the sender.
Possible Values: 0-15
More information about the pulseaudio-discuss
mailing list