From ca18b8b73357092bbcbe253651f57df43ec538a0 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Thu, 26 May 2022 12:44:07 +0300 Subject: [PATCH] bluez5: endpoint can be used only by one device at a time AVDTP (v1.3 Sec 5.3) has a limitation that a local SEP (on the same adapter) can be connected to at most one remote SEP. Trying to do have it connected to multiple remotes either fails or causes misbehavior later on. Skip SetConfigure the same local endpoint for multiple remote ones in codec switch. BlueZ observes this restriction in SelectConfiguration, so also it won't try to do invalid configurations. In BlueZ 5.64, the SetConfiguration calls succeed, but subsequent transport acquires will fail. (Likely already the SetConfiguration DBus call should fail.) This all has the consequence, with the current approach to the codec=endpoint correspondence, that if multiple devices are connected to the same adapter, they currently have to use different codecs. --- spa/plugins/bluez5/bluez5-dbus.c | 17 +++++++++++++++++ spa/plugins/bluez5/defs.h | 1 + 2 files changed, 18 insertions(+) diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index c2e4a7ba7..6fd375781 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -1867,6 +1867,7 @@ void spa_bt_transport_free(struct spa_bt_transport *transport) if (device && device->connected_profiles != prev_connected) spa_bt_device_emit_profiles_changed(device, device->profiles, prev_connected); + free(transport->endpoint_path); free(transport->path); free(transport); } @@ -2530,6 +2531,7 @@ static void a2dp_codec_switch_next(struct spa_bt_a2dp_codec_switch *sw) static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *sw) { struct spa_bt_remote_endpoint *ep; + struct spa_bt_transport *t; const struct a2dp_codec *codec; uint8_t config[A2DP_MAX_CAPS_SIZE]; char *local_endpoint_base; @@ -2584,6 +2586,19 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s goto next; } + /* Each endpoint can be used by only one device at a time (on each adapter) */ + spa_list_for_each(t, &sw->device->monitor->transport_list, link) { + if (t->device == sw->device) + continue; + if (t->device->adapter != sw->device->adapter) + continue; + if (spa_streq(t->endpoint_path, local_endpoint)) { + spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: endpoint %s in use, try next", + sw, local_endpoint); + goto next; + } + } + res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, &sw->device->monitor->default_audio_info, sw->device->settings, config); @@ -3031,6 +3046,8 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn, transport->volumes[i].hw_volume_max = SPA_BT_VOLUME_A2DP_MAX; } + free(transport->endpoint_path); + transport->endpoint_path = strdup(endpoint); transport->profile = profile; transport->a2dp_codec = codec; transport_update_props(transport, &it[1], NULL); diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 5efb2407f..2bdace5d3 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -574,6 +574,7 @@ struct spa_bt_transport { unsigned int codec; void *configuration; int configuration_len; + char *endpoint_path; uint32_t n_channels; uint32_t channels[64];