From 071b3e7fc5a89ddc1c7d51ca5854aa661e4cc33b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 25 Mar 2009 17:57:19 -0300 Subject: Update ipc to match new message headers introduced on BlueZ 4.34. --- src/modules/bluetooth/module-bluetooth-device.c | 46 ++++++++++++++----------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 2500fb09..d09dc2c9 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -311,7 +311,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp * } else if (u->profile == PROFILE_A2DP) { while (bytes_left > 0) { - if (codec->type == BT_A2DP_CODEC_SBC) + if ((codec->type == BT_A2DP_SBC_SINK) && !codec->lock) break; bytes_left -= codec->length; @@ -321,7 +321,7 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp * if (bytes_left <= 0 || codec->length != sizeof(u->a2dp.sbc_capabilities)) return -1; - pa_assert(codec->type == BT_A2DP_CODEC_SBC); + pa_assert(codec->type == BT_A2DP_SBC_SINK); memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities)); } @@ -344,7 +344,7 @@ static int get_caps(struct userdata *u) { msg.getcaps_req.h.name = BT_GET_CAPABILITIES; msg.getcaps_req.h.length = sizeof(msg.getcaps_req); - pa_strlcpy(msg.getcaps_req.device, u->address, sizeof(msg.getcaps_req.device)); + pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object)); if (u->profile == PROFILE_A2DP) msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP; else { @@ -602,12 +602,29 @@ static void setup_sbc(struct a2dp_info *a2dp) { static int set_conf(struct userdata *u) { union { + struct bt_open_req open_req; + struct bt_open_rsp open_rsp; struct bt_set_configuration_req setconf_req; struct bt_set_configuration_rsp setconf_rsp; bt_audio_error_t error; uint8_t buf[BT_SUGGESTED_BUFFER_SIZE]; } msg; + memset(&msg, 0, sizeof(msg)); + msg.open_req.h.type = BT_REQUEST; + msg.open_req.h.name = BT_OPEN; + msg.open_req.h.length = sizeof(msg.open_req); + + pa_strlcpy(msg.open_req.object, u->path, sizeof(msg.open_req.object)); + msg.open_req.seid = u->profile == PROFILE_A2DP ? u->a2dp.sbc_capabilities.capability.seid : BT_A2DP_SEID_RANGE + 1; + msg.open_req.lock = u->profile == PROFILE_A2DP ? BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK; + + if (service_send(u, &msg.open_req.h) < 0) + return -1; + + if (service_expect(u, &msg.open_rsp.h, sizeof(msg), BT_OPEN, sizeof(msg.open_rsp)) < 0) + return -1; + if (u->profile == PROFILE_A2DP ) { u->sample_spec.format = PA_SAMPLE_S16LE; @@ -626,15 +643,14 @@ static int set_conf(struct userdata *u) { msg.setconf_req.h.name = BT_SET_CONFIGURATION; msg.setconf_req.h.length = sizeof(msg.setconf_req); - pa_strlcpy(msg.setconf_req.device, u->address, sizeof(msg.setconf_req.device)); - msg.setconf_req.access_mode = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_ACCESS_MODE_WRITE : BT_CAPABILITIES_ACCESS_MODE_READWRITE; - - msg.setconf_req.codec.transport = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_TRANSPORT_A2DP : BT_CAPABILITIES_TRANSPORT_SCO; - if (u->profile == PROFILE_A2DP) { memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities, sizeof(u->a2dp.sbc_capabilities)); - msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec); + } else { + msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO; + msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1; + msg.setconf_req.codec.length = sizeof(pcm_capabilities_t); } + msg.setconf_req.h.length += msg.setconf_req.codec.length - sizeof(msg.setconf_req.codec); if (service_send(u, &msg.setconf_req.h) < 0) return -1; @@ -642,18 +658,6 @@ static int set_conf(struct userdata *u) { if (service_expect(u, &msg.setconf_rsp.h, sizeof(msg), BT_SET_CONFIGURATION, sizeof(msg.setconf_rsp)) < 0) return -1; - if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_A2DP) || - (u->profile == PROFILE_HSP && msg.setconf_rsp.transport != BT_CAPABILITIES_TRANSPORT_SCO)) { - pa_log("Transport doesn't match what we requested."); - return -1; - } - - if ((u->profile == PROFILE_A2DP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_WRITE) || - (u->profile == PROFILE_HSP && msg.setconf_rsp.access_mode != BT_CAPABILITIES_ACCESS_MODE_READWRITE)) { - pa_log("Access mode doesn't match what we requested."); - return -1; - } - u->link_mtu = msg.setconf_rsp.link_mtu; /* setup SBC encoder now we agree on parameters */ -- cgit From 168c741b644a1134bc7c2ca51adb094ec736c160 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 24 Mar 2009 12:04:52 -0300 Subject: Query and make use of the current configuration. --- src/modules/bluetooth/module-bluetooth-device.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index d09dc2c9..bcb65a47 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -275,7 +275,7 @@ static ssize_t service_expect(struct userdata*u, bt_audio_msg_header_t *rsp, siz return 0; } -static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *rsp) { +static int parse_caps(struct userdata *u, uint8_t seid, const struct bt_get_capabilities_rsp *rsp) { uint16_t bytes_left; const codec_capabilities_t *codec; @@ -306,6 +306,9 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp * pa_assert(codec->type == BT_HFP_CODEC_PCM); + if (codec->configured && seid == 0) + return codec->seid; + memcpy(&u->hsp.pcm_capabilities, codec, sizeof(u->hsp.pcm_capabilities)); } else if (u->profile == PROFILE_A2DP) { @@ -323,19 +326,23 @@ static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp * pa_assert(codec->type == BT_A2DP_SBC_SINK); + if (codec->configured && seid == 0) + return codec->seid; + memcpy(&u->a2dp.sbc_capabilities, codec, sizeof(u->a2dp.sbc_capabilities)); } return 0; } -static int get_caps(struct userdata *u) { +static int get_caps(struct userdata *u, uint8_t seid) { union { struct bt_get_capabilities_req getcaps_req; struct bt_get_capabilities_rsp getcaps_rsp; bt_audio_error_t error; uint8_t buf[BT_SUGGESTED_BUFFER_SIZE]; } msg; + int ret; pa_assert(u); @@ -343,6 +350,7 @@ static int get_caps(struct userdata *u) { msg.getcaps_req.h.type = BT_REQUEST; msg.getcaps_req.h.name = BT_GET_CAPABILITIES; msg.getcaps_req.h.length = sizeof(msg.getcaps_req); + msg.getcaps_req.seid = seid; pa_strlcpy(msg.getcaps_req.object, u->path, sizeof(msg.getcaps_req.object)); if (u->profile == PROFILE_A2DP) @@ -359,7 +367,11 @@ static int get_caps(struct userdata *u) { if (service_expect(u, &msg.getcaps_rsp.h, sizeof(msg), BT_GET_CAPABILITIES, 0) < 0) return -1; - return parse_caps(u, &msg.getcaps_rsp); + ret = parse_caps(u, seid, &msg.getcaps_rsp); + if (ret <= 0) + return ret; + + return get_caps(u, ret); } static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode) { @@ -1575,7 +1587,7 @@ static int init_bt(struct userdata *u) { static int setup_bt(struct userdata *u) { pa_assert(u); - if (get_caps(u) < 0) + if (get_caps(u, 0) < 0) return -1; pa_log_debug("Got device capabilities"); -- cgit From 13f1c4413b54489d8ff7ddbbd8d36de26049e12d Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 26 Mar 2009 15:38:40 -0300 Subject: Do not reconfigure capabilities. --- src/modules/bluetooth/module-bluetooth-device.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index bcb65a47..0a3c91a5 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -462,6 +462,9 @@ static int setup_a2dp(struct userdata *u) { } } + if (cap->capability.configured) + return 0; + if (u->sample_spec.channels <= 1) { if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; -- cgit From 61cd6d4c19f77e560cec4325061efe4723816481 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 24 Mar 2009 14:38:52 +0200 Subject: bluetooth: fail when switching on non-connected profile --- src/modules/bluetooth/module-bluetooth-device.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 0a3c91a5..4c1f1c3e 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -133,6 +133,7 @@ struct userdata { char *address; char *path; + const pa_bluetooth_device* device; pa_dbus_connection *connection; @@ -1733,6 +1734,15 @@ 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) { + pa_log_warn("HSP is not connected, refused to switch profile"); + return -1; + } + else if (u->device->audio_sink_connected <= 0 && *d == PROFILE_A2DP) { + pa_log_warn("A2DP is not connected, refused to switch profile"); + return -1; + } + if (u->sink) { inputs = pa_sink_move_all_start(u->sink); #ifdef NOKIA @@ -1926,7 +1936,6 @@ int pa__init(pa_module* m) { uint32_t channels; struct userdata *u; const char *address, *path; - const pa_bluetooth_device *d; pa_bluetooth_discovery *y = NULL; DBusError err; char *mike, *speaker; @@ -1987,11 +1996,11 @@ int pa__init(pa_module* m) { if (!(y = pa_bluetooth_discovery_get(m->core))) goto fail; - if (!(d = find_device(u, y, address, path))) + if (!(u->device = find_device(u, y, address, path))) /* should discovery ref be kept? */ goto fail; /* Add the card structure. This will also initialize the default profile */ - if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), d) < 0) + if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), u->device) < 0) goto fail; pa_bluetooth_discovery_unref(y); -- cgit From 9e8c2d393a6e2ef8ceda58ff3db6c3a7a7223d46 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 26 Mar 2009 21:31:12 +0200 Subject: bluetooth: don't access outside array range --- src/modules/bluetooth/module-bluetooth-device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 4c1f1c3e..2c4f29c8 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -448,8 +448,8 @@ static int setup_a2dp(struct userdata *u) { break; } - if ((unsigned) i >= PA_ELEMENTSOF(freq_table)) { - for (; i >= 0; i--) { + if ((unsigned) i == PA_ELEMENTSOF(freq_table)) { + for (--i; i >= 0; i--) { if (cap->frequency & freq_table[i].cap) { u->sample_spec.rate = freq_table[i].rate; cap->frequency = freq_table[i].cap; @@ -463,6 +463,8 @@ static int setup_a2dp(struct userdata *u) { } } + pa_assert(i < PA_ELEMENTSOF(freq_table)); + if (cap->capability.configured) return 0; -- cgit From 87fcb3d5925cc030e957f55399f8c3e96c66cbb5 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Fri, 27 Mar 2009 21:48:04 +0200 Subject: bluetooth: use new audio State properties --- src/modules/bluetooth/module-bluetooth-device.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src/modules/bluetooth/module-bluetooth-device.c') 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; -- cgit