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 --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, -- 2.40.1