[pulseaudio-discuss] [PATCH] Absolute volume control for A2DP transport

EHfive eh5 at sokka.cn
Sun Oct 14 23:54:47 UTC 2018


On 10/15/18 7:44 AM, EHfive wrote:
>
> 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;
>
here should be " if (match_DISABLE_ABSOLUTE_VOLUME(addr)) "
>
> 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 at lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>> _______________________________________________
>>> pulseaudio-discuss mailing list
>>> pulseaudio-discuss at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
>>>
>
> _______________________________________________
> pulseaudio-discuss mailing list
> pulseaudio-discuss at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/pulseaudio-discuss/attachments/20181015/d9150524/attachment-0001.html>


More information about the pulseaudio-discuss mailing list