diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index e37a8facc..d326c312a 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -47,16 +47,6 @@ #define PROP_KEY_HEADSET_ROLES "bluez5.headset-roles" -#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" -#define DBUS_SIGNAL_INTERFACES_ADDED "InterfacesAdded" -#define DBUS_SIGNAL_INTERFACES_REMOVED "InterfacesRemoved" -#define DBUS_SIGNAL_PROPERTIES_CHANGED "PropertiesChanged" - -#define BLUEZ_INTERFACE_BATTERY_PROVIDER "org.bluez.BatteryProvider1" -#define BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER "org.bluez.BatteryProviderManager1" - -#define PIPEWIRE_BATTERY_PROVIDER "/org/freedesktop/pipewire/battery" - struct spa_bt_backend { struct spa_bt_monitor *monitor; @@ -72,8 +62,6 @@ struct spa_bt_backend { struct spa_list rfcomm_list; unsigned int msbc_support_enabled_in_config:1; - unsigned int has_battery_provider; - unsigned int battery_provider_unavailable; }; struct transport_data { @@ -166,205 +154,6 @@ finish: return t; } -// Working with BlueZ Battery Provider. Developed using https://github.com/dgreid/adhd/commit/655b58f as example of DBus calls. -static char *battery_name(struct spa_bt_device *d) -{ - char *path = malloc(strlen(PIPEWIRE_BATTERY_PROVIDER) + strlen(d->path) + 1); - sprintf(path, PIPEWIRE_BATTERY_PROVIDER"%s", d->path); - - // /org/freedesktop/pipewire/battery/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX - return path; -} - -static void write_battery(DBusMessageIter *iter, struct spa_bt_device *device) -{ - DBusMessageIter dict, entry, variant; - - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); - - dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, - &entry); - const char *prop_percentage = "Percentage"; - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &prop_percentage); - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_BYTE_AS_STRING, &variant); - dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &device->battery); - dbus_message_iter_close_container(&entry, &variant); - dbus_message_iter_close_container(&dict, &entry); - - dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); - const char *prop_device = "Device"; - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &prop_device); - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_OBJECT_PATH_AS_STRING, - &variant); - dbus_message_iter_append_basic(&variant, DBUS_TYPE_OBJECT_PATH, &device->path); - dbus_message_iter_close_container(&entry, &variant); - dbus_message_iter_close_container(&dict, &entry); - - dbus_message_iter_close_container(iter, &dict); -} - -static void update_battery(struct spa_bt_device *device) -{ - const char *name = battery_name(device); - spa_log_debug(device->monitor->log, NAME": updating battery: %s", name); - - DBusMessage *msg; - DBusMessageIter iter; - - msg = dbus_message_new_signal(name, - DBUS_INTERFACE_PROPERTIES, - DBUS_SIGNAL_PROPERTIES_CHANGED); - - dbus_message_iter_init_append(msg, &iter); - const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; - dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, - &interface); - - write_battery(&iter, device); - - if (!dbus_connection_send(device->monitor->conn, msg, NULL)) - spa_log_error(device->monitor->log, NAME": Error updating battery"); - - dbus_message_unref(msg); -} - -static void create_battery(struct spa_bt_device *device) { - DBusMessage *msg; - DBusMessageIter iter, entry, dict; - msg = dbus_message_new_signal(PIPEWIRE_BATTERY_PROVIDER, - DBUS_INTERFACE_OBJECT_MANAGER, - DBUS_SIGNAL_INTERFACES_ADDED); - - dbus_message_iter_init_append(msg, &iter); - const char *bat_name = battery_name(device); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, - &bat_name); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sa{sv}}", &dict); - dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); - const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, - &interface); - - write_battery(&entry, device); - - dbus_message_iter_close_container(&dict, &entry); - dbus_message_iter_close_container(&iter, &dict); - - if (!dbus_connection_send(device->monitor->conn, msg, NULL)) { - spa_log_error(device->monitor->backend_native->log, NAME": Failed to create virtual battery for %s", device->address); - return; - } - - dbus_message_unref(msg); - - spa_log_debug(device->monitor->backend_native->log, NAME": Created virtual battery for %s", device->address); - device->has_battery = true; -} - -static void remove_battery(struct spa_bt_device *d) { - if (!d->monitor->backend_native->has_battery_provider) return; - - spa_log_debug(d->monitor->backend_native->log, NAME": Removing battery provider: %s", battery_name(d)); - - DBusMessage *m = dbus_message_new_signal(PIPEWIRE_BATTERY_PROVIDER, - DBUS_INTERFACE_OBJECT_MANAGER, - DBUS_SIGNAL_INTERFACES_REMOVED); - - DBusMessageIter i, entry; - - dbus_message_iter_init_append(m, &i); - const char *bat_name = battery_name(d); - dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, - &bat_name); - dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, - DBUS_TYPE_STRING_AS_STRING, &entry); - const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, - &interface); - dbus_message_iter_close_container(&i, &entry); - - if (!dbus_connection_send(d->monitor->conn, m, NULL)) { - spa_log_error(d->monitor->backend_native->log, NAME": sending " DBUS_SIGNAL_INTERFACES_REMOVED " failed"); - } - - dbus_message_unref(m); - - d->has_battery = false; -} - -static void on_battery_provider_registered(DBusPendingCall *pending_call, - void *data) -{ - DBusMessage *reply; - struct spa_bt_device *device = data; - - reply = dbus_pending_call_steal_reply(pending_call); - dbus_pending_call_unref(pending_call); - - if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { - spa_log_error(device->monitor->log, NAME": Failed to register battery provider. Error: %s", dbus_message_get_error_name(reply)); - spa_log_error(device->monitor->log, NAME": BlueZ battery provider is not available, won't retry to register it"); - device->monitor->backend_native->battery_provider_unavailable = true; - dbus_message_unref(reply); - return; - } - - spa_log_debug(device->monitor->log, NAME": Registered battery provider"); - - device->monitor->backend_native->has_battery_provider = true; - - if (!device->has_battery) - create_battery(device); - - dbus_message_unref(reply); -} - -static void register_battery_provider(DBusConnection *conn, struct spa_bt_device *device) -{ - DBusMessage *method_call; - DBusMessageIter message_iter; - DBusPendingCall *pending_call; - - method_call = dbus_message_new_method_call( - BLUEZ_SERVICE, device->adapter_path, - BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER, - "RegisterBatteryProvider"); - - if (!method_call) { - spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); - return; - } - - dbus_message_iter_init_append(method_call, &message_iter); - const char *object_path = PIPEWIRE_BATTERY_PROVIDER; - dbus_message_iter_append_basic(&message_iter, DBUS_TYPE_OBJECT_PATH, - &object_path); - - if (!dbus_connection_send_with_reply(conn, method_call, &pending_call, - DBUS_TIMEOUT_USE_DEFAULT)) { - dbus_message_unref(method_call); - spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); - return; - } - - dbus_message_unref(method_call); - - if (!pending_call) { - spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); - return; - } - - if (!dbus_pending_call_set_notify( - pending_call, on_battery_provider_registered, - device, NULL)) { - spa_log_error(device->monitor->log, "Failed to register battery provider"); - dbus_pending_call_cancel(pending_call); - dbus_pending_call_unref(pending_call); - } -} - static void rfcomm_free(struct rfcomm *rfcomm) { spa_list_remove(&rfcomm->link); @@ -692,25 +481,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf) spa_log_debug(backend->log, NAME": battery level: %d%%", level); // TODO: report without Battery Provider (using props) - - // BlueZ likely is running without battery provider support, don't try to report battery - if (backend->battery_provider_unavailable) return true; - - // If everything is initialized and battery level has not changed we don't need to send anything to BlueZ - if (backend->has_battery_provider && rfcomm->device->has_battery && rfcomm->device->battery == level) return true; - - rfcomm->device->battery = level; - - if (!backend->has_battery_provider) { - // No provider: register it, create battery in hook - register_battery_provider(backend->conn, rfcomm->device); - } else if (!rfcomm->device->has_battery) { - // Have provider but no battery: create battery, it will already contain percentage - create_battery(rfcomm->device); - } else { - // Just update existing battery percentage - update_battery(rfcomm->device); - } + spa_bt_device_report_battery_level(rfcomm->device, level); } } } else if (strncmp(buf, "AT+APLSIRI?", 11) == 0) { @@ -1373,8 +1144,6 @@ static DBusHandlerResult profile_request_disconnection(DBusConnection *conn, DBu return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } - remove_battery(d); - spa_list_for_each_safe(rfcomm, rfcomm_tmp, &backend->rfcomm_list, link) { if (rfcomm->device == d && rfcomm->profile == profile) { if (rfcomm->source.loop) diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 67b1f80b3..0bae6d9ce 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -53,6 +53,46 @@ #define NAME "bluez5-monitor" +struct spa_bt_monitor { + struct spa_handle handle; + struct spa_device device; + + struct spa_log *log; + struct spa_loop *main_loop; + struct spa_system *main_system; + struct spa_dbus *dbus; + struct spa_dbus_connection *dbus_connection; + DBusConnection *conn; + + struct spa_hook_list hooks; + + uint32_t count; + uint32_t id; + + /* + * Lists of BlueZ objects, kept up-to-date by following DBus events + * initiated by BlueZ. Object lifetime is also determined by that. + */ + struct spa_list adapter_list; + struct spa_list device_list; + struct spa_list remote_endpoint_list; + struct spa_list transport_list; + + unsigned int filters_added:1; + unsigned int objects_listed:1; + + struct spa_bt_backend *backend_native; + struct spa_bt_backend *backend_ofono; + struct spa_bt_backend *backend_hsphfpd; + + struct spa_dict enabled_codecs; + + unsigned int enable_sbc_xq:1; + unsigned int backend_native_registered:1; + unsigned int backend_ofono_registered:1; + unsigned int backend_hsphfpd_registered:1; +}; + /* Stream endpoints owned by BlueZ for each device */ struct spa_bt_remote_endpoint { struct spa_list link; @@ -109,6 +149,211 @@ struct spa_bt_a2dp_codec_switch { static int spa_bt_transport_stop_release_timer(struct spa_bt_transport *transport); static int spa_bt_transport_start_release_timer(struct spa_bt_transport *transport); +// Working with BlueZ Battery Provider. +// Developed using https://github.com/dgreid/adhd/commit/655b58f as an example of DBus calls. + +// Name of battery, formatted as /org/freedesktop/pipewire/battery/org/bluez/hciX/dev_XX_XX_XX_XX_XX_XX +static char *battery_get_name(struct spa_bt_device *device) +{ + char *path = malloc(strlen(PIPEWIRE_BATTERY_PROVIDER) + strlen(device->path) + 1); + sprintf(path, PIPEWIRE_BATTERY_PROVIDER "%s", device->path); + + return path; +} + +// Unregister virtual battery of device +static void battery_remove(struct spa_bt_device *device) { + if (!device->adapter->has_battery_provider) return; + + spa_log_debug(device->monitor->log, NAME": Removing virtual battery: %s", battery_get_name(device)); + + DBusMessage *m = dbus_message_new_signal(PIPEWIRE_BATTERY_PROVIDER, + DBUS_INTERFACE_OBJECT_MANAGER, + DBUS_SIGNAL_INTERFACES_REMOVED); + + DBusMessageIter i, entry; + + dbus_message_iter_init_append(m, &i); + const char *bat_name = battery_get_name(device); + dbus_message_iter_append_basic(&i, DBUS_TYPE_OBJECT_PATH, + &bat_name); + dbus_message_iter_open_container(&i, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, &entry); + const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, + &interface); + dbus_message_iter_close_container(&i, &entry); + + if (!dbus_connection_send(device->monitor->conn, m, NULL)) { + spa_log_error(device->monitor->log, NAME": sending " DBUS_SIGNAL_INTERFACES_REMOVED " failed"); + } + + dbus_message_unref(m); + + device->has_battery = false; +} + +// Create properties for Battery Provider request +static void battery_write_properties(DBusMessageIter *iter, struct spa_bt_device *device) +{ + DBusMessageIter dict, entry, variant; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict); + + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, + &entry); + const char *prop_percentage = "Percentage"; + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &prop_percentage); + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_BYTE_AS_STRING, &variant); + dbus_message_iter_append_basic(&variant, DBUS_TYPE_BYTE, &device->battery); + dbus_message_iter_close_container(&entry, &variant); + dbus_message_iter_close_container(&dict, &entry); + + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); + const char *prop_device = "Device"; + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &prop_device); + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_OBJECT_PATH_AS_STRING, + &variant); + dbus_message_iter_append_basic(&variant, DBUS_TYPE_OBJECT_PATH, &device->path); + dbus_message_iter_close_container(&entry, &variant); + dbus_message_iter_close_container(&dict, &entry); + + dbus_message_iter_close_container(iter, &dict); +} + +// Send current percentage to BlueZ +static void battery_update(struct spa_bt_device *device) +{ + const char *name = battery_get_name(device); + spa_log_debug(device->monitor->log, NAME": updating battery: %s", name); + + DBusMessage *msg; + DBusMessageIter iter; + + msg = dbus_message_new_signal(name, + DBUS_INTERFACE_PROPERTIES, + DBUS_SIGNAL_PROPERTIES_CHANGED); + + dbus_message_iter_init_append(msg, &iter); + const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + &interface); + + battery_write_properties(&iter, device); + + if (!dbus_connection_send(device->monitor->conn, msg, NULL)) + spa_log_error(device->monitor->log, NAME": Error updating battery"); + + dbus_message_unref(msg); +} + +// Create ney virtual battery with value stored in current device object +static void battery_create(struct spa_bt_device *device) { + DBusMessage *msg; + DBusMessageIter iter, entry, dict; + msg = dbus_message_new_signal(PIPEWIRE_BATTERY_PROVIDER, + DBUS_INTERFACE_OBJECT_MANAGER, + DBUS_SIGNAL_INTERFACES_ADDED); + + dbus_message_iter_init_append(msg, &iter); + const char *bat_name = battery_get_name(device); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &bat_name); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sa{sv}}", &dict); + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); + const char *interface = BLUEZ_INTERFACE_BATTERY_PROVIDER; + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, + &interface); + + battery_write_properties(&entry, device); + + dbus_message_iter_close_container(&dict, &entry); + dbus_message_iter_close_container(&iter, &dict); + + if (!dbus_connection_send(device->monitor->conn, msg, NULL)) { + spa_log_error(device->monitor->log, NAME": Failed to create virtual battery for %s", device->address); + return; + } + + dbus_message_unref(msg); + + spa_log_debug(device->monitor->log, NAME": Created virtual battery for %s", device->address); + device->has_battery = true; +} + +static void on_battery_provider_registered(DBusPendingCall *pending_call, + void *data) +{ + DBusMessage *reply; + struct spa_bt_device *device = data; + + reply = dbus_pending_call_steal_reply(pending_call); + dbus_pending_call_unref(pending_call); + + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { + spa_log_error(device->monitor->log, NAME": Failed to register battery provider. Error: %s", dbus_message_get_error_name(reply)); + spa_log_error(device->monitor->log, NAME": BlueZ Battery Provider is not available, won't retry to register it. Make sure you are running BlueZ 5.56+ with experimental features to use Battery Provider."); + device->adapter->battery_provider_unavailable = true; + dbus_message_unref(reply); + return; + } + + spa_log_debug(device->monitor->log, NAME": Registered Battery Provider"); + + device->adapter->has_battery_provider = true; + + if (!device->has_battery) + battery_create(device); + + dbus_message_unref(reply); +} + +// Register Battery Provider for adapter and then create virtual battery for device +static void register_battery_provider(struct spa_bt_device *device) +{ + DBusMessage *method_call; + DBusMessageIter message_iter; + DBusPendingCall *pending_call; + + method_call = dbus_message_new_method_call( + BLUEZ_SERVICE, device->adapter_path, + BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER, + "RegisterBatteryProvider"); + + if (!method_call) { + spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); + return; + } + + dbus_message_iter_init_append(method_call, &message_iter); + const char *object_path = PIPEWIRE_BATTERY_PROVIDER; + dbus_message_iter_append_basic(&message_iter, DBUS_TYPE_OBJECT_PATH, + &object_path); + + if (!dbus_connection_send_with_reply(device->monitor->conn, method_call, &pending_call, + DBUS_TIMEOUT_USE_DEFAULT)) { + dbus_message_unref(method_call); + spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); + return; + } + + dbus_message_unref(method_call); + + if (!pending_call) { + spa_log_error(device->monitor->log, NAME": Failed to register battery provider"); + return; + } + + if (!dbus_pending_call_set_notify( + pending_call, on_battery_provider_registered, + device, NULL)) { + spa_log_error(device->monitor->log, "Failed to register battery provider"); + dbus_pending_call_cancel(pending_call); + dbus_pending_call_unref(pending_call); + } +} static inline void add_dict(struct spa_pod_builder *builder, const char *key, const char *val) { @@ -406,6 +651,7 @@ static void device_free(struct spa_bt_device *device) struct spa_bt_monitor *monitor = device->monitor; spa_log_debug(monitor->log, "%p", device); + battery_remove(device); device_stop_timer(device); device_remove(monitor, device); @@ -3160,3 +3406,28 @@ const struct spa_handle_factory spa_bluez5_dbus_factory = { impl_init, impl_enum_interface_info, }; + +// Report battery percentage to BlueZ using experimental (BlueZ 5.56) Battery Provider API. No-op if no changes occured. +int spa_bt_device_report_battery_level(struct spa_bt_device *device, uint8_t percentage) +{ + // BlueZ likely is running without battery provider support, don't try to report battery + if (device->adapter->battery_provider_unavailable) return 0; + + // If everything is initialized and battery level has not changed we don't need to send anything to BlueZ + if (device->adapter->has_battery_provider && device->has_battery && device->battery == percentage) return 1; + + device->battery = percentage; + + if (!device->adapter->has_battery_provider) { + // No provider: register it, create battery when registered + register_battery_provider(device); + } else if (!device->has_battery) { + // Have provider but no battery: create battery with correct percentage + battery_create(device); + } else { + // Just update existing battery percentage + battery_update(device); + } + + return 1; +} diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 44a065e2e..045caf609 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -48,6 +48,17 @@ extern "C" { #define BLUEZ_MEDIA_INTERFACE BLUEZ_SERVICE ".Media1" #define BLUEZ_MEDIA_ENDPOINT_INTERFACE BLUEZ_SERVICE ".MediaEndpoint1" #define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1" +#define BLUEZ_INTERFACE_BATTERY_PROVIDER BLUEZ_SERVICE ".BatteryProvider1" +#define BLUEZ_INTERFACE_BATTERY_PROVIDER_MANAGER BLUEZ_SERVICE ".BatteryProviderManager1" + +#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager" +#define DBUS_SIGNAL_INTERFACES_ADDED "InterfacesAdded" +#define DBUS_SIGNAL_INTERFACES_REMOVED "InterfacesRemoved" +#define DBUS_SIGNAL_PROPERTIES_CHANGED "PropertiesChanged" + +#define PIPEWIRE_BATTERY_PROVIDER "/org/freedesktop/pipewire/battery" + +#define SPA_BT_HFP_HF_IPHONEACCEV_KEY_BATTERY 1 #define MIN_LATENCY 512 #define MAX_LATENCY 1024 @@ -279,6 +290,8 @@ struct spa_bt_adapter { int powered; unsigned int endpoints_registered:1; unsigned int application_registered:1; + unsigned int has_battery_provider; + unsigned int battery_provider_unavailable; }; enum spa_bt_form_factor { @@ -369,46 +382,6 @@ struct spa_bt_device_events { void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected); }; -struct spa_bt_monitor { - struct spa_handle handle; - struct spa_device device; - - struct spa_log *log; - struct spa_loop *main_loop; - struct spa_system *main_system; - struct spa_dbus *dbus; - struct spa_dbus_connection *dbus_connection; - DBusConnection *conn; - - struct spa_hook_list hooks; - - uint32_t count; - uint32_t id; - - /* - * Lists of BlueZ objects, kept up-to-date by following DBus events - * initiated by BlueZ. Object lifetime is also determined by that. - */ - struct spa_list adapter_list; - struct spa_list device_list; - struct spa_list remote_endpoint_list; - struct spa_list transport_list; - - unsigned int filters_added:1; - unsigned int objects_listed:1; - - struct spa_bt_backend *backend_native; - struct spa_bt_backend *backend_ofono; - struct spa_bt_backend *backend_hsphfpd; - - struct spa_dict enabled_codecs; - - unsigned int enable_sbc_xq:1; - unsigned int backend_native_registered:1; - unsigned int backend_ofono_registered:1; - unsigned int backend_hsphfpd_registered:1; -}; - struct spa_bt_device { struct spa_list link; struct spa_bt_monitor *monitor; @@ -450,6 +423,7 @@ int spa_bt_device_ensure_a2dp_codec(struct spa_bt_device *device, const struct a bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec); const struct a2dp_codec **spa_bt_device_get_supported_a2dp_codecs(struct spa_bt_device *device, size_t *count); int spa_bt_device_release_transports(struct spa_bt_device *device); +int spa_bt_device_report_battery_level(struct spa_bt_device *device, uint8_t percentage); #define spa_bt_device_emit(d,m,v,...) spa_hook_list_call(&(d)->listener_list, \ struct spa_bt_device_events, \ @@ -491,9 +465,6 @@ struct spa_bt_transport_implementation { int (*destroy) (void *data); }; -// Key for getting battery state -#define SPA_BT_HFP_HF_IPHONEACCEV_KEY_BATTERY 1 - struct spa_bt_transport { struct spa_list link; struct spa_bt_monitor *monitor;