diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index daa9bab05538c..6a834a124d9be 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -173,7 +173,10 @@ Bluetooth Audio BAP Scan Delegator is used together with the BAP Broadcast Sink, then the PA state of the receive state of a :c:struct:`bt_bap_broadcast_sink` will still be automatically updated when the PA state changes. (:github:`95453`) - +* :c:func:`bt_bap_broadcast_assistant_discover` will now no longer perform reads of the remote BASS + receive states at the end of the procedure. Users will have to manually call + :c:func:`bt_bap_broadcast_assistant_read_recv_state` to read the existing receive states, if any, + prior to performing any operations. (:github:`91587``) .. zephyr-keep-sorted-stop diff --git a/samples/bluetooth/bap_broadcast_assistant/src/main.c b/samples/bluetooth/bap_broadcast_assistant/src/main.c index 6458bfe60fe3b..3f9420f426cf3 100644 --- a/samples/bluetooth/bap_broadcast_assistant/src/main.c +++ b/samples/bluetooth/bap_broadcast_assistant/src/main.c @@ -52,6 +52,7 @@ struct scan_recv_info { }; static struct bt_conn *broadcast_sink_conn; +static uint8_t remote_recv_state_count; static uint32_t selected_broadcast_id; static uint8_t selected_sid; static uint16_t selected_pa_interval; @@ -71,6 +72,7 @@ static K_SEM_DEFINE(sem_sink_connected, 0, 1); static K_SEM_DEFINE(sem_sink_disconnected, 0, 1); static K_SEM_DEFINE(sem_security_updated, 0, 1); static K_SEM_DEFINE(sem_bass_discovered, 0, 1); +static K_SEM_DEFINE(sem_recv_state_read, 0, 1); static K_SEM_DEFINE(sem_pa_synced, 0, 1); static K_SEM_DEFINE(sem_pa_sync_terminted, 0, 1); static K_SEM_DEFINE(sem_received_base_subgroups, 0, 1); @@ -511,6 +513,7 @@ static void bap_broadcast_assistant_discover_cb(struct bt_conn *conn, int err, if (err == 0) { printk("BASS discover done with %u recv states\n", recv_state_count); + remote_recv_state_count = recv_state_count; k_sem_give(&sem_bass_discovered); } else { printk("BASS discover failed (%d)\n", err); @@ -526,6 +529,35 @@ static void bap_broadcast_assistant_add_src_cb(struct bt_conn *conn, int err) } } +static void +bap_broadcast_assistant_recv_state_read_cb(struct bt_conn *conn, int err, + const struct bt_bap_scan_delegator_recv_state *state) +{ + if (err != 0) { + printk("BASS recv state read failed (%d)\n", err); + return; + } + + if (state != NULL) { + char le_addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(&state->addr, le_addr, sizeof(le_addr)); + printk("BASS recv state: src_id %u, addr %s, sid %u, sync_state %u, encrypt_state " + "%u, num_subgroups %u\n", + state->src_id, le_addr, state->adv_sid, state->pa_sync_state, + state->encrypt_state, state->num_subgroups); + + for (uint8_t i = 0; i < state->num_subgroups; i++) { + const struct bt_bap_bass_subgroup *subgroup = &state->subgroups[i]; + + printk("\t[%d]: BIS sync %u, metadata_len %u\n", i, subgroup->bis_sync, + subgroup->metadata_len); + } + } /* else empty receive state */ + + k_sem_give(&sem_recv_state_read); +} + static void pa_sync_synced_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info) { @@ -550,6 +582,7 @@ static void pa_sync_term_cb(struct bt_le_per_adv_sync *sync, static struct bt_bap_broadcast_assistant_cb ba_cbs = { .discover = bap_broadcast_assistant_discover_cb, .add_src = bap_broadcast_assistant_add_src_cb, + .recv_state = bap_broadcast_assistant_recv_state_read_cb, }; static struct bt_le_per_adv_sync_cb pa_synced_cb = { @@ -618,6 +651,31 @@ BT_CONN_CB_DEFINE(conn_callbacks) = { .security_changed = security_changed_cb }; +static int read_recv_states(void) +{ + /* Attempts to read all found receive states - Some or all may be empty */ + for (uint8_t i = 0U; i < remote_recv_state_count; i++) { + int err; + + err = bt_bap_broadcast_assistant_read_recv_state(broadcast_sink_conn, i); + + if (err != 0) { + printk("Failed to read receive state[%u]: %d\n", i, err); + + return err; + } + + err = k_sem_take(&sem_recv_state_read, SEM_TIMEOUT); + if (err != 0) { + printk("Failed to take sem_recv_state_read: %d\n", err); + + return err; + } + } + + return 0; +} + int main(void) { int err; @@ -667,6 +725,12 @@ int main(void) continue; } + err = read_recv_states(); + if (err != 0) { + printk("Failed to read receive states\n"); + continue; + } + /* TODO: Discover and parse the PACS on the sink and use the information * when discovering and adding a source to the sink. * Also, before populating the parameters to sync to the broadcast source diff --git a/subsys/bluetooth/audio/bap_broadcast_assistant.c b/subsys/bluetooth/audio/bap_broadcast_assistant.c index 77ead34fef688..9494ce3ec3608 100644 --- a/subsys/bluetooth/audio/bap_broadcast_assistant.c +++ b/subsys/bluetooth/audio/bap_broadcast_assistant.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2019 Bose Corporation - * Copyright (c) 2022-2023 Nordic Semiconductor ASA + * Copyright (c) 2022-2025 Nordic Semiconductor ASA * Copyright (c) 2024 Demant A/S * * SPDX-License-Identifier: Apache-2.0 @@ -565,20 +565,15 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, const void *data, uint16_t length) { struct bap_broadcast_assistant_instance *inst = inst_by_conn(conn); + bool active_recv_state = data != NULL && length != 0; + struct bt_bap_scan_delegator_recv_state recv_state; + uint16_t handle = params->single.handle; + int cb_err = err; if (inst == NULL) { return BT_GATT_ITER_STOP; } - uint16_t handle = params->single.handle; - uint8_t last_handle_index = inst->recv_state_cnt - 1; - uint16_t last_handle = inst->recv_state_handles[last_handle_index]; - struct bt_bap_scan_delegator_recv_state recv_state; - int cb_err = err; - bool active_recv_state = data != NULL && length != 0; - - /* TODO: Split discovery and receive state characteristic read */ - (void)memset(params, 0, sizeof(*params)); LOG_DBG("%s receive state", active_recv_state ? "Active " : "Inactive"); @@ -611,48 +606,12 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err, if (cb_err != 0) { LOG_DBG("err %d", cb_err); - - if (atomic_test_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) { - bap_broadcast_assistant_discover_complete(conn, cb_err, 0); - } else { - atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY); - bap_broadcast_assistant_recv_state_changed(conn, cb_err, NULL); - } - } else if (handle == last_handle) { - if (atomic_test_bit(inst->flags, BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) { - const uint8_t recv_state_cnt = inst->recv_state_cnt; - - bap_broadcast_assistant_discover_complete(conn, cb_err, recv_state_cnt); - } else { - atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY); - bap_broadcast_assistant_recv_state_changed(conn, cb_err, - active_recv_state ? - &recv_state : NULL); - } + atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY); + bap_broadcast_assistant_recv_state_changed(conn, cb_err, NULL); } else { - for (uint8_t i = 0U; i < inst->recv_state_cnt; i++) { - if (handle != inst->recv_state_handles[i]) { - continue; - } - - if (i + 1 < ARRAY_SIZE(inst->recv_state_handles)) { - cb_err = read_recv_state(inst, i + 1); - if (cb_err != 0) { - LOG_DBG("Failed to read receive state: %d", cb_err); - - if (atomic_test_bit(inst->flags, - BAP_BA_FLAG_DISCOVER_IN_PROGRESS)) { - bap_broadcast_assistant_discover_complete( - conn, cb_err, 0); - } else { - atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY); - bap_broadcast_assistant_recv_state_changed( - conn, cb_err, NULL); - } - } - } - break; - } + atomic_clear_bit(inst->flags, BAP_BA_FLAG_BUSY); + bap_broadcast_assistant_recv_state_changed(conn, cb_err, + active_recv_state ? &recv_state : NULL); } return BT_GATT_ITER_STOP; @@ -686,10 +645,7 @@ static uint8_t char_discover_func(struct bt_conn *conn, LOG_DBG("Found %u BASS receive states", inst->recv_state_cnt); (void)memset(params, 0, sizeof(*params)); - err = read_recv_state(inst, 0); - if (err != 0) { - bap_broadcast_assistant_discover_complete(conn, err, 0); - } + bap_broadcast_assistant_discover_complete(conn, 0, inst->recv_state_cnt); return BT_GATT_ITER_STOP; } diff --git a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c index 5d7d3ab7db8e9..47cf617f189b8 100644 --- a/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c @@ -179,6 +179,7 @@ static void bap_broadcast_assistant_recv_state_cb( #if defined(CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER) if (state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) { + printk("Sending PAST %p to %p\n", g_pa_sync, conn); err = bt_le_per_adv_sync_transfer(g_pa_sync, conn, BT_UUID_BASS_VAL); if (err != 0) { @@ -336,6 +337,29 @@ static void test_exchange_mtu(void) printk("MTU exchanged\n"); } +static void update_conn_params(void) +{ + /* When we are the broadcast assistant we do not know the PA interval or ISO interval, so + * set the connection parameters to something that is unlike to be a multiple of either to + * avoid issues with e.g. PAST. + * 45 fits nicely as it is not a multiple of neither BT_BAP_ADV_PARAM_BROADCAST_FAST or + * BT_BAP_ADV_PARAM_BROADCAST_SLOW, nor 7.5 ms or 10 ms for ISO + */ + int err; + + UNSET_FLAG(flag_conn_updated); + err = bt_conn_le_param_update(default_conn, + BT_LE_CONN_PARAM(BT_GAP_MS_TO_CONN_INTERVAL(35), + BT_GAP_MS_TO_CONN_INTERVAL(35), 0, + BT_GAP_MS_TO_CONN_TIMEOUT(4000))); + if (err != 0) { + FAIL("Failed to update connection parameters %d\n", err); + return; + } + + WAIT_FOR_FLAG(flag_conn_updated); +} + static void test_bass_discover(void) { int err; @@ -749,6 +773,8 @@ static int common_init(void) WAIT_FOR_FLAG(flag_connected); + update_conn_params(); + test_exchange_mtu(); test_bass_discover(); test_bass_read_receive_states(); diff --git a/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c b/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c index ca0e38ec600fc..855154b2b0aae 100644 --- a/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c +++ b/tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c @@ -152,11 +152,11 @@ static int pa_sync_past(struct bt_conn *conn, param.skip = PA_SYNC_SKIP; param.timeout = interval_to_sync_timeout(pa_interval); + printk("Subscribing to PAST from %p\n", conn); err = bt_le_per_adv_sync_transfer_subscribe(conn, ¶m); if (err != 0) { printk("Could not do PAST subscribe: %d\n", err); } else { - printk("Syncing with PAST: %d\n", err); state->pa_syncing = true; k_work_init_delayable(&state->pa_timer, pa_timer_handler); (void)k_work_reschedule(&state->pa_timer, @@ -233,14 +233,14 @@ static void recv_state_updated_cb(struct bt_conn *conn, state = sync_state_get_by_src_id(recv_state->src_id); if (state == NULL) { - FAIL("Could not get state"); + FAIL("Could not get state\n"); return; } if (state->recv_state != NULL) { if (state->recv_state != recv_state) { - FAIL("Sync state receive state mismatch: %p - %p", - state->recv_state, recv_state); + FAIL("Sync state receive state mismatch: %p - %p\n", state->recv_state, + recv_state); return; } } else { @@ -265,12 +265,12 @@ static int pa_sync_req_cb(struct bt_conn *conn, int err; reset_cp_flags(); - printk("PA Sync request: past_avail %u, pa_interval 0x%04x\n: %p", - past_avail, pa_interval, recv_state); + printk("PA Sync request: past_avail %u, pa_interval 0x%04x: %p\n", past_avail, pa_interval, + recv_state); state = sync_state_get_or_new(recv_state); if (state == NULL) { - FAIL("Could not get state"); + FAIL("Could not get state\n"); return -1; } @@ -513,7 +513,7 @@ static bool broadcast_source_found(struct bt_data *data, void *user_data) state = sync_state_get_or_new(NULL); if (state == NULL) { - FAIL("Failed to get sync state"); + FAIL("Failed to get sync state\n"); return true; } @@ -893,7 +893,7 @@ static void test_main_server_sync_server_rem(void) err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL); if (err != 0) { - FAIL("Could not start scan (%d)", err); + FAIL("Could not start scan (%d)\n", err); return; } diff --git a/tests/bsim/bluetooth/audio/test_scripts/bap_bass_client_sync.sh b/tests/bsim/bluetooth/audio/test_scripts/bap_bass_client_sync.sh index 6c3d71511d887..76744e5a54ec6 100755 --- a/tests/bsim/bluetooth/audio/test_scripts/bap_bass_client_sync.sh +++ b/tests/bsim/bluetooth/audio/test_scripts/bap_bass_client_sync.sh @@ -25,7 +25,7 @@ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \ Execute ./bs_${BOARD_TS}_tests_bsim_bluetooth_audio_prj_conf \ -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -d=2 -testid=bass_broadcaster \ - -RealEncryption=1 -rs=69 -D=3 -start_offset=2e3 + -RealEncryption=1 -rs=79 -D=3 -start_offset=4e3 # Simulation time should be larger than the WAIT_TIME in common.h Execute ./bs_2G4_phy_v1 -v=${VERBOSITY_LEVEL} -s=${SIMULATION_ID} -D=3 \