From 1302116ea4b622342f1dfc3f797536335680eb08 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 6 Nov 2025 18:02:44 -0500 Subject: [PATCH] bass: Fix not cleaning up delegator properly When BIG sync is lost, or the assistant modify removing all streams, delegator should be freed to so the assistant can start over and share another stream. --- profiles/audio/bap.c | 27 +++--- profiles/audio/bass.c | 200 ++++++++++++++++++++++-------------------- 2 files changed, 122 insertions(+), 105 deletions(-) diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c index c10f019ed..0883f6c47 100644 --- a/profiles/audio/bap.c +++ b/profiles/audio/bap.c @@ -3270,14 +3270,6 @@ static void pac_removed_broadcast(struct bt_bap_pac *pac, void *user_data) ep_unregister(ep); } -static bool match_device(const void *data, const void *match_data) -{ - const struct bap_data *bdata = data; - const struct btd_device *device = match_data; - - return bdata->device == device; -} - static struct bap_data *bap_data_new(struct btd_device *device) { struct bap_data *data; @@ -3673,6 +3665,14 @@ static int bap_bcast_probe(struct btd_service *service) return 0; } +static bool match_service(const void *data, const void *match_data) +{ + const struct bap_data *bdata = data; + const struct btd_service *service = match_data; + + return bdata->service == service; +} + static void bap_bcast_remove(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); @@ -3682,7 +3682,10 @@ static void bap_bcast_remove(struct btd_service *service) ba2str(device_get_address(device), addr); DBG("%s", addr); - data = queue_find(sessions, match_device, device); + /* Lookup the bap session for this service since in case of + * bass_delegator its user data is set by bass plugin. + */ + data = queue_find(sessions, match_service, service); if (!data) { error("BAP service not handled by profile"); return; @@ -3791,10 +3794,12 @@ static int bap_disconnect(struct btd_service *service) static int bap_bcast_disconnect(struct btd_service *service) { - struct btd_device *device = btd_service_get_device(service); struct bap_data *data; - data = queue_find(sessions, match_device, device); + /* Lookup the bap session for this service since in case of + * bass_delegator its user data is set by bass plugin. + */ + data = queue_find(sessions, match_service, service); if (!data) { error("BAP service not handled by profile"); return -EINVAL; diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c index 0ba29f939..9ace37237 100644 --- a/profiles/audio/bass.c +++ b/profiles/audio/bass.c @@ -269,14 +269,6 @@ static void bass_req_bcode(struct bt_bap_stream *stream, dg->timeout = g_timeout_add_seconds(10, req_timeout, dg); } -static bool delegator_match_device(const void *data, const void *match_data) -{ - const struct bass_delegator *dg = data; - const struct btd_device *device = match_data; - - return dg->device == device; -} - static int stream_get_bis(struct bt_bap_stream *stream) { char *path = bt_bap_stream_get_user_data(stream); @@ -366,6 +358,33 @@ static void setup_free(void *data) free(setup); } +static void delegator_disconnect(struct bass_delegator *dg) +{ + struct btd_device *device = dg->device; + struct btd_service *service = dg->service; + + DBG("%p", dg); + + /* Disconnect service so BAP driver is cleanup properly and bt_bap is + * detached from the device. + */ + btd_service_disconnect(service); + + /* Remove service since delegator shold have been freed at this point */ + device_remove_profile(device, btd_service_get_profile(service)); + + /* If the device is no longer consider connected it means no other + * service was connected so it has no longer any use and can be safely + * removed. + */ + if (!btd_device_is_connected(device)) { + struct btd_adapter *adapter; + + adapter = device_get_adapter(device); + btd_adapter_remove_device(adapter, device); + } +} + static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, uint8_t new_state, void *user_data) { @@ -459,6 +478,8 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state, setup->stream = NULL; queue_remove(setup->dg->setups, setup); setup_free(setup); + if (queue_isempty(dg->setups)) + delegator_disconnect(dg); break; } } @@ -1296,45 +1317,27 @@ static void bap_bc_attached(struct bt_bap *bap, void *user_data) bass_data_add(data); } -static void bap_attached(struct bt_bap *bap, void *user_data) +static bool delegator_match_device(const void *data, const void *match_data) { - struct btd_service *service; - struct btd_profile *p; - struct btd_device *device; - struct btd_adapter *adapter; - struct bass_delegator *dg; - struct bass_data *data; - GError *err = NULL; - - service = bt_bap_get_user_data(bap); - if (!service) - return bap_bc_attached(bap, user_data); - - DBG("%p", bap); - - p = btd_service_get_profile(service); - if (!p) - return; - - /* Only handle sessions with Broadcast Sources */ - if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR)) - return; - - device = btd_service_get_device(service); - adapter = device_get_adapter(device); + const struct bass_delegator *dg = data; + const struct btd_device *device = match_data; - /* Create BASS session with the Broadcast Source */ - data = bass_data_new(adapter, device); - data->bis_id = bt_bap_bis_cb_register(bap, bis_probe, - bis_remove, device, NULL); + return dg->device == device; +} - bass_data_add(data); +static void delegator_attach(struct bt_bap *bap, struct btd_device *device, + struct btd_service *service) +{ + struct bass_delegator *dg; + GError *err = NULL; dg = queue_find(delegators, delegator_match_device, device); if (!dg) /* Only probe devices added via Broadcast Assistants */ return; + DBG("delegator %p", dg); + if (dg->service) /* Service has already been probed */ return; @@ -1345,9 +1348,9 @@ static void bap_attached(struct bt_bap *bap, void *user_data) dg->io = bt_io_listen(NULL, confirm_cb, dg, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, - btd_adapter_get_address(adapter), + btd_adapter_get_address(device_get_adapter(device)), BT_IO_OPT_SOURCE_TYPE, - btd_adapter_get_address_type(adapter), + btd_adapter_get_address_type(device_get_adapter(device)), BT_IO_OPT_DEST_BDADDR, device_get_address(device), BT_IO_OPT_DEST_TYPE, @@ -1366,6 +1369,41 @@ static void bap_attached(struct bt_bap *bap, void *user_data) btd_service_set_user_data(service, dg); } +static void bap_attached(struct bt_bap *bap, void *user_data) +{ + struct btd_service *service; + struct btd_profile *p; + struct btd_device *device; + struct btd_adapter *adapter; + struct bass_data *data; + + service = bt_bap_get_user_data(bap); + if (!service) + return bap_bc_attached(bap, user_data); + + DBG("%p", bap); + + p = btd_service_get_profile(service); + if (!p) + return; + + /* Only handle sessions with Broadcast Sources */ + if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR)) + return; + + device = btd_service_get_device(service); + adapter = device_get_adapter(device); + + /* Create BASS session with the Broadcast Source */ + data = bass_data_new(adapter, device); + data->bis_id = bt_bap_bis_cb_register(bap, bis_probe, + bis_remove, device, NULL); + + bass_data_add(data); + + delegator_attach(bap, device, service); +} + static bool match_bap(const void *data, const void *match_data) { const struct bass_data *d = data; @@ -1417,12 +1455,35 @@ static void delegator_free(struct bass_delegator *dg) free(dg); } +static bool match_service(const void *data, const void *match_data) +{ + const struct bass_data *bdata = data; + const struct btd_service *service = match_data; + + return bdata->service == service; +} + +static void delegator_detach(struct btd_service *service) +{ + struct bass_delegator *dg; + + dg = btd_service_get_user_data(service); + if (!dg) + return; + + if (!queue_remove(delegators, dg)) + return; + + DBG("%p", dg); + + delegator_free(dg); + + btd_service_set_user_data(service, NULL); +} + static void bap_detached(struct bt_bap *bap, void *user_data) { struct btd_service *service; - struct btd_profile *p; - struct btd_device *device; - struct bass_delegator *dg; struct bass_data *data; data = queue_find(sessions, match_bap, bap); @@ -1435,31 +1496,15 @@ static void bap_detached(struct bt_bap *bap, void *user_data) if (!service) return; - p = btd_service_get_profile(service); - if (!p) - return; - - /* Only handle sessions with Broadcast Sources */ - if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR)) - return; - - device = btd_service_get_device(service); - /* Remove BASS session with the Broadcast Source device */ - data = queue_find(sessions, match_device, device); + data = queue_find(sessions, match_service, service); if (data) { bt_bap_bis_cb_unregister(bap, data->bis_id); bt_bap_state_unregister(bap, data->state_id); bass_data_remove(data); } - dg = queue_remove_if(delegators, delegator_match_device, device); - if (!dg) - return; - - delegator_free(dg); - - btd_service_set_user_data(service, NULL); + delegator_detach(service); } static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp, @@ -1807,39 +1852,6 @@ static int handle_mod_src_req(struct bt_bcast_src *bcast_src, switch (sync_state) { case BT_BASS_SYNCHRONIZED_TO_PA: bass_update_bis_sync(dg, bcast_src); - - /* Check if there are any setups left since it means the PA - * should be no longer synchronized. - */ - if (queue_isempty(dg->setups)) { - /* IO is no longer needed since there are no setups */ - g_io_channel_shutdown(dg->io, TRUE, NULL); - g_io_channel_unref(dg->io); - dg->io = NULL; - - bt_bass_set_pa_sync(dg->src, - BT_BASS_NOT_SYNCHRONIZED_TO_PA); - - if (!dg->service) - return 0; - - /* Disconnect service so BAP driver is cleanup - * properly. - */ - btd_service_disconnect(dg->service); - - /* If the device is no longer consider connected - * it means no other service was connected so it - * has no longer any use and can be safely removed. - */ - if (!btd_device_is_connected(dg->device)) { - struct btd_adapter *adapter; - - adapter = device_get_adapter(dg->device); - btd_adapter_remove_device(adapter, dg->device); - } - } - break; case BT_BASS_NOT_SYNCHRONIZED_TO_PA: if (params->pa_sync == PA_SYNC_NO_PAST) { -- 2.47.3