[pulseaudio-discuss] [RFCv0 11/21] bluetooth: Parse HandsfreeAudioCard properties

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Fri May 30 02:47:30 PDT 2014


On Tue, 2014-02-04 at 19:03 -0300, jprvita at gmail.com wrote:
> From: João Paulo Rechi Vita <jprvita at openbossa.org>
> 
> ---
>  src/modules/bluetooth/hfaudioagent-ofono.c | 129 ++++++++++++++++++++++++++++-
>  1 file changed, 127 insertions(+), 2 deletions(-)
> 
> diff --git a/src/modules/bluetooth/hfaudioagent-ofono.c b/src/modules/bluetooth/hfaudioagent-ofono.c
> index c939988..d381a29 100644
> --- a/src/modules/bluetooth/hfaudioagent-ofono.c
> +++ b/src/modules/bluetooth/hfaudioagent-ofono.c
> @@ -25,6 +25,9 @@
>  
>  #include <pulsecore/core-util.h>
>  #include <pulsecore/dbus-shared.h>
> +#include <pulsecore/shared.h>
> +
> +#include "bluez5-util.h"
>  
>  #include "hfaudioagent.h"
>  
> @@ -56,9 +59,21 @@
>      "  </interface>"                                                \
>      "</node>"
>  
> +typedef struct hf_audio_card {
> +    char *path;
> +    char *remote;
> +    char *local;

I suggest renaming these to remote_address and local_address for
clarity.

> +
> +    int fd;
> +    uint8_t codec;
> +
> +    pa_bluetooth_transport *transport;
> +} hf_audio_card;
> +
>  struct hf_audio_agent_data {
>      pa_core *core;
>      pa_dbus_connection *connection;
> +    pa_bluetooth_discovery *discovery;
>  
>      bool filter_added;
>      char *ofono_bus_id;
> @@ -84,6 +99,111 @@ static pa_dbus_pending* pa_bluetooth_dbus_send_and_add_to_pending(hf_audio_agent
>      return p;
>  }
>  
> +static hf_audio_card *hf_audio_card_new(hf_audio_agent_data *hfdata, const char *path) {
> +    hf_audio_card *hfac = pa_xnew0(hf_audio_card, 1);
> +
> +    hfac->path = pa_xstrdup(path);
> +    hfac->fd = -1;
> +
> +    return hfac;
> +}
> +
> +static void hf_audio_card_free(void *data) {

Don't use void pointer here just to avoid a cast in the
pa_hashmap_new_full(), it goes against the convention.

> +    hf_audio_card *hfac = data;
> +
> +    pa_assert(hfac);
> +
> +    pa_bluetooth_transport_free(hfac->transport);
> +    pa_xfree(hfac->path);
> +    pa_xfree(hfac->remote);
> +    pa_xfree(hfac->local);
> +    pa_xfree(hfac);
> +}
> +
> +static int hf_audio_agent_transport_acquire(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
> +    return -1;
> +}
> +
> +static void hf_audio_agent_transport_release(pa_bluetooth_transport *t) {
> +}
> +
> +static void hf_audio_agent_card_found(hf_audio_agent_data *hfdata, const char *path, DBusMessageIter *props_i) {
> +    DBusMessageIter i, value_i;
> +    const char *key, *value;
> +    hf_audio_card *hfac;
> +    pa_bluetooth_device *d;
> +
> +    pa_assert(hfdata);
> +    pa_assert(path);
> +    pa_assert(props_i);
> +
> +    pa_log_debug("New HF card found: %s", path);
> +
> +    hfac = hf_audio_card_new(hfdata, path);
> +
> +    while (dbus_message_iter_get_arg_type(props_i) != DBUS_TYPE_INVALID) {
> +        char c;
> +
> +        if ((c = dbus_message_iter_get_arg_type(props_i)) != DBUS_TYPE_DICT_ENTRY) {
> +            pa_log_error("Invalid properties for %s: expected \'e\', received \'%c\'", path, c);
> +            goto fail;
> +        }

These arg type checks can be avoided if you check the message signature.
(Variant contents of course still need to be validated.)

> +
> +        dbus_message_iter_recurse(props_i, &i);
> +
> +        if ((c = dbus_message_iter_get_arg_type(&i)) != DBUS_TYPE_STRING) {
> +            pa_log_error("Invalid properties for %s: expected \'s\', received \'%c\'", path, c);
> +            goto fail;
> +        }
> +
> +        dbus_message_iter_get_basic(&i, &key);
> +        dbus_message_iter_next(&i);
> +
> +        if ((c = dbus_message_iter_get_arg_type(&i)) != DBUS_TYPE_VARIANT) {
> +            pa_log_error("Invalid properties for %s: expected \'v\', received \'%c\'", path, c);
> +            goto fail;
> +        }
> +
> +        dbus_message_iter_recurse(&i, &value_i);
> +
> +        if ((c = dbus_message_iter_get_arg_type(&value_i)) != DBUS_TYPE_STRING) {
> +            pa_log_error("Invalid properties for %s: expected \'s\', received \'%c\'", path, c);
> +            goto fail;
> +        }
> +
> +        dbus_message_iter_get_basic(&value_i, &value);
> +
> +        if (pa_streq(key, "RemoteAddress"))
> +            hfac->remote = pa_xstrdup(value);
> +        else if (pa_streq(key, "LocalAddress"))
> +            hfac->local = pa_xstrdup(value);

You should prepare for duplicate properties. The current code leaks
memory in case of duplicates.

> +
> +        pa_log_debug("%s: %s", key, value);
> +
> +        dbus_message_iter_next(props_i);
> +    }
> +
> +    pa_hashmap_put(hfdata->hf_audio_cards, hfac->path, hfac);
> +
> +    d = pa_bluetooth_discovery_get_device_by_address(hfdata->discovery, hfac->remote, hfac->local);
> +    if (d) {
> +        hfac->transport = pa_bluetooth_transport_new(d, hfdata->ofono_bus_id, path, PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY, NULL, 0);
> +        hfac->transport->acquire = hf_audio_agent_transport_acquire;
> +        hfac->transport->release = hf_audio_agent_transport_release;
> +        hfac->transport->userdata = hfdata;
> +
> +        d->transports[PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY] = hfac->transport;

I don't see matching assignment that sets the device transport to NULL
when the transport is removed.

I think this assignment doesn't belong here anyway, it should be done in
pa_bluetooth_transport_put(). (Setting the device transport to NULL
would then ideally be done in pa_bluetooth_transport_unlink(), because
unlink() should generally mirror put() so that unlink() undoes
everything that is done in put().)

> +
> +        pa_bluetooth_transport_put(hfac->transport);
> +    } else
> +        pa_log_error("Device doesnt exist for %s", path);

It seems possible at least in theory that we get HandsfreeAudioCard
properties from oFono before we get Device properties from BlueZ. Is
there something (other than implementation details) that guarantees that
this doesn't happen? If nothing guarantees that, then we should handle
the case where information from oFono arrives before information from
BlueZ.

> +
> +    return;
> +
> +fail:
> +    pa_xfree(hfac);

Use hf_audio_card_free() to make sure you don't leak any of the struct
members.

> +}
> +
>  static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userdata) {
>      DBusMessage *r;
>      pa_dbus_pending *p;
> @@ -132,7 +252,7 @@ static void hf_audio_agent_get_cards_reply(DBusPendingCall *pending, void *userd
>  
>          dbus_message_iter_recurse(&struct_i, &props_i);
>  
> -        /* TODO: Parse HandsfreeAudioCard properties */
> +        hf_audio_agent_card_found(hfdata, path, &props_i);
>  
>          dbus_message_iter_next(&array_i);
>      }
> @@ -312,7 +432,9 @@ hf_audio_agent_data *hf_audio_agent_init(pa_core *c) {
>  
>      hfdata = pa_xnew0(hf_audio_agent_data, 1);
>      hfdata->core = c;
> -    hfdata->hf_audio_cards = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
> +    hfdata->hf_audio_cards = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, hf_audio_card_free,
> +                                                 NULL);

The third argument of pa_hashmap_new_full() is the function for freeing
the key and the fourth argument is the function for freeing the value.
The key freeing function should be NULL and hf_audio_card_free() should
be used for freeing the value. Doesn't this cause crashing on your
system every time you shut down pulseaudio?

> +    hfdata->discovery = pa_shared_get(c, "bluetooth-discovery");

I think it would be better to pass the discovery object as an argument
to hf_audio_agent_init().

>  
>      dbus_error_init(&err);
>  
> @@ -381,5 +503,8 @@ void hf_audio_agent_done(hf_audio_agent_data *data) {
>          pa_dbus_connection_unref(hfdata->connection);
>      }
>  
> +    if (hfdata->discovery)
> +        hfdata->discovery = NULL;

This is pointless, since hfdata gets freed anyway. Or maybe the idea is
to increase the chances of a quick crash due to null pointer
dereferencing if there's buggy code that tries to access
hfdata->discovery after hfdata is freed? Even in that case having the if
is unnecessary, you can do the assignment unconditionally.

-- 
Tanu



More information about the pulseaudio-discuss mailing list