Simply add some lines. Also, volume means host (as sink role)
volume when in profile a2dp_source(device as source role) , don't
need to disable it.
But should we do it in PA? Isn't it Bluez's job?
On 10/15/18 2:54 AM, ValdikSS wrote:
Can you please integrate exceptions from the Android database? https://android.googlesource.com/platform/system/bt/+/master/device/include/interop_database.h Ones with INTEROP_DISABLE_ABSOLUTE_VOLUME On 03/10/2018 16:12, EHfive wrote:On 10/3/18 8:37 PM, EHfive wrote:Require bluez-tools/mpris-proxy running. (No hurt if dosen't) If you need play/pause/next... controls , add configurations below to /etc/dbus-1/system.d/ ------------------------ mpris.conf <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <policy context="default"> <allow send_interface="org.mpris.MediaPlayer2.Player"/> </policy> </busconfig> ------------------------An alternative https://gist.github.com/EHfive/e2a28d0279a6247fab4bac93d73b8571 A python script which implement org.mpris.MediaPlayer2.Player and register mpris player object by calling org.bluez.Media1.RegisterPlayer.=================== diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 2d83373..72cd05a 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -348,6 +348,50 @@ void pa_bluetooth_transport_free(pa_bluetooth_transport *t) { pa_xfree(t); } +static int bluez5_transport_set_property(pa_bluetooth_transport *t, const char *prop_name, int prop_type, void *prop_value){ + DBusMessage *m, *r; + DBusError err; + DBusMessageIter i; + const char * interface = BLUEZ_MEDIA_TRANSPORT_INTERFACE; + + pa_log_debug("Setting property, Owner: %s; Path: %s; Property: %s",t->owner, t->path, prop_name); + + pa_assert(t); + pa_assert(t->device); + pa_assert(t->device->discovery); + + dbus_error_init(&err); + + pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.freedesktop.DBus.Properties", "Set")); + + dbus_message_iter_init_append(m, &i); + + pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &interface)); + pa_assert_se(dbus_message_iter_append_basic(&i, DBUS_TYPE_STRING, &prop_name)); + pa_dbus_append_basic_variant(&i, prop_type, prop_value); + + r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err); + dbus_message_unref(m); + m = NULL; + if(r) { + dbus_message_unref(r); + r = NULL; + } + + if(dbus_error_is_set(&err)) { + pa_log_debug("Failed to set property \"%s.%s\"", interface, prop_name); + return -1; + } + + return 0; +} + +static int bluez5_transport_set_volume(pa_bluetooth_transport *t, uint16_t volume){ + if(t->a2dp_gain == volume) + return 0; + return bluez5_transport_set_property(t, "Volume", DBUS_TYPE_UINT16, &volume); +} + static int bluez5_transport_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) { DBusMessage *m, *r; DBusError err; @@ -441,6 +485,14 @@ bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) { return false; } +void pa_transport_set_a2dp_gain(pa_bluetooth_transport *t, uint16_t a2dp_gain){ + if(t->a2dp_gain == a2dp_gain) + return; + t->a2dp_gain = a2dp_gain; + pa_hook_fire(pa_bluetooth_discovery_hook(t->device->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_GAIN_CHANGED), t); +} + + static int transport_state_from_string(const char* value, pa_bluetooth_transport_state_t *state) { pa_assert(value); pa_assert(state); @@ -483,6 +535,18 @@ static void parse_transport_property(pa_bluetooth_transport *t, DBusMessageIter pa_bluetooth_transport_set_state(t, state); } + break; + } + case DBUS_TYPE_UINT16: { + + uint16_t value; + dbus_message_iter_get_basic(&variant_i, &value); + + if (pa_streq(key, "Volume")) { + pa_log_debug("Transport Volume Changed to %u ", value); + pa_transport_set_a2dp_gain(t, value); + } + break; } } @@ -1468,6 +1532,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage t = pa_bluetooth_transport_new(d, sender, path, p, config, size); t->acquire = bluez5_transport_acquire_cb; t->release = bluez5_transport_release_cb; + t->set_volume = bluez5_transport_set_volume; pa_bluetooth_transport_put(t); pa_log_debug("Transport %s available for profile %s", t->path, pa_bluetooth_profile_to_string(t->profile)); diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index ad30708..5b8149d 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -47,6 +47,7 @@ typedef enum pa_bluetooth_hook { 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_GAIN_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_MAX } pa_bluetooth_hook_t; @@ -70,6 +71,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 int (*pa_bluetooth_transport_set_volume_cb)(pa_bluetooth_transport *t, uint16_t volume); struct pa_bluetooth_transport { pa_bluetooth_device *device; @@ -84,6 +86,7 @@ struct pa_bluetooth_transport { uint16_t microphone_gain; uint16_t speaker_gain; + uint16_t a2dp_gain; pa_bluetooth_transport_state_t state; @@ -92,6 +95,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_volume_cb set_volume; void *userdata; }; diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 351ad12..49a6dba 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -64,6 +64,7 @@ PA_MODULE_USAGE("path=<device object path>" #define BITPOOL_DEC_LIMIT 32 #define BITPOOL_DEC_STEP 5 #define HSP_MAX_GAIN 15 +#define BLUEZ_MAX_GAIN 127 static const char* const valid_modargs[] = { "path", @@ -113,6 +114,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_gain_changed_slot; pa_bluetooth_discovery *discovery; pa_bluetooth_device *device; @@ -1056,6 +1058,37 @@ static void source_set_volume_cb(pa_source *s) { u->transport->set_microphone_gain(u->transport, gain); } +static void source_set_a2dp_volume_cb(pa_source *s) { + uint16_t gain; + pa_volume_t volume; + struct userdata *u; + + pa_assert(s); + pa_assert(s->core); + + u = s->userdata; + + pa_assert(u); + pa_assert(u->source == s); + + if (u->transport->set_volume == NULL) + return; + + gain = (uint16_t) ((pa_cvolume_max(&s->real_volume) * BLUEZ_MAX_GAIN) / PA_VOLUME_NORM); + + pa_log_debug("Real Volume Gain:%u", gain); + + if (gain > BLUEZ_MAX_GAIN) + gain = BLUEZ_MAX_GAIN; + + volume = (pa_volume_t) (gain * PA_VOLUME_NORM / BLUEZ_MAX_GAIN); + + pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume); + pa_cvolume_set(&s->soft_volume, u->sample_spec.channels, volume); + + u->transport->set_volume(u->transport, gain); +} + /* Run from main thread */ static int add_source(struct userdata *u) { pa_source_new_data data; @@ -1109,6 +1142,9 @@ static int add_source(struct userdata *u) { if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) { pa_source_set_set_volume_callback(u->source, source_set_volume_cb); u->source->n_volume_steps = 16; + } else if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) { + pa_source_set_set_volume_callback(u->source, source_set_a2dp_volume_cb); + u->source->n_volume_steps = 1; } return 0; } @@ -1230,6 +1266,40 @@ static void sink_set_volume_cb(pa_sink *s) { u->transport->set_speaker_gain(u->transport, gain); } +static void sink_set_a2dp_volume_cb(pa_sink *s) { + uint16_t gain; + pa_volume_t volume; + struct userdata *u; + + pa_assert(s); + pa_assert(s->core); + + u = s->userdata; + + pa_assert(u); + pa_assert(u->sink == s); + + if (u->transport->set_volume == NULL) + return; + + gain = (uint16_t) ((pa_cvolume_max(&s->real_volume) * BLUEZ_MAX_GAIN) / PA_VOLUME_NORM); + + pa_log_debug("Real Volume Gain:%u", gain); + + if (gain > BLUEZ_MAX_GAIN) + gain = BLUEZ_MAX_GAIN; + + volume = (pa_volume_t) (gain * PA_VOLUME_NORM / BLUEZ_MAX_GAIN); + + pa_cvolume_set(&s->real_volume, u->sample_spec.channels, volume); + + if(u->transport->set_volume(u->transport, gain) < 0) { + pa_cvolume_set(&s->soft_volume, u->sample_spec.channels, PA_VOLUME_NORM); + pa_sink_set_set_volume_callback(s, NULL); + u->transport->a2dp_gain = 0xFFu; + } +} + /* Run from main thread */ static int add_sink(struct userdata *u) { pa_sink_new_data data; @@ -1284,6 +1354,9 @@ static int add_sink(struct userdata *u) { if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) { pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb); u->sink->n_volume_steps = 16; + } else if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) { bdaddr_t addr = u->device->address; if (! match_DISABLE_ABSOLUTE_VOLUME(addr)) { }+ pa_sink_set_set_volume_callback(u->sink, sink_set_a2dp_volume_cb); + u->sink->n_volume_steps = 1; } return 0; } @@ -2340,6 +2413,53 @@ static pa_hook_result_t transport_microphone_gain_changed_cb(pa_bluetooth_discov return PA_HOOK_OK; } +static pa_hook_result_t transport_a2dp_gain_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) { + pa_volume_t volume; + pa_cvolume v; + uint16_t gain; + + pa_assert(t); + pa_assert(u); + + if (t != u->transport) + return PA_HOOK_OK; + bdaddr_t addr = u->device->address; if (! match_DISABLE_ABSOLUTE_VOLUME(addr)) return PA_HOOK_OK; + gain = t->a2dp_gain; + volume = (pa_volume_t) (gain * PA_VOLUME_NORM / BLUEZ_MAX_GAIN); + + pa_cvolume_set(&v, u->sample_spec.channels, volume); + + if(u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK){ + pa_assert(u->sink); + + if(!u->sink->set_volume){ + pa_cvolume_set(&u->sink->soft_volume, u->sample_spec.channels, PA_VOLUME_NORM); + pa_sink_set_set_volume_callback(u->sink, sink_set_a2dp_volume_cb); + } + + + if (gain == 0) + pa_sink_mute_changed(u->sink, true); + else if(u->sink->muted) + pa_sink_mute_changed(u->sink, false); + + pa_sink_volume_changed(u->sink, &v); + } else if(u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE){ + pa_assert(u->source); + + + if (gain == 0) + pa_source_mute_changed(u->source, true); + else if(u->source->muted) + pa_source_mute_changed(u->source, false); + + 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); @@ -2430,6 +2550,9 @@ 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_gain_changed_slot = + pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_A2DP_GAIN_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_a2dp_gain_changed_cb, u); + if (add_card(u) < 0) goto fail; @@ -2491,6 +2614,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_gain_changed_slot) + pa_hook_slot_free(u->transport_a2dp_gain_changed_slot); + if (u->sbc_info.buffer) pa_xfree(u->sbc_info.buffer); _______________________________________________ pulseaudio-discuss mailing list pulseaudio-discuss@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss_______________________________________________ pulseaudio-discuss mailing list pulseaudio-discuss@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss |
_______________________________________________ pulseaudio-discuss mailing list pulseaudio-discuss@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss