diff options
| author | Marc-André Lureau <marc-andre.lureau@nokia.com> | 2009-03-27 21:48:04 +0200 | 
|---|---|---|
| committer | Marc-André Lureau <marc-andre.lureau@nokia.com> | 2009-03-27 22:59:57 +0200 | 
| commit | 87fcb3d5925cc030e957f55399f8c3e96c66cbb5 (patch) | |
| tree | cc17bb3b677284fcf3c4b52ab033c87b0d3d07e3 | |
| parent | 38825d79123678bf0c5d156aaea4bedb888a7fcd (diff) | |
bluetooth: use new audio State properties
| -rw-r--r-- | src/modules/bluetooth/bluetooth-util.c | 109 | ||||
| -rw-r--r-- | src/modules/bluetooth/bluetooth-util.h | 25 | ||||
| -rw-r--r-- | src/modules/bluetooth/module-bluetooth-device.c | 13 | ||||
| -rw-r--r-- | src/modules/bluetooth/module-bluetooth-discover.c | 14 | 
4 files changed, 112 insertions, 49 deletions
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index dfebf663..771afff5 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -42,6 +42,22 @@ struct pa_bluetooth_discovery {  static void get_properties_reply(DBusPendingCall *pending, void *userdata);  static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessage *m, DBusPendingCallNotifyFunction func); +static enum pa_bt_audio_state pa_bt_audio_state_from_string(const char* value) { +    pa_assert(value); + +    if (pa_streq(value, "disconnected")) { +        return PA_BT_AUDIO_STATE_DISCONNECTED; +    } else if (pa_streq(value, "connecting")) { +        return PA_BT_AUDIO_STATE_CONNECTING; +    } else if (pa_streq(value, "connected")) { +        return PA_BT_AUDIO_STATE_CONNECTED; +    } else if (pa_streq(value, "playing")) { +        return PA_BT_AUDIO_STATE_PLAYING; +    } + +    return PA_BT_AUDIO_STATE_INVALID; +} +  static pa_bluetooth_uuid *uuid_new(const char *uuid) {      pa_bluetooth_uuid *u; @@ -66,7 +82,7 @@ static pa_bluetooth_device* device_new(const char *path) {      d->dead = FALSE; -    d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0; +    d->device_info_valid = 0;      d->name = NULL;      d->path = pa_xstrdup(path); @@ -78,9 +94,9 @@ static pa_bluetooth_device* device_new(const char *path) {      d->class = -1;      d->trusted = -1; -    d->audio_sink_connected = -1; - -    d->headset_connected = -1; +    d->audio_state = PA_BT_AUDIO_STATE_INVALID; +    d->audio_sink_state = PA_BT_AUDIO_STATE_INVALID; +    d->headset_state = PA_BT_AUDIO_STATE_INVALID;      return d;  } @@ -102,25 +118,14 @@ static void device_free(pa_bluetooth_device *d) {      pa_xfree(d);  } -static pa_bool_t device_is_loaded(pa_bluetooth_device *d) { -    pa_assert(d); - -    return -        d->device_info_valid && -        d->audio_sink_info_valid && -        d->headset_info_valid; -} -  static pa_bool_t device_is_audio(pa_bluetooth_device *d) {      pa_assert(d); -    pa_assert(d->device_info_valid); -    pa_assert(d->audio_sink_info_valid); -    pa_assert(d->headset_info_valid); -      return -        d->device_info_valid > 0 && -        (d->audio_sink_info_valid > 0 || d->headset_info_valid > 0); +        d->device_info_valid && +        (d->audio_state != PA_BT_AUDIO_STATE_INVALID || +         d->audio_sink_state != PA_BT_AUDIO_STATE_INVALID || +         d->headset_state != PA_BT_AUDIO_STATE_INVALID);  }  static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device *d, DBusMessageIter *i) { @@ -222,6 +227,11 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device                      node = uuid_new(value);                      PA_LLIST_PREPEND(pa_bluetooth_uuid, d->uuids, node); +                    /* this might eventually be racy if .Audio is not there yet, but the State change will come anyway later, so this call is for cold-detection mostly */ +                    pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Audio", "GetProperties")); +                    send_and_add_to_pending(y, d, m, get_properties_reply); + +                    /* Vudentz said the interfaces are here when the UUIDs are announced */                      if (strcasecmp(HSP_HS_UUID, value) == 0 || strcasecmp(HFP_HS_UUID, value) == 0) {                          pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->path, "org.bluez.Headset", "GetProperties"));                          send_and_add_to_pending(y, d, m, get_properties_reply); @@ -242,12 +252,12 @@ static int parse_device_property(pa_bluetooth_discovery *y, pa_bluetooth_device      return 0;  } -static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusMessageIter *i) { +static int parse_audio_property(pa_bluetooth_discovery *u, int *state, DBusMessageIter *i) {      const char *key;      DBusMessageIter variant_i;      pa_assert(u); -    pa_assert(connected); +    pa_assert(state);      pa_assert(i);      if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { @@ -269,17 +279,27 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusM      dbus_message_iter_recurse(i, &variant_i); -/*     pa_log_debug("Parsing property org.bluez.{AudioSink|Headset}.%s", key); */ +/*     pa_log_debug("Parsing property org.bluez.{Audio|AudioSink|Headset}.%s", key); */      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, "State")) +                *state = pa_bt_audio_state_from_string(value); +/*             pa_log_debug("Value %s", value); */ +        } +          case DBUS_TYPE_BOOLEAN: {              dbus_bool_t value;              dbus_message_iter_get_basic(&variant_i, &value); -            if (pa_streq(key, "Connected")) -                *connected = !!value; +            /* if (pa_streq(key, "Connected")) */ +            /*     *connected = !!value; */  /*             pa_log_debug("Value %s", pa_yes_no(value)); */ @@ -294,9 +314,6 @@ static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_b      pa_assert(y);      pa_assert(d); -    if (!device_is_loaded(d)) -        return; -      if (!device_is_audio(d))          return; @@ -326,10 +343,6 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {      if (dbus_message_is_method_call(p->message, "org.bluez.Device", "GetProperties"))          d->device_info_valid = valid; -    else if (dbus_message_is_method_call(p->message, "org.bluez.Headset", "GetProperties")) -        d->headset_info_valid = valid; -    else if (dbus_message_is_method_call(p->message, "org.bluez.AudioSink", "GetProperties")) -        d->audio_sink_info_valid = valid;      if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { @@ -361,12 +374,16 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) {                  if (parse_device_property(y, d, &dict_i) < 0)                      goto finish; +            } else if (dbus_message_has_interface(p->message, "org.bluez.Audio")) { +                if (parse_audio_property(y, &d->audio_state, &dict_i) < 0) +                    goto finish; +              } else if (dbus_message_has_interface(p->message, "org.bluez.Headset")) { -                if (parse_audio_property(y, &d->headset_connected, &dict_i) < 0) +                if (parse_audio_property(y, &d->headset_state, &dict_i) < 0)                      goto finish;              }  else if (dbus_message_has_interface(p->message, "org.bluez.AudioSink")) { -                if (parse_audio_property(y, &d->audio_sink_connected, &dict_i) < 0) +                if (parse_audio_property(y, &d->audio_sink_state, &dict_i) < 0)                      goto finish;              }          } @@ -572,7 +589,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us          found_adapter(y, path);          return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -    } else if (dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") || +    } else if (dbus_message_is_signal(m, "org.bluez.Audio", "PropertyChanged") || +               dbus_message_is_signal(m, "org.bluez.Headset", "PropertyChanged") ||                 dbus_message_is_signal(m, "org.bluez.AudioSink", "PropertyChanged") ||                 dbus_message_is_signal(m, "org.bluez.Device", "PropertyChanged")) { @@ -590,12 +608,16 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us                  if (parse_device_property(y, d, &arg_i) < 0)                      goto fail; +            } else if (dbus_message_has_interface(m, "org.bluez.Audio")) { +                if (parse_audio_property(y, &d->audio_state, &arg_i) < 0) +                    goto fail; +              } else if (dbus_message_has_interface(m, "org.bluez.Headset")) { -                if (parse_audio_property(y, &d->headset_connected, &arg_i) < 0) +                if (parse_audio_property(y, &d->headset_state, &arg_i) < 0)                      goto fail;              }  else if (dbus_message_has_interface(m, "org.bluez.AudioSink")) { -                if (parse_audio_property(y, &d->audio_sink_connected, &arg_i) < 0) +                if (parse_audio_property(y, &d->audio_sink_state, &arg_i) < 0)                      goto fail;              } @@ -690,6 +712,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) {                  "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",                  "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'",                  "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", +                "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",                  "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",                  "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL) < 0) {          pa_log("Failed to add D-Bus matches: %s", err.message); @@ -746,6 +769,7 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) {                                 "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'",                                 "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'",                                 "type='signal',sender='org.bluez',interface='org.bluez.Device',member='PropertyChanged'", +                               "type='signal',sender='org.bluez',interface='org.bluez.Audio',member='PropertyChanged'",                                 "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'",                                 "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL); @@ -833,3 +857,16 @@ char *pa_bluetooth_cleanup_name(const char *name) {      return t;  } + +pa_bool_t 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; +} diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index 57f11725..54114738 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -53,12 +53,20 @@ struct pa_bluetooth_uuid {      PA_LLIST_FIELDS(pa_bluetooth_uuid);  }; +/* This enum is shared among Audio, Headset, and AudioSink, although not all values are acceptable in all profiles */ +enum pa_bt_audio_state { +    PA_BT_AUDIO_STATE_INVALID = -1, +    PA_BT_AUDIO_STATE_DISCONNECTED, +    PA_BT_AUDIO_STATE_CONNECTING, +    PA_BT_AUDIO_STATE_CONNECTED, +    PA_BT_AUDIO_STATE_PLAYING, +    PA_BT_AUDIO_STATE_LAST +}; +  struct pa_bluetooth_device {      pa_bool_t dead;      int device_info_valid;      /* 0: no results yet; 1: good results; -1: bad results ... */ -    int audio_sink_info_valid;  /* ... same here ... */ -    int headset_info_valid;     /* ... and here */      /* Device information */      char *name; @@ -71,11 +79,14 @@ struct pa_bluetooth_device {      int class;      int trusted; -    /* AudioSink information */ -    int audio_sink_connected; +    /* Audio state */ +    int audio_state; -    /* Headset information */ -    int headset_connected; +    /* AudioSink state */ +    int audio_sink_state; + +    /* Headset state */ +    int headset_state;  };  pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core); @@ -93,4 +104,6 @@ const char* pa_bluetooth_get_form_factor(uint32_t class);  char *pa_bluetooth_cleanup_name(const char *name); +pa_bool_t pa_bluetooth_uuid_has(pa_bluetooth_uuid *uuids, const char *uuid); +  #endif diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 2c4f29c8..9fc1531e 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -1736,11 +1736,11 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {      d = PA_CARD_PROFILE_DATA(new_profile); -    if (u->device->headset_connected <= 0 && *d == PROFILE_HSP) { +    if (u->device->headset_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_HSP) {          pa_log_warn("HSP is not connected, refused to switch profile");          return -1;      } -    else if (u->device->audio_sink_connected <= 0 && *d == PROFILE_A2DP) { +    else if (u->device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) {          pa_log_warn("A2DP is not connected, refused to switch profile");          return -1;      } @@ -1821,7 +1821,11 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl      data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); -    if (device->audio_sink_info_valid > 0) { +    /* we base hsp/a2dp availability on UUIDs. +       Ideally, it would be based on "Connected" state, but +       we can't afford to wait for this information when +       we are loaded with profile="hsp", for instance */ +    if (pa_bluetooth_uuid_has(device->uuids, A2DP_SINK_UUID)) {          p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(enum profile));          p->priority = 10;          p->n_sinks = 1; @@ -1835,7 +1839,8 @@ static int add_card(struct userdata *u, const char *default_profile, const pa_bl          pa_hashmap_put(data.profiles, p->name, p);      } -    if (device->headset_info_valid > 0) { +    if (pa_bluetooth_uuid_has(device->uuids, HSP_HS_UUID) || +	pa_bluetooth_uuid_has(device->uuids, HFP_HS_UUID)) {          p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile));          p->priority = 20;          p->n_sinks = 1; diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c index 49c7a800..6f3dba12 100644 --- a/src/modules/bluetooth/module-bluetooth-discover.c +++ b/src/modules/bluetooth/module-bluetooth-discover.c @@ -84,8 +84,7 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const      mi = pa_hashmap_get(u->hashmap, d->path);      if (!d->dead && -        d->device_connected > 0 && -        (d->audio_sink_connected > 0 || d->headset_connected > 0)) { +        d->device_connected > 0 && d->audio_state >= PA_BT_AUDIO_STATE_CONNECTED) {          if (!mi) {              pa_module *m = NULL; @@ -93,7 +92,16 @@ static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const              /* Oh, awesome, a new device has shown up and been connected! */ -            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\" profile=\"%s\"", d->address, d->path, d->headset_connected > 0 ? "hsp" : "a2dp"); +            args = pa_sprintf_malloc("address=\"%s\" path=\"%s\"", d->address, d->path); +#if 0 +            /* This is in case we have to use hsp immediately, without waiting for .Audio.State = Connected */ +            if (d->headset_state >= PA_BT_AUDIO_STATE_CONNECTED && somecondition) { +                char *tmp; +                tmp = pa_sprintf_malloc("%s profile=\"hsp\"", args); +                pa_xfree(args); +                args = tmp; +            } +#endif  #ifdef NOKIA              if (pa_modargs_get_value(u->modargs, "sco_sink", NULL) &&  | 
