From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v1 12/12] bap: reuse the PA sync established to discover a Broadcast Source
Date: Wed, 9 Sep 2026 15:23:08 -0400 [thread overview]
Message-ID: <20260909192308.1306567-13-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260909192308.1306567-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
A Broadcast Sink creates a short lived PA sync to read the BASE of a
Broadcast Source, closes it, and creates a new one once a stream is
enabled, as syncing to the BIG requires a PA sync. The second sync has
to be established again before the BIG sync can be requested, which
delays the start of the stream.
Keep the sync of the BIG Info report around instead, and reuse it, but
only while there is nothing else to discover, as a sync holds resources
that are needed to discover other Broadcast Sources: it is released as
soon as another source is probed, and after a grace timeout if no
stream is enabled in the meantime.
Assisted-by: opencode:claude-opus-5
---
profiles/audio/bap.c | 115 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 107 insertions(+), 8 deletions(-)
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index ff8f58a12091..5771c9ae0fdf 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -139,6 +139,8 @@ struct bap_data {
struct queue *bcast_snks;
struct queue *server_streams;
GIOChannel *listen_io;
+ bool pa_synced;
+ unsigned int pa_timer;
unsigned int io_id;
unsigned int cig_update_id;
bool services_ready;
@@ -176,6 +178,9 @@ static void bap_data_free(struct bap_data *data)
{
struct queue *bcast_snks = data->bcast_snks;
+ if (data->pa_timer)
+ g_source_remove(data->pa_timer);
+
if (data->listen_io) {
g_io_channel_shutdown(data->listen_io, TRUE, NULL);
g_io_channel_unref(data->listen_io);
@@ -1560,6 +1565,63 @@ static void bis_handler(uint8_t sid, uint8_t bis, uint8_t sgrp,
path);
}
+/* Time a PA sync is kept around waiting for a stream to be enabled,
+ * before it is released.
+ */
+#define PA_SYNC_GRACE_TIMEOUT 5
+
+static void pa_sync_release(struct bap_data *data)
+{
+ if (!data->pa_synced)
+ return;
+
+ DBG("Release PA sync");
+
+ if (data->pa_timer) {
+ g_source_remove(data->pa_timer);
+ data->pa_timer = 0;
+ }
+
+ if (data->listen_io) {
+ g_io_channel_shutdown(data->listen_io, TRUE, NULL);
+ g_io_channel_unref(data->listen_io);
+ data->listen_io = NULL;
+ }
+
+ data->pa_synced = false;
+}
+
+static gboolean pa_sync_timeout(gpointer user_data)
+{
+ struct bap_data *data = user_data;
+
+ data->pa_timer = 0;
+ pa_sync_release(data);
+
+ return FALSE;
+}
+
+static bool pa_sync_pending(const void *data, const void *match_data)
+{
+ const struct bap_data *bdata = data;
+
+ if (bdata == match_data)
+ return false;
+
+ /* A session with a listener that has not synced yet is still
+ * discovering a Broadcast Source.
+ */
+ return bdata->listen_io && !bdata->pa_synced;
+}
+
+static void pa_sync_release_session(void *data, void *user_data)
+{
+ struct bap_data *bdata = data;
+
+ if (bdata != user_data)
+ pa_sync_release(bdata);
+}
+
static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
@@ -1591,10 +1653,21 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
g_io_channel_unref(data->listen_io);
data->listen_io = NULL;
- /* For short-lived PA, the sync is no longer needed at
- * this point, so the io can be closed.
- */
- g_io_channel_shutdown(io, TRUE, NULL);
+ if (queue_find(sessions, pa_sync_pending, data)) {
+ /* Other Broadcast Sources are still being discovered, so the
+ * sync is closed to not hold the resources needed for them.
+ */
+ g_io_channel_shutdown(io, TRUE, NULL);
+ } else {
+ /* Nothing else to discover: keep the sync for a while, as
+ * syncing to the BIG requires one, so it does not have to be
+ * established again if a stream is enabled.
+ */
+ data->listen_io = g_io_channel_ref(io);
+ data->pa_synced = true;
+ data->pa_timer = g_timeout_add_seconds(PA_SYNC_GRACE_TIMEOUT,
+ pa_sync_timeout, data);
+ }
/* Analyze received BASE data and create remote media endpoints for each
* BIS matching our capabilities
@@ -3592,6 +3665,11 @@ static int pa_sync(struct bap_data *data)
DBG("Create PA sync with this source");
+ /* Release any sync kept by another session, as it is not needed
+ * to discover this source.
+ */
+ queue_foreach(sessions, pa_sync_release_session, data);
+
data->listen_io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, data,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR,
@@ -3662,10 +3740,12 @@ static gboolean iso_do_big_sync(GIOChannel *io, GIOCondition cond,
DBG("BIG info received, do BIG sync");
- g_io_channel_unref(data->listen_io);
- g_io_channel_shutdown(data->listen_io, TRUE, NULL);
- data->listen_io = io;
- g_io_channel_ref(data->listen_io);
+ if (data->listen_io != io) {
+ g_io_channel_unref(data->listen_io);
+ g_io_channel_shutdown(data->listen_io, TRUE, NULL);
+ data->listen_io = io;
+ g_io_channel_ref(data->listen_io);
+ }
/* Append each linked BIS to the BIG sync request */
append_setup(setup->stream, &iso_bc_addr);
@@ -3714,6 +3794,25 @@ static void pa_and_big_sync(struct bap_setup *setup)
{
GError *err = NULL;
struct bap_data *bap_data = setup->data;
+
+ if (bap_data->pa_synced) {
+ DBG("Reuse PA sync with this source");
+
+ /* The sync is in use from now on, so it is not released
+ * while the BIG sync is being set up.
+ */
+ bap_data->pa_synced = false;
+
+ if (bap_data->pa_timer) {
+ g_source_remove(bap_data->pa_timer);
+ bap_data->pa_timer = 0;
+ }
+
+ bap_data->io_id = g_io_add_watch(bap_data->listen_io, G_IO_OUT,
+ iso_do_big_sync, setup);
+ return;
+ }
+
DBG("Create PA sync with this source");
bap_data->listen_io = bt_io_listen(NULL, long_pa_sync_confirm_cb, setup,
--
2.55.0
next prev parent reply other threads:[~2026-09-09 19:23 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 19:22 [PATCH BlueZ v1 00/12] Add functional tests for A2DP and BAP Luiz Augusto von Dentz
2026-09-09 19:22 ` [PATCH BlueZ v1 01/12] build: add doc/test-functional.rst to EXTRA_DIST Luiz Augusto von Dentz
2026-09-10 18:28 ` Add functional tests for A2DP and BAP bluez.test.bot
2026-09-09 19:22 ` [PATCH BlueZ v1 02/12] doc: describe the functional test cases Luiz Augusto von Dentz
2026-09-09 19:22 ` [PATCH BlueZ v1 03/12] client: do not prompt for LE Audio settings on A2DP endpoints Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 04/12] client: add A2DP endpoint registration scripts Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 05/12] test: functional: add A2DP tests Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 06/12] client: rename media endpoint scripts to include the codec Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 07/12] client: add BAP endpoint registration scripts Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 08/12] doc: bluetoothctl: document init script option and scripts Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 09/12] test: functional: add BAP unicast tests Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 10/12] test: functional: add BAP broadcast tests Luiz Augusto von Dentz
2026-09-09 19:23 ` [PATCH BlueZ v1 11/12] test: functional: add BAP broadcast assistant test Luiz Augusto von Dentz
2026-09-09 19:23 ` Luiz Augusto von Dentz [this message]
2026-09-10 20:50 ` [PATCH BlueZ v1 00/12] Add functional tests for A2DP and BAP 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=20260909192308.1306567-13-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