From: Jo?o Paulo Rechi Vita <jprvita@xxxxxxxxxxxxx> This code is based on previous work by Mikel Astiz. --- src/modules/bluetooth/bluez5-util.c | 178 +++++++++++++++++++++++++++++++++++- src/modules/bluetooth/bluez5-util.h | 9 ++ 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 746dd78..fe91b0e 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -105,6 +105,31 @@ static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(pa_bluetooth_d return p; } +static const char *pa_bluetooth_dbus_check_variant_property(DBusMessageIter *i) { + const char *key; + + pa_assert(i); + + if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { + pa_log_error("Property name not a string."); + return NULL; + } + + dbus_message_iter_get_basic(i, &key); + + if (!dbus_message_iter_next(i)) { + pa_log_error("Property value missing"); + return NULL; + } + + if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) { + pa_log_error("Property value not a variant."); + return NULL; + } + + return key; +} + pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const char *owner, const char *path, pa_bluetooth_profile_t p, const uint8_t *config, int size, pa_bluetooth_transport_acquire_cb acquire, @@ -228,6 +253,36 @@ bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d) { return false; } +static pa_bluetooth_uuid *pa_bluetooth_uuid_new(const char *uuid) { + pa_bluetooth_uuid *u; + + u = pa_xnew(pa_bluetooth_uuid, 1); + u->uuid = pa_xstrdup(uuid); + PA_LLIST_INIT(pa_bluetooth_uuid, u); + + return u; +} + +static void pa_bluetooth_uuid_free(pa_bluetooth_uuid *u) { + pa_assert(u); + + pa_xfree(u->uuid); + pa_xfree(u); +} + +bool pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid) { + pa_assert(uuid); + + while (uuids) { + if (strcasecmp(uuids->uuid, uuid) == 0) + return true; + + uuids = uuids->next; + } + + return false; +} + static pa_bluetooth_device* pa_bluetooth_discovery_create_device(pa_bluetooth_discovery *y, const char *path) { pa_bluetooth_device *d; @@ -237,6 +292,7 @@ static pa_bluetooth_device* pa_bluetooth_discovery_create_device(pa_bluetooth_di d = pa_xnew0(pa_bluetooth_device, 1); d->discovery = y; d->path = pa_xstrdup(path); + PA_LLIST_HEAD_INIT(pa_bluetooth_uuid, d->uuids); pa_hashmap_put(y->devices, d->path, d); @@ -273,6 +329,7 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_d } static void pa_bluetooth_device_free(pa_bluetooth_device *d) { + pa_bluetooth_uuid *u; unsigned i; pa_assert(d); @@ -289,6 +346,11 @@ static void pa_bluetooth_device_free(pa_bluetooth_device *d) { pa_bluetooth_transport_free(t); } + while ((u = d->uuids)) { + PA_LLIST_REMOVE(pa_bluetooth_uuid, d->uuids, u); + pa_bluetooth_uuid_free(u); + } + d->discovery = NULL; pa_xfree(d->path); pa_xfree(d->alias); @@ -319,6 +381,116 @@ static void pa_bluetooth_discovery_remove_all_devices(pa_bluetooth_discovery *y) } } +static int parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i, bool is_property_change) { + const char *key; + DBusMessageIter variant_i; + + pa_assert(d); + + key = pa_bluetooth_dbus_check_variant_property(i); + if (key == NULL) { + pa_log_error("Received invalid property for device %s", d->path); + return -1; + } + + dbus_message_iter_recurse(i, &variant_i); + + switch (dbus_message_iter_get_arg_type(&variant_i)) { + + case DBUS_TYPE_STRING: { + const char *value; + dbus_message_iter_get_basic(&variant_i, &value); + + if (pa_streq(key, "Alias")) { + pa_xfree(d->alias); + d->alias = pa_xstrdup(value); + } else if (pa_streq(key, "Address")) { + if (is_property_change) { + pa_log_error("Device property 'Address' expected to be constant but changed for %s", d->path); + return -1; + } + + if (d->address) { + pa_log_error("Device %s: Received a duplicate Address property.", d->path); + return -1; + } + + d->address = pa_xstrdup(value); + } + + pa_log_debug("%s: %s", key, value); + break; + } + + case DBUS_TYPE_UINT32: { + uint32_t value; + dbus_message_iter_get_basic(&variant_i, &value); + + if (pa_streq(key, "Class")) + d->class_of_device = (int) value; + + pa_log_debug("%s: %d", key, value); + break; + } + + case DBUS_TYPE_ARRAY: { + DBusMessageIter ai; + dbus_message_iter_recurse(&variant_i, &ai); + + if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING && pa_streq(key, "UUIDs")) { + while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) { + pa_bluetooth_uuid *node; + const char *value; + + dbus_message_iter_get_basic(&ai, &value); + + if (pa_bluetooth_uuid_has(d->uuids, value)) { + dbus_message_iter_next(&ai); + continue; + } + + node = pa_bluetooth_uuid_new(value); + PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node); + + pa_log_debug("%s: %s", key, value); + dbus_message_iter_next(&ai); + } + } + + break; + } + } + + return 0; +} + +static int parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i, bool is_property_change) { + DBusMessageIter element_i; + int ret = 0; + + dbus_message_iter_recurse(i, &element_i); + + while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter dict_i; + + dbus_message_iter_recurse(&element_i, &dict_i); + + if (parse_device_property(d, &dict_i, is_property_change) < 0) + ret = -1; + + dbus_message_iter_next(&element_i); + } + + if (!d->address || !d->alias/* || d->paired < 0 || d->trusted < 0*/) { + pa_log_error("Non-optional information missing for device %s", d->path); + d->device_info_valid = -1; + return -1; + } + + d->device_info_valid = 1; + return ret; +} + static void register_endpoint_reply(DBusPendingCall *pending, void *userdata) { DBusMessage *r; pa_dbus_pending *p; @@ -423,6 +595,8 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa register_endpoint(y, path, A2DP_SOURCE_ENDPOINT, A2DP_SOURCE_UUID); register_endpoint(y, path, A2DP_SINK_ENDPOINT, A2DP_SINK_UUID); } else if (pa_streq(interface, BLUEZ_DEVICE_INTERFACE)) { + pa_bluetooth_device *d; + if (pa_bluetooth_discovery_get_device_by_path(y, path)) { pa_log_error("Found duplicated D-Bus path for device %s", path); return; @@ -430,8 +604,8 @@ static void parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessa pa_log_debug("Device %s found", path); - pa_bluetooth_discovery_create_device(y, path); - /* TODO: parse device properties */ + d = pa_bluetooth_discovery_create_device(y, path); + parse_device_properties(d, &iface_i, false); } else pa_log_debug("Unknown interface %s found, skipping", interface); diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index 68c2dc0..b1a112f 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -27,6 +27,7 @@ #define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb" #define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb" +typedef struct pa_bluetooth_uuid pa_bluetooth_uuid; typedef struct pa_bluetooth_transport pa_bluetooth_transport; typedef struct pa_bluetooth_device pa_bluetooth_device; typedef struct pa_bluetooth_discovery pa_bluetooth_discovery; @@ -71,6 +72,11 @@ struct pa_bluetooth_transport { void *userdata; }; +struct pa_bluetooth_uuid { + char *uuid; + PA_LLIST_FIELDS(pa_bluetooth_uuid); +}; + struct pa_bluetooth_device { pa_bluetooth_discovery *discovery; @@ -84,6 +90,7 @@ struct pa_bluetooth_device { int class_of_device; pa_bluetooth_transport *transports[PA_BLUETOOTH_PROFILE_COUNT]; + PA_LLIST_HEAD(pa_bluetooth_uuid, uuids); }; pa_bluetooth_transport *pa_bluetooth_transport_new(pa_bluetooth_device *d, const char *owner, const char *path, @@ -94,6 +101,8 @@ void pa_bluetooth_transport_free(pa_bluetooth_transport *t); bool pa_bluetooth_device_any_transport_connected(const pa_bluetooth_device *d); +bool pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid); + 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 *address); -- 1.7.11.7