From cd501887875b2ee18a0922825dac66102dab3a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Danis?= Date: Fri, 22 Jul 2022 11:01:18 +0200 Subject: [PATCH] bluez5: Fix node creation depending on device role We can't determine which remote endpoint or device the SelectConfiguration() call is associated with. For LE Audio BAP, as this method is called only for the Initiator we set the whole instance as a Central/Initiator. This flag is unset on BAP media endpoint removal. --- spa/plugins/bluez5/bluez5-dbus.c | 23 ++++++++++++++++++++++- spa/plugins/bluez5/bluez5-device.c | 20 ++++++++++++-------- spa/plugins/bluez5/defs.h | 1 + spa/plugins/bluez5/media-sink.c | 10 ++++++++-- spa/plugins/bluez5/media-source.c | 3 +++ 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 852519487..a0badc999 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -133,6 +133,7 @@ struct spa_bt_monitor { struct media_codec_audio_info default_audio_info; bool le_audio_supported; + bool bap_initiator; }; /* Stream endpoints owned by BlueZ for each device */ @@ -641,6 +642,14 @@ static DBusHandlerResult endpoint_select_properties(DBusConnection *conn, DBusMe else res = -ENOTSUP; + /* FIXME: We can't determine which remote endpoint or device the + * SelectConfiguration() call is associated with. For LE Audio BAP, + * as this method is called only for the Initiator we set the whole + * instance as a Central/Initiator. + */ + if (codec->bap) + monitor->bap_initiator = true; + if (res < 0 || res != size) { spa_log_error(monitor->log, "can't select config: %d (%s)", res, spa_strerror(res)); @@ -2004,6 +2013,7 @@ struct spa_bt_transport *spa_bt_transport_create(struct spa_bt_monitor *monitor, t->fd = -1; t->sco_io = NULL; t->delay = SPA_BT_UNKNOWN_DELAY; + t->bap_initiator = monitor->bap_initiator; t->user_data = SPA_PTROFF(t, sizeof(struct spa_bt_transport), void); spa_hook_list_init(&t->listener_list); @@ -4133,6 +4143,17 @@ static void interfaces_removed(struct spa_bt_monitor *monitor, DBusMessageIter * ep = remote_endpoint_find(monitor, object_path); if (ep != NULL) { struct spa_bt_device *d = ep->device; + /* FIXME: As we had been unabe to determine which remote endpoint or + * device the SelectConfiguration() has been associated with, this + * removes the general Central/Initiator flag on LE Audio BAP media + * endpoint removal. + */ + int i; + for (i = 0; monitor->media_codecs[i]; i++) { + const struct media_codec *codec = monitor->media_codecs[i]; + if (codec->codec_id == ep->codec && codec->bap) + monitor->bap_initiator = false; + } remote_endpoint_free(ep); if (d) spa_bt_device_emit_profiles_changed(d, d->profiles, d->connected_profiles); @@ -4446,7 +4467,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us transport_update_props(transport, &it[1], NULL); } - } + } fail: dbus_error_free(&err); diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index 775b96e38..eb002b1ce 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -678,11 +678,8 @@ static int emit_nodes(struct impl *this) 1, SPA_NAME_API_BLUEZ5_SCO_SINK, false); } } - if (this->bt_dev->connected_profiles & (SPA_BT_PROFILE_MEDIA_SOURCE)) { - if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_BAP_SOURCE) - t = find_transport(this, SPA_BT_PROFILE_BAP_SOURCE, 0); - else - t = find_transport(this, SPA_BT_PROFILE_A2DP_SOURCE, 0); + if (this->bt_dev->connected_profiles & (SPA_BT_PROFILE_A2DP_SOURCE)) { + t = find_transport(this, SPA_BT_PROFILE_A2DP_SOURCE, 0); if (t) { this->props.codec = t->media_codec->id; emit_dynamic_node(&this->dyn_media_source, this, t, @@ -731,8 +728,11 @@ static int emit_nodes(struct impl *this) t = find_transport(this, SPA_BT_PROFILE_BAP_SOURCE, 0); if (t) { this->props.codec = t->media_codec->id; - emit_dynamic_node(&this->dyn_media_source, this, t, - DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false); + if (t->bap_initiator) + emit_node(this, t, DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false); + else + emit_dynamic_node(&this->dyn_media_source, this, t, + DEVICE_ID_SOURCE, SPA_NAME_API_BLUEZ5_MEDIA_SOURCE, false); } } @@ -740,7 +740,11 @@ static int emit_nodes(struct impl *this) t = find_transport(this, SPA_BT_PROFILE_BAP_SINK, this->props.codec); if (t) { this->props.codec = t->media_codec->id; - emit_node(this, t, DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_MEDIA_SINK, false); + if (t->bap_initiator) + emit_node(this, t, DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_MEDIA_SINK, false); + else + emit_dynamic_node(&this->dyn_media_sink, this, t, + DEVICE_ID_SINK, SPA_NAME_API_BLUEZ5_MEDIA_SINK, false); } } diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 4c4437dbc..15732dbba 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -602,6 +602,7 @@ struct spa_bt_transport { void *configuration; int configuration_len; char *endpoint_path; + bool bap_initiator; uint32_t n_channels; uint32_t channels[64]; diff --git a/spa/plugins/bluez5/media-sink.c b/spa/plugins/bluez5/media-sink.c index d0104e157..902b988f3 100644 --- a/spa/plugins/bluez5/media-sink.c +++ b/spa/plugins/bluez5/media-sink.c @@ -136,6 +136,7 @@ struct impl { unsigned int started:1; unsigned int following:1; + unsigned int is_output:1; unsigned int is_duplex:1; @@ -1123,8 +1124,10 @@ static void emit_node_info(struct impl *this, bool full) { struct spa_dict_item node_info_items[] = { { SPA_KEY_DEVICE_API, "bluez5" }, - { SPA_KEY_MEDIA_CLASS, "Audio/Sink" }, - { SPA_KEY_NODE_DRIVER, "true" }, + { SPA_KEY_MEDIA_CLASS, this->is_output ? "Audio/Sink" : "Stream/Input/Audio" }, + { "media.name", ((this->transport && this->transport->device->name) ? + this->transport->device->name : this->codec->bap ? "BAP" : "A2DP" ) }, + { SPA_KEY_NODE_DRIVER, this->is_output ? "true" : "false" }, }; uint64_t old = full ? this->info.change_mask : 0; if (full) @@ -1775,6 +1778,9 @@ impl_init(const struct spa_handle_factory *factory, this->is_duplex ? MEDIA_CODEC_FLAG_SINK : 0, this->transport->device->settings); + if (this->codec->bap) + this->is_output = this->transport->bap_initiator; + reset_props(this, &this->props); spa_bt_transport_add_listener(this->transport, diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c index 8586238b3..f9e06e38a 100644 --- a/spa/plugins/bluez5/media-source.c +++ b/spa/plugins/bluez5/media-source.c @@ -1582,6 +1582,9 @@ impl_init(const struct spa_handle_factory *factory, } this->use_duplex_source = this->is_duplex || (this->codec->duplex_codec != NULL); + if (this->codec->bap) + this->is_input = this->transport->bap_initiator; + if (this->codec->init_props != NULL) this->codec_props = this->codec->init_props(this->codec, this->is_duplex ? 0 : MEDIA_CODEC_FLAG_SINK,