From c667befe9a2e03a35a69c012e0e2330481f05e1d Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Mon, 18 Jan 2021 14:26:47 +0100 Subject: [PATCH] bluetooth: Provide (HSP/HFP-received) battery level as device property Part-of: --- src/modules/bluetooth/backend-native.c | 1 + src/modules/bluetooth/bluez5-util.c | 6 ++++ src/modules/bluetooth/bluez5-util.h | 5 ++++ src/modules/bluetooth/module-bluez5-device.c | 30 ++++++++++++++++++++ 4 files changed, 42 insertions(+) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 8ba2ded0a..2882d79ac 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -769,6 +769,7 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i switch (key) { case 1: pa_log_notice("Battery Level: %d0%%", val + 1); + pa_bluetooth_device_report_battery_level(t->device, (val + 1) * 10); break; case 2: pa_log_notice("Dock Status: %s", val ? "docked" : "undocked"); diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 067c79777..e55fcf262 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -868,6 +868,12 @@ bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) { return false; } +void pa_bluetooth_device_report_battery_level(pa_bluetooth_device *d, uint8_t level) { + d->has_battery_level = true; + d->battery_level = level; + pa_hook_fire(&d->discovery->hooks[PA_BLUETOOTH_HOOK_DEVICE_BATTERY_LEVEL_CHANGED], d); +} + static int transport_state_from_string(const char* value, pa_bluetooth_transport_state_t *state) { pa_assert(value); pa_assert(state); diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index e4580869f..ac9c8da10 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -64,6 +64,7 @@ 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_DEVICE_UNLINK, /* Call data: pa_bluetooth_device */ + PA_BLUETOOTH_HOOK_DEVICE_BATTERY_LEVEL_CHANGED, /* Call data: pa_bluetooth_device */ PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */ @@ -150,6 +151,9 @@ struct pa_bluetooth_device { pa_bluetooth_transport *transports[PA_BLUETOOTH_PROFILE_COUNT]; pa_time_event *wait_for_profiles_timer; + + bool has_battery_level; + uint8_t battery_level; }; struct pa_bluetooth_adapter { @@ -197,6 +201,7 @@ void pa_bluetooth_transport_load_a2dp_sink_volume(pa_bluetooth_transport *t); bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d); bool pa_bluetooth_device_switch_codec(pa_bluetooth_device *device, pa_bluetooth_profile_t profile, pa_hashmap *capabilities_hashmap, const pa_a2dp_endpoint_conf *endpoint_conf, void (*codec_switch_cb)(bool, pa_bluetooth_profile_t profile, void *), void *userdata); +void pa_bluetooth_device_report_battery_level(pa_bluetooth_device *d, uint8_t level); pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_discovery *y, const char *path); pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local); diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 7fe785883..579c63c0f 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -103,6 +103,7 @@ struct userdata { pa_core *core; pa_hook_slot *device_connection_changed_slot; + pa_hook_slot *device_battery_level_changed_slot; pa_hook_slot *transport_state_changed_slot; pa_hook_slot *transport_sink_volume_changed_slot; pa_hook_slot *transport_source_volume_changed_slot; @@ -2157,6 +2158,12 @@ static int add_card(struct userdata *u) { data.name = pa_sprintf_malloc("bluez_card.%s", d->address); data.namereg_fail = false; + if (d->has_battery_level) { + // See device_battery_level_changed_cb + uint8_t level = d->battery_level; + pa_proplist_setf(data.proplist, "bluetooth.battery", "%d%%", level); + } + create_card_ports(u, data.ports); PA_HASHMAP_FOREACH(uuid, d->uuids, state) { @@ -2295,6 +2302,22 @@ static pa_hook_result_t device_connection_changed_cb(pa_bluetooth_discovery *y, return PA_HOOK_OK; } +static pa_hook_result_t device_battery_level_changed_cb(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) { + uint8_t level; + + pa_assert(d); + pa_assert(u); + + if (d != u->device || !d->has_battery_level) + return PA_HOOK_OK; + + level = d->battery_level; + + pa_proplist_setf(u->card->proplist, "bluetooth.battery", "%d%%", level); + + return PA_HOOK_OK; +} + /* Run from main thread */ static pa_hook_result_t transport_state_changed_cb(pa_bluetooth_discovery *y, pa_bluetooth_transport *t, struct userdata *u) { pa_assert(t); @@ -2691,6 +2714,10 @@ int pa__init(pa_module* m) { pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) device_connection_changed_cb, u); + u->device_battery_level_changed_slot = + pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_DEVICE_BATTERY_LEVEL_CHANGED), + PA_HOOK_NORMAL, (pa_hook_cb_t) device_battery_level_changed_cb, u); + u->transport_state_changed_slot = pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_state_changed_cb, u); @@ -2767,6 +2794,9 @@ void pa__done(pa_module *m) { if (u->device_connection_changed_slot) pa_hook_slot_free(u->device_connection_changed_slot); + if (u->device_battery_level_changed_slot) + pa_hook_slot_free(u->device_battery_level_changed_slot); + if (u->transport_state_changed_slot) pa_hook_slot_free(u->transport_state_changed_slot);