From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 02/11] bass: wait for the session to be ready before pushing a source
Date: Tue, 15 Sep 2026 17:15:19 -0400 [thread overview]
Message-ID: <20260915211528.1223784-3-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260915211528.1223784-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
A Broadcast Assistant could write to the Broadcast Audio Scan Control
Point of a Scan Delegator before its own session had enabled the
Broadcast Receive State notifications, as the connection was completed
as soon as the session was attached.
When that happens the delegator handles the Add Source, sets the state
to request the sync info to be transferred, and notifies it, but the
notification is dropped since the assistant has not subscribed yet. The
assistant never learns it has to transfer the sync info, so PAST never
happens, and the delegator is left waiting for it until the kernel
gives up, which takes 20 seconds, and falls back to creating the sync
itself.
Complete the connection only once the session is ready, and queue any
push received in the meantime, replaying it afterwards, so it is not
rejected just because the user was quick.
With this the sync info is transferred right after the Add Source, and
test_bass_past_transport_acquire consistently takes around 11 seconds
instead of intermittently taking over 40 seconds when the transfer was
missed.
Assisted-by: opencode:claude-opus-5
---
profiles/audio/bass.c | 124 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 109 insertions(+), 15 deletions(-)
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index 533d45babfeb..c9a9111e010f 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
@@ -94,6 +94,14 @@ struct bass_data {
unsigned int cp_id;
unsigned int bis_id;
unsigned int state_id;
+ unsigned int ready_id;
+ bool ready;
+ struct queue *pushes;
+};
+
+struct bass_push {
+ struct bass_assistant *assistant;
+ DBusMessage *msg;
};
struct bass_assistant {
@@ -1218,10 +1226,31 @@ static DBusMessage *push_add_src(struct bass_assistant *assistant,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static DBusMessage *push_src(struct bass_assistant *assistant,
+ DBusMessage *msg)
+{
+ if (assistant->state == ASSISTANT_STATE_ACTIVE) {
+ return push_mod_src(assistant, msg);
+ } else if (assistant->state == ASSISTANT_STATE_LOCAL) {
+ struct bass_src *src;
+
+ src = queue_find(assistant->srcs, match_src_data,
+ assistant->data->bass);
+ if (src) {
+ assistant->src_id = src->src_id;
+ return push_mod_src(assistant, msg);
+ }
+ }
+
+ return push_add_src(assistant, msg);
+}
+
static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
void *user_data)
{
struct bass_assistant *assistant = user_data;
+ struct bass_data *data;
+ struct bass_push *push;
DBusMessageIter props, dict;
DBG("");
@@ -1240,20 +1269,25 @@ static DBusMessage *push(DBusConnection *conn, DBusMessage *msg,
return btd_error_invalid_args(msg);
}
- if (assistant->state == ASSISTANT_STATE_ACTIVE) {
- return push_mod_src(assistant, msg);
- } else if (assistant->state == ASSISTANT_STATE_LOCAL) {
- struct bass_src *src;
+ /* Wait for the session to be ready before writing to the control
+ * point, otherwise the Broadcast Receive State notifications may not
+ * be enabled yet and the state changes it triggers, e.g. a request to
+ * transfer the sync info, would be missed.
+ */
+ data = queue_find(sessions, match_bass, assistant->data->bass);
+ if (data && !data->ready) {
+ DBG("Session not ready, queueing request");
- src = queue_find(assistant->srcs, match_src_data,
- assistant->data->bass);
- if (src) {
- assistant->src_id = src->src_id;
- return push_mod_src(assistant, msg);
- }
+ push = new0(struct bass_push, 1);
+ push->assistant = assistant;
+ push->msg = dbus_message_ref(msg);
+
+ queue_push_tail(data->pushes, push);
+
+ return NULL;
}
- return push_add_src(assistant, msg);
+ return push_src(assistant, msg);
}
static const GDBusMethodTable assistant_methods[] = {
@@ -1754,6 +1788,7 @@ static struct bass_data *bass_data_new(struct btd_adapter *adapter,
data = new0(struct bass_data, 1);
data->adapter = adapter;
data->device = device;
+ data->pushes = queue_new();
return data;
}
@@ -1788,6 +1823,19 @@ static void bass_data_add(struct bass_data *data)
device_set_past_support(data->device, true);
}
+static void bass_push_free(void *user_data)
+{
+ struct bass_push *push = user_data;
+ DBusMessage *reply;
+
+ reply = btd_error_failed(push->msg, "Session removed");
+ if (reply)
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+ dbus_message_unref(push->msg);
+ free(push);
+}
+
static void bass_data_free(struct bass_data *data)
{
if (data->service) {
@@ -1798,6 +1846,11 @@ static void bass_data_free(struct bass_data *data)
bt_bass_src_unregister(data->bass, data->src_id);
bt_bass_cp_handler_unregister(data->bass, data->cp_id);
+ if (data->ready_id)
+ bt_bass_ready_unregister(data->bass, data->ready_id);
+
+ queue_destroy(data->pushes, bass_push_free);
+
bt_bass_unref(data->bass);
queue_remove_all(assistants, assistant_match_data,
@@ -2365,6 +2418,35 @@ static void bass_remove(struct btd_service *service)
bass_data_remove(data);
}
+static void bass_ready(struct bt_bass *bass, void *user_data)
+{
+ struct btd_service *service = user_data;
+ struct bass_data *data = btd_service_get_user_data(service);
+ struct bass_push *push;
+
+ DBG("bass %p", bass);
+
+ /* The callback is unregistered with the session, not here, as it is
+ * called while the ready callbacks are being iterated.
+ */
+ btd_service_connecting_complete(service, 0);
+
+ if (!data)
+ return;
+
+ data->ready = true;
+
+ while ((push = queue_pop_head(data->pushes))) {
+ DBusMessage *reply = push_src(push->assistant, push->msg);
+
+ if (reply)
+ g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+ dbus_message_unref(push->msg);
+ free(push);
+ }
+}
+
static int bass_accept(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
@@ -2383,10 +2465,22 @@ static int bass_accept(struct btd_service *service)
/* Only attach client if initiator of the connection otherwise act as
* delegator.
*/
- if (btd_service_is_initiator(service) &&
- !bt_bass_attach(data->bass, client)) {
- error("BASS unable to attach");
- return -EINVAL;
+ if (btd_service_is_initiator(service)) {
+ /* Complete the connection once the session is ready, so no
+ * operation is attempted before the Broadcast Receive State
+ * notifications are enabled, otherwise the state changes they
+ * trigger, e.g. a request to transfer the sync info, would be
+ * missed.
+ */
+ data->ready_id = bt_bass_ready_register(data->bass, bass_ready,
+ service, NULL);
+
+ if (!bt_bass_attach(data->bass, client)) {
+ error("BASS unable to attach");
+ return -EINVAL;
+ }
+
+ return 0;
}
btd_service_connecting_complete(service, 0);
--
2.55.0
next prev parent reply other threads:[~2026-09-15 21:15 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-15 21:15 [PATCH BlueZ v1 00/11] Cover a BAP stream to a coordinated set Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 01/11] shared/bass: add a ready callback Luiz Augusto von Dentz
2026-09-15 21:58 ` Cover a BAP stream to a coordinated set bluez.test.bot
2026-09-16 0:55 ` bluez.test.bot
2026-09-15 21:15 ` Luiz Augusto von Dentz [this message]
2026-09-15 21:15 ` [PATCH BlueZ v1 03/11] test: functional: report what a test is waiting for Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 04/11] test: functional: answer the notification registered by the victim Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 05/11] doc: describe the BAP coordinated set test cases Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 06/11] emulator: use the handle of the receiving side Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 07/11] emulator: allow the maximum number of CIS of a CIG Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 08/11] device: keep the long term key of both roles Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 09/11] client: allow a capability with the auto agent Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 10/11] test: functional: fail as soon as an operation fails Luiz Augusto von Dentz
2026-09-15 21:15 ` [PATCH BlueZ v1 11/11] test: functional: add the BAP coordinated set tests Luiz Augusto von Dentz
2026-09-16 18:30 ` [PATCH BlueZ v1 00/11] Cover a BAP stream to a coordinated set patchwork-bot+bluetooth
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=20260915211528.1223784-3-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.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