[pulseaudio-discuss] [RFC v0 03/15] bluetooth: Parse the tree returned by ObjectManager

Mikel Astiz mikel.astiz.oss at gmail.com
Mon Jan 7 05:14:29 PST 2013


Hi Tanu,

On Sun, Dec 30, 2012 at 2:21 PM, Tanu Kaskinen <tanuk at iki.fi> wrote:
> On Wed, 2012-12-19 at 13:58 +0100, Mikel Astiz wrote:
>> --- a/src/modules/bluetooth/bluetooth-util.c
>> +++ b/src/modules/bluetooth/bluetooth-util.c
>> @@ -366,7 +366,7 @@ static int parse_device_property(pa_bluetooth_device *d, DBusMessageIter *i) {
>>
>>      dbus_message_iter_recurse(i, &variant_i);
>>
>> -/*     pa_log_debug("Parsing property org.bluez.Device.%s", key); */
>> +/*    pa_log_debug("Parsing device property '%s'", key); */
>
> Not that this bothers me much, but I'd personally remove any commented
> out code instead of trying to keep it up to date.
>
>> +static int parse_device_properties(pa_bluetooth_device *d, DBusMessageIter *i) {
>> +    DBusMessageIter element_i;
>> +
>> +    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) < 0)
>> +            return -1;
>> +
>> +        dbus_message_iter_next(&element_i);
>> +    }
>> +
>> +    d->device_info_valid = d->name && d->address;
>> +
>> +    return 0;
>
> Shouldn't the return value be -1 if device_info_valid is 0? And why do

Makes sense. Furthermore, device_info_valid should be set to -1 in this case.

> you only check that the name and address are set, why not other
> properties?

I chose these two because of being non-optional in both BlueZ 4 and 5
and are at the same time being used by PA. We could also check the
alias, paired and trusted properties.

>> +}
>> +
>> +static int parse_interfaces_and_properties(pa_bluetooth_discovery *y, DBusMessageIter *dict_i) {
>> +    DBusMessageIter element_i;
>> +    const char *path;
>> +
>> +    if (dbus_message_iter_get_arg_type(dict_i) != DBUS_TYPE_OBJECT_PATH) {
>> +        pa_log("Expected D-Bus object path in GetManagedObjects() dictionary.");
>> +        return -1;
>> +    }
>> +
>> +    dbus_message_iter_get_basic(dict_i, &path);
>> +
>> +    if (!dbus_message_iter_next(dict_i) || dbus_message_iter_get_arg_type(dict_i) != DBUS_TYPE_ARRAY) {
>> +        pa_log("D-Bus interfaces missing for object %s", path);
>> +        return -1;
>> +    }
>> +
>> +    dbus_message_iter_recurse(dict_i, &element_i);
>> +
>> +    while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
>> +        DBusMessageIter iface_i;
>> +        const char *interface;
>> +
>> +        dbus_message_iter_recurse(&element_i, &iface_i);
>> +
>> +        if (dbus_message_iter_get_arg_type(&iface_i) != DBUS_TYPE_STRING) {
>> +            pa_log("Expected interface name in ObjectManager dictionary.");
>> +            return -1;
>> +        }
>> +
>> +        dbus_message_iter_get_basic(&iface_i, &interface);
>> +
>> +        if (!dbus_message_iter_next(&iface_i) || dbus_message_iter_get_arg_type(&iface_i) != DBUS_TYPE_ARRAY) {
>> +            pa_log("Interface properties missing for %s interface %s", path, interface);
>> +            return -1;
>> +        }
>> +
>> +        if (pa_streq(interface, "org.bluez.Adapter1")) {
>> +            pa_log_debug("Adapter %s found", path);
>> +            register_adapter_endpoints(y, path);
>> +        } else if (pa_streq(interface, "org.bluez.Device1")) {
>> +            pa_bluetooth_device *d;
>> +
>> +            if (pa_hashmap_get(y->devices, path)) {
>> +                pa_log("Found duplicated D-Bus address for device %s", path);
>
> Nitpick: s/address/object path/
>
>> +                return -1;
>> +            }
>> +
>> +            pa_log_debug("Device %s found", path);
>> +
>> +            d = device_new(y, path);
>> +            pa_hashmap_put(y->devices, d->path, d);
>> +
>> +            /* FIXME: BlueZ 5 doesn't support the old Audio interface, and thus it's not possible to know if any audio
>> +               profile is about to be connected. This can introduce regressions with modules such as module-card-restore */
>
> Please wrap comments, at least multi-line comments, at 80 chars. (This
> rule didn't seem to be documented in the coding style wiki page... now
> it is.)

OK, I didn't know about this rule.

>
> Btw, is it in your plans to fix module-card-restore?

I gave this a quick try and I found it more complicated than I first
thought. It's not my highest priority so it might take a while until I
could address this issue.

>
>> +            d->audio_state = PA_BT_AUDIO_STATE_DISCONNECTED;
>> +
>> +            if (parse_device_properties(d, &iface_i) < 0)
>> +                return -1;
>
> The broken device is now left in y->devices. I think it would be better
> to only add the device to y->devices if parsing the properties succeeds,
> and otherwise free the device here.

device_info_valid==-1 seems to serve exactly this purpose, so I'd
avoid changing this behavior in this patch and leave it for later.

>
>> @@ -896,6 +993,23 @@ static void get_managed_objects_reply(DBusPendingCall *pending, void *userdata)
>>      pa_log_info("D-Bus ObjectManager detected so assuming BlueZ version 5.");
>>      y->version = BLUEZ_VERSION_5;
>>
>> +    if (!dbus_message_iter_init(r, &arg_i) || dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
>> +        pa_log("GetManagedObjects() result is not a dictionary.");
>> +        goto finish;
>> +    }
>
> libdbus guarantees that the message contents match the message
> signature, so rather than checking the message argument types separately
> for each argument, you can just check that the message signature is what
> you expect ("a{oa{sa{sv}}}" in this case). Only when you start parsing
> variants it's necessary to check the types again.

OK.

>
>> +
>> +    dbus_message_iter_recurse(&arg_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_interfaces_and_properties(y, &dict_i) < 0)
>> +            goto finish;
>
> I think you should either ignore it here if parsing the properties of an
> object fails, or fail properly (that is, remove all objects and do
> nothing until bluetoothd is restarted). Stopping the discovery process
> half-way if one object is broken doesn't seem like a good error handling
> approach.

I'll ignore the error and proceed with the following objects.

Cheers,
Mikel


More information about the pulseaudio-discuss mailing list