Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/releases/migration-guide-4.3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
64 changes: 64 additions & 0 deletions samples/bluetooth/bap_broadcast_assistant/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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)
{
Expand All @@ -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 = {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
66 changes: 11 additions & 55 deletions subsys/bluetooth/audio/bap_broadcast_assistant.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/bsim/bluetooth/audio/src/bap_broadcast_assistant_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
18 changes: 9 additions & 9 deletions tests/bsim/bluetooth/audio/src/bap_scan_delegator_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, &param);
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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
Loading