From: "Frédéric Danis" <frederic.danis@collabora.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ 1/3] audio: Add ability to desynchronized linked transport
Date: Mon, 27 Apr 2026 19:20:54 +0200 [thread overview]
Message-ID: <20260427172056.148115-2-frederic.danis@collabora.com> (raw)
In-Reply-To: <20260427172056.148115-1-frederic.danis@collabora.com>
If bluetoothd is started in testing mode a new Desynchronized property
is added, allowing to prevent automatic acquire of linked transport
objects.
When desynchronized, each transports needs to be acquired separately.
This allows to pass PTS tests BAP/UCL/STR/BV-543-C and BV-546-C.
---
profiles/audio/transport.c | 113 ++++++++++++++++++++++++++++++++-----
1 file changed, 100 insertions(+), 13 deletions(-)
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index 5c2a2777e..f8f68737d 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -37,6 +37,7 @@
#include "src/shared/bap.h"
#include "src/shared/bass.h"
#include "src/shared/io.h"
+#include "src/btd.h"
#ifdef HAVE_A2DP
#include "avdtp.h"
@@ -109,11 +110,13 @@ struct bap_transport {
guint resume_id;
struct iovec *meta;
guint chan_id;
+ bool desynchronized;
};
struct media_transport_ops {
const char *uuid;
const GDBusPropertyTable *properties;
+ const GDBusPropertyTable *test_properties;
void (*set_owner)(struct media_transport *transport,
struct media_owner *owner);
void (*remove_owner)(struct media_transport *transport,
@@ -351,7 +354,7 @@ static void transport_bap_remove_owner(struct media_transport *transport,
{
struct bap_transport *bap = transport->data;
- if (bap && bap->linked)
+ if (bap && bap->linked && !bap->desynchronized)
queue_foreach(bt_bap_stream_io_get_links(bap->stream),
linked_transport_remove_owner, owner);
}
@@ -729,7 +732,7 @@ static void transport_bap_set_owner(struct media_transport *transport,
{
struct bap_transport *bap = transport->data;
- if (bap && bap->linked)
+ if (bap && bap->linked && !bap->desynchronized)
queue_foreach(bt_bap_stream_io_get_links(bap->stream),
linked_transport_set_owner, owner);
}
@@ -1463,6 +1466,60 @@ static void set_links(const GDBusPropertyTable *property,
g_dbus_pending_property_success(id);
}
+static gboolean get_desynchronized(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+ &bap->desynchronized);
+
+ return TRUE;
+}
+
+static void transport_desynchronize(void *data, void *user_data)
+{
+ struct bt_bap_stream *link = data;
+ bool desynchronized = PTR_TO_UINT(user_data);
+ struct media_transport *transport;
+ struct bap_transport *bap;
+
+ transport = find_transport_by_bap_stream(link);
+ bap = transport->data;
+ bap->desynchronized = desynchronized;
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "Desynchronized");
+}
+
+static void set_desynchronized(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, GDBusPendingPropertySet id,
+ void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+ g_dbus_pending_property_error(id,
+ ERROR_INTERFACE ".InvalidArguments",
+ "Expected BOOLEAN");
+ return;
+ }
+
+ dbus_message_iter_get_basic(iter, &bap->desynchronized);
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "Desynchronized");
+
+ /* Set desynchronized for all the links */
+ queue_foreach(bt_bap_stream_io_get_links(bap->stream),
+ transport_desynchronize,
+ UINT_TO_PTR(bap->desynchronized));
+
+ g_dbus_pending_property_success(id);
+}
+
static gboolean qos_ucast_exists(const GDBusPropertyTable *property, void *data)
{
struct media_transport *transport = data;
@@ -1486,6 +1543,23 @@ static const GDBusPropertyTable transport_bap_uc_properties[] = {
{ }
};
+static const GDBusPropertyTable transport_bap_uc_test_properties[] = {
+ { "Device", "o", get_device },
+ { "UUID", "s", get_uuid },
+ { "Codec", "y", get_codec },
+ { "Configuration", "ay", get_configuration },
+ { "State", "s", get_state },
+ { "QoS", "a{sv}", get_ucast_qos, NULL, qos_ucast_exists },
+ { "Endpoint", "o", get_endpoint, NULL, endpoint_exists },
+ { "Location", "u", get_location },
+ { "Metadata", "ay", get_metadata, set_metadata },
+ { "Links", "ao", get_links, NULL, links_exists },
+ { "Volume", "q", get_volume, set_volume, volume_exists },
+ { "Desynchronized", "b", get_desynchronized, set_desynchronized,
+ links_exists},
+ { }
+};
+
static gboolean get_bcast_qos(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -1920,6 +1994,9 @@ static void transport_bap_update_links_uc(
g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path,
MEDIA_TRANSPORT_INTERFACE,
"Links");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(), transport->path,
+ MEDIA_TRANSPORT_INTERFACE,
+ "Desynchronized");
DBG("stream %p linked %s", bap->stream, bap->linked ? "true" : "false");
}
@@ -2037,8 +2114,9 @@ static guint transport_bap_resume(struct media_transport *transport,
return bap->resume_id;
}
- id = bt_bap_stream_enable(bap->stream, bap->linked, NULL,
- bap_enable_complete, owner);
+ id = bt_bap_stream_enable(bap->stream,
+ bap->desynchronized ? false : bap->linked,
+ NULL, bap_enable_complete, owner);
if (!id)
return 0;
@@ -2161,7 +2239,7 @@ static void transport_bap_set_state(struct media_transport *transport,
{
struct bap_transport *bap = transport->data;
- if (!bap->linked)
+ if (!bap->linked || bap->desynchronized)
return;
/* Update links */
@@ -2540,10 +2618,11 @@ static void *transport_asha_init(struct media_transport *transport, void *data)
#define TRANSPORT_OPS(_uuid, _props, _set_owner, _remove_owner, _init, \
_resume, _suspend, _cancel, _set_state, _get_stream, \
_get_volume, _set_volume, _set_delay, _update_links, \
- _destroy) \
+ _destroy, _test_props) \
{ \
.uuid = _uuid, \
.properties = _props, \
+ .test_properties = _test_props, \
.set_owner = _set_owner, \
.remove_owner = _remove_owner, \
.init = _init, \
@@ -2565,26 +2644,28 @@ static void *transport_asha_init(struct media_transport *transport, void *data)
transport_a2dp_resume, transport_a2dp_suspend, \
transport_a2dp_cancel, NULL, \
transport_a2dp_get_stream, transport_a2dp_get_volume, \
- _set_volume, _set_delay, NULL, _destroy)
+ _set_volume, _set_delay, NULL, _destroy, NULL)
#define BAP_OPS(_uuid, _props, _set_owner, _remove_owner, _update_links, \
- _set_state) \
+ _set_state, _test_props) \
TRANSPORT_OPS(_uuid, _props, _set_owner, _remove_owner,\
transport_bap_init, \
transport_bap_resume, transport_bap_suspend, \
transport_bap_cancel, _set_state, \
transport_bap_get_stream, transport_bap_get_volume, \
transport_bap_set_volume, NULL, \
- _update_links, transport_bap_destroy)
+ _update_links, transport_bap_destroy, _test_props)
#define BAP_UC_OPS(_uuid) \
BAP_OPS(_uuid, transport_bap_uc_properties, \
transport_bap_set_owner, transport_bap_remove_owner, \
- transport_bap_update_links_uc, transport_bap_set_state)
+ transport_bap_update_links_uc, \
+ transport_bap_set_state, \
+ transport_bap_uc_test_properties)
#define BAP_BC_OPS(_uuid) \
BAP_OPS(_uuid, transport_bap_bc_properties, NULL, NULL, \
- transport_bap_update_links_bc, NULL)
+ transport_bap_update_links_bc, NULL, NULL)
#define ASHA_OPS(_uuid) \
TRANSPORT_OPS(_uuid, transport_asha_properties, NULL, NULL, \
@@ -2592,7 +2673,7 @@ static void *transport_asha_init(struct media_transport *transport, void *data)
transport_asha_resume, transport_asha_suspend, \
transport_asha_cancel, NULL, NULL, \
transport_asha_get_volume, transport_asha_set_volume, \
- NULL, NULL, NULL)
+ NULL, NULL, NULL, NULL)
static const struct media_transport_ops transport_ops[] = {
#ifdef HAVE_A2DP
@@ -2647,6 +2728,7 @@ struct media_transport *media_transport_create(struct btd_device *device,
struct media_transport *transport;
const struct media_transport_ops *ops;
int fd;
+ const GDBusPropertyTable *properties;
transport = g_new0(struct media_transport, 1);
if (device)
@@ -2701,9 +2783,14 @@ struct media_transport *media_transport_create(struct btd_device *device,
goto fail;
}
+ if (btd_opts.testing && ops->test_properties)
+ properties = ops->test_properties;
+ else
+ properties = ops->properties;
+
if (g_dbus_register_interface(btd_get_dbus_connection(),
transport->path, MEDIA_TRANSPORT_INTERFACE,
- transport_methods, NULL, ops->properties,
+ transport_methods, NULL, properties,
transport, media_transport_free) == FALSE) {
error("Could not register transport %s", transport->path);
goto fail;
--
2.43.0
next prev parent reply other threads:[~2026-04-27 17:21 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-27 17:20 [PATCH BlueZ 0/3] Add ability to desynchronized transports for PTS tests Frédéric Danis
2026-04-27 17:20 ` Frédéric Danis [this message]
2026-04-27 18:02 ` [PATCH BlueZ 1/3] audio: Add ability to desynchronized linked transport Luiz Augusto von Dentz
2026-04-27 18:56 ` Add ability to desynchronized transports for PTS tests bluez.test.bot
2026-04-27 17:20 ` [PATCH BlueZ 2/3] doc: Add documentation for CIS transport Desynchronized property Frédéric Danis
2026-04-27 17:20 ` [PATCH BlueZ 3/3] client/player: Add support to desynchronize linked transports Frédéric Danis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260427172056.148115-2-frederic.danis@collabora.com \
--to=frederic.danis@collabora.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox