diff mbox series

[BlueZ,7/9] bap: Handle req to sync to multiple BISes

Message ID 20241004123523.1012743-8-vlad.pruteanu@nxp.com
State New
Headers show
Series Allow syncing to multiple BISes from the same BIG | expand

Commit Message

Vlad Pruteanu Oct. 4, 2024, 12:35 p.m. UTC
When syncing to multiple BISes from the same BIG, an acquire call
will be issued by the Audio Server for each BIS. These need to be
merged so that the controller will receive only one req which
includes all the BISes.

When a call to create a BIG sync request is received, a check is
performed to find if any streams are in RELEASING or PENDING
state. If there are, they are part of multiple BISes sync and the
audio server was not reacquired them yet. Otherwise, the request
is allocated and the num_bis and bc_bis are set, based on streams
in ENABLING state.
---
 profiles/audio/bap.c | 101 +++++++++++++++++++++++++++++--------------
 1 file changed, 68 insertions(+), 33 deletions(-)
diff mbox series

Patch

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 666d3324e..7251d8759 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -1031,21 +1031,22 @@  static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
 
 	DBG("BIG Sync completed");
 
-	if (setup->io) {
-		g_io_channel_unref(setup->io);
-		g_io_channel_shutdown(setup->io, TRUE, NULL);
-		setup->io = NULL;
+	req->iso_bc_addr.bc_num_bis--;
+	if (req->iso_bc_addr.bc_num_bis == 0) {
+		if (setup->io) {
+			g_io_channel_unref(setup->io);
+			g_io_channel_shutdown(setup->io, TRUE, NULL);
+			setup->io = NULL;
+		}
+		/* This device is no longer needed */
+		btd_service_connecting_complete(bap_data->service, 0);
+		queue_remove(bap_data->adapter->bcast_pa_requests, req);
+		queue_destroy(req->setups, NULL);
+		free(req);
 	}
 
-	/* This device is no longer needed */
-	btd_service_connecting_complete(bap_data->service, 0);
-
 	fd = g_io_channel_unix_get_fd(io);
 
-	queue_remove(bap_data->adapter->bcast_pa_requests, req);
-	queue_destroy(req->setups, NULL);
-	free(req);
-
 	if (bt_bap_stream_set_io(setup->stream, fd)) {
 		bt_bap_stream_start(setup->stream, NULL, NULL);
 		g_io_channel_set_close_on_unref(io, FALSE);
@@ -2289,38 +2290,72 @@  static gboolean pa_idle_timer(gpointer user_data)
 	return TRUE;
 }
 
+static void find_pending_req(void *data, void *user_data)
+{
+	struct bap_setup *setup = data;
+	bool *pending = user_data;
+
+	if (bt_bap_stream_get_state(setup->stream) ==
+		BT_BAP_STREAM_STATE_PENDING ||
+		bt_bap_stream_get_state(setup->stream) ==
+		BT_BAP_STREAM_STATE_RELEASING)
+		*pending = TRUE;
+}
+
+static void count_pending(void *data, void *user_data)
+{
+	struct bap_setup *setup = data;
+	struct bap_bcast_pa_req *req = user_data;
+
+	if (bt_bap_stream_get_state(setup->stream) ==
+				BT_BAP_STREAM_STATE_ENABLING) {
+		req->iso_bc_addr.bc_bis[req->iso_bc_addr.bc_num_bis] =
+				get_bis_from_stream(setup->stream);
+		req->iso_bc_addr.bc_num_bis++;
+		DBG("pushing setup for BIS %d",
+				get_bis_from_stream(setup->stream));
+		queue_push_tail(req->setups, setup);
+	}
+}
+
 static void setup_accept_io_broadcast(struct bap_data *data,
 					struct bap_setup *setup)
 {
-	struct bap_bcast_pa_req *req = new0(struct bap_bcast_pa_req, 1);
+	struct bap_bcast_pa_req *req;
+	bool pending = FALSE;
 	struct bap_adapter *adapter = data->adapter;
 
-	req->setups = queue_new();
-	req->iso_bc_addr.bc_bdaddr_type =
+	/* Search for requests to sync to the same BIG.
+	 * If any, merge the current request with it.
+	 */
+	queue_foreach(data->bcast_snks, find_pending_req, &pending);
+	if (!pending) {
+		req = new0(struct bap_bcast_pa_req, 1);
+		req->iso_bc_addr.bc_bdaddr_type =
 			btd_device_get_bdaddr_type(data->device);
-	memcpy(&req->iso_bc_addr.bc_bdaddr,
+		memcpy(&req->iso_bc_addr.bc_bdaddr,
 			device_get_address(data->device), sizeof(bdaddr_t));
-	req->iso_bc_addr.bc_bis[req->iso_bc_addr.bc_num_bis] =
-			get_bis_from_stream(setup->stream);
-	req->iso_bc_addr.bc_num_bis++;
-	queue_push_tail(req->setups, setup);
-
-	/* Timer could be stopped if all other requests were treated.
-	 * Check the state of the timer and turn it on so that this request
-	 * can also be treated.
-	 */
-	if (adapter->pa_timer_id == 0)
-		adapter->pa_timer_id = g_timeout_add_seconds(PA_IDLE_TIMEOUT,
+		req->setups = queue_new();
+		queue_foreach(data->bcast_snks, count_pending, req);
+
+		/* Timer could be stopped if all other requests were treated.
+		 * Check the state of the timer and turn it on so that this
+		 * request can also be treated.
+		 */
+		if (adapter->pa_timer_id == 0)
+			adapter->pa_timer_id = g_timeout_add_seconds(
+								PA_IDLE_TIMEOUT,
 								pa_idle_timer,
 								adapter);
 
-	/* Add this request to the PA queue.
-	 * We don't need to check the queue here, as we cannot have
-	 * BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
-	 */
-	req->type = BAP_PA_BIG_SYNC_REQ;
-	req->in_progress = FALSE;
-	queue_push_tail(adapter->bcast_pa_requests, req);
+		/* Add this request to the PA queue.
+		 * We don't need to check the queue here, as we cannot have
+		 * BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
+		 */
+		req->type = BAP_PA_BIG_SYNC_REQ;
+		req->in_progress = FALSE;
+		queue_push_tail(adapter->bcast_pa_requests, req);
+	}
 }
 
 static void setup_create_ucast_io(struct bap_data *data,