[pulseaudio-discuss] [PATCH 37/56] bluetooth: Parse BlueZ 5 device properties

jprvita at gmail.com jprvita at gmail.com
Fri Jul 12 11:06:52 PDT 2013


From: João Paulo Rechi Vita <jprvita at openbossa.org>

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



More information about the pulseaudio-discuss mailing list