Skip to content

Commit 4750a06

Browse files
committed
Bluetooth: BAP: Shell: Refactor receive states
Refactor how receive states are handled in the BAP shell. The scan delegator's receive states are not available from the broadcast sink, and the broadcast sink makes sure to properly set the pa_sync object in the receive state struct. The receive states are now also using the BAP service data to identity the receive state when using PAST. The broadcast assistant will now cache data from a remote device, and makes it available to e.g. CAP. Additionally if there is a broadcast source, we cache the values neccesary to identity if a remote receive state represents our local broadcast source. Signed-off-by: Emil Gydesen <[email protected]>
1 parent 8f89606 commit 4750a06

File tree

5 files changed

+391
-118
lines changed

5 files changed

+391
-118
lines changed

subsys/bluetooth/audio/shell/audio.h

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
/*
8-
* Copyright (c) 2023 Nordic Semiconductor ASA
8+
* Copyright (c) 2023-2025 Nordic Semiconductor ASA
99
*
1010
* SPDX-License-Identifier: Apache-2.0
1111
*/
@@ -25,15 +25,18 @@
2525
#include <zephyr/bluetooth/bluetooth.h>
2626
#include <zephyr/bluetooth/hci_types.h>
2727
#include <zephyr/bluetooth/iso.h>
28+
#include <zephyr/kernel.h>
2829
#include <zephyr/shell/shell.h>
2930
#include <zephyr/sys/atomic_types.h>
3031
#include <zephyr/sys/byteorder.h>
3132
#include <zephyr/sys/printk.h>
3233
#include <zephyr/sys/util.h>
3334
#include <zephyr/sys/util_macro.h>
3435
#include <zephyr/sys_clock.h>
36+
#include <zephyr/toolchain.h>
3537

3638
#include "common/bt_shell_private.h"
39+
#include "host/shell/bt.h"
3740

3841
#define SHELL_PRINT_INDENT_LEVEL_SIZE 2
3942
#define MAX_CODEC_FRAMES_PER_SDU 4U
@@ -176,15 +179,16 @@ struct broadcast_source {
176179
};
177180
struct bt_audio_codec_cfg codec_cfg;
178181
struct bt_bap_qos_cfg qos;
179-
uint32_t broadcast_id;
182+
uint32_t broadcast_id; /* BT_BAP_INVALID_BROADCAST_ID when not in use */
183+
uint8_t addr_type;
184+
uint8_t adv_sid; /* BT_GAP_SID_INVALID when not in use */
180185
};
181186

182187
struct broadcast_sink {
183188
struct bt_bap_broadcast_sink *bap_sink;
184189
struct bt_le_per_adv_sync *pa_sync;
185190
uint8_t received_base[UINT8_MAX];
186191
uint8_t base_size;
187-
uint32_t broadcast_id;
188192
size_t stream_cnt;
189193
bool syncable;
190194
};
@@ -197,6 +201,32 @@ struct unicast_group {
197201
};
198202
};
199203

204+
struct broadcast_assistant_recv_state {
205+
/* Number of receive state on the remote device */
206+
uint8_t recv_state_count;
207+
208+
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
209+
/* Contains the src_id representing our local default_broadcast */
210+
uint8_t default_source_src_id;
211+
uint8_t default_source_subgroup_count;
212+
bool default_source_big_synced;
213+
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
214+
};
215+
216+
struct scan_delegator_sync_state {
217+
uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE];
218+
const struct bt_bap_scan_delegator_recv_state *recv_state;
219+
struct bt_le_per_adv_sync *pa_sync;
220+
struct bt_conn *conn;
221+
struct k_work_delayable pa_timer;
222+
uint32_t broadcast_id;
223+
uint16_t pa_interval;
224+
bool active;
225+
bool pa_syncing;
226+
bool past_avail;
227+
uint8_t src_id;
228+
};
229+
200230
#define BAP_UNICAST_AC_MAX_CONN 2U
201231
#define BAP_UNICAST_AC_MAX_SNK (2U * BAP_UNICAST_AC_MAX_CONN)
202232
#define BAP_UNICAST_AC_MAX_SRC (2U * BAP_UNICAST_AC_MAX_CONN)
@@ -239,6 +269,20 @@ int cap_ac_unicast(const struct shell *sh, const struct cap_unicast_ac_param *pa
239269
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
240270
#endif /* CONFIG_BT_BAP_UNICAST */
241271

272+
#if defined(CONFIG_BT_BAP_BROADCAST_ASSISTANT)
273+
extern struct broadcast_assistant_recv_state broadcast_assistant_recv_states[CONFIG_BT_MAX_CONN];
274+
#endif /* CONFIG_BT_BAP_BROADCAST_ASSISTANT */
275+
#if defined(CONFIG_BT_BAP_SCAN_DELEGATOR)
276+
extern struct scan_delegator_sync_state
277+
scan_delegator_sync_states[CONFIG_BT_BAP_SCAN_DELEGATOR_RECV_STATE_COUNT];
278+
279+
struct scan_delegator_sync_state *scan_delegator_sync_state_new(void);
280+
struct scan_delegator_sync_state *
281+
scan_delegator_sync_state_get_by_pa(struct bt_le_per_adv_sync *sync);
282+
struct scan_delegator_sync_state *
283+
scan_delegator_sync_state_get_by_values(uint32_t broadcast_id, uint8_t addr_type, uint8_t sid);
284+
#endif /* CONFIG_BT_BAP_SCAN_DELEGATOR */
285+
242286
static inline void print_qos(const struct bt_bap_qos_cfg *qos)
243287
{
244288
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE) || defined(CONFIG_BT_BAP_UNICAST)

subsys/bluetooth/audio/shell/bap.c

Lines changed: 122 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
/*
77
* Copyright (c) 2020 Intel Corporation
8-
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
8+
* Copyright (c) 2022-2025 Nordic Semiconductor ASA
99
*
1010
* SPDX-License-Identifier: Apache-2.0
1111
*/
@@ -390,7 +390,6 @@ static bool encode_frame(struct shell_stream *sh_stream, uint8_t index, size_t f
390390
false;
391391
}
392392

393-
/* TODO: Move the following to a function in bap_usb.c*/
394393
bap_usb_get_frame(sh_stream, chan_alloc, lc3_tx_buf);
395394
} else {
396395
/* Generate sine wave */
@@ -817,6 +816,20 @@ static int set_metadata(struct bt_audio_codec_cfg *codec_cfg, const char *meta_s
817816
}
818817

819818
#if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
819+
static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
820+
{
821+
#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
822+
(void)memset(snks[bt_conn_index(conn)], 0, sizeof(snks[0]));
823+
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
824+
#if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
825+
(void)memset(srcs[bt_conn_index(conn)], 0, sizeof(srcs[0]));
826+
#endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
827+
}
828+
829+
BT_CONN_CB_DEFINE(conn_callbacks) = {
830+
.disconnected = disconnected_cb,
831+
};
832+
820833
static uint8_t stream_dir(const struct bt_bap_stream *stream)
821834
{
822835
if (stream->conn) {
@@ -2299,7 +2312,6 @@ struct bt_broadcast_info {
22992312
static struct broadcast_sink_auto_scan {
23002313
struct broadcast_sink *broadcast_sink;
23012314
struct bt_broadcast_info broadcast_info;
2302-
struct bt_le_per_adv_sync **out_sync;
23032315
} auto_scan = {
23042316
.broadcast_info = {
23052317
.broadcast_id = BT_BAP_INVALID_BROADCAST_ID,
@@ -2363,6 +2375,49 @@ static bool scan_check_and_get_broadcast_values(struct bt_data *data, void *user
23632375
}
23642376
}
23652377

2378+
static void pa_sync_broadcast_sink(const struct bt_le_scan_recv_info *info)
2379+
{
2380+
struct bt_le_per_adv_sync_param create_params = {0};
2381+
int err;
2382+
2383+
err = bt_le_scan_stop();
2384+
if (err != 0) {
2385+
bt_shell_error("Could not stop scan: %d", err);
2386+
}
2387+
2388+
bt_addr_le_copy(&create_params.addr, info->addr);
2389+
create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
2390+
create_params.sid = info->sid;
2391+
create_params.skip = PA_SYNC_SKIP;
2392+
create_params.timeout = interval_to_sync_timeout(info->interval);
2393+
2394+
bt_shell_print("Attempting to PA sync to the broadcaster");
2395+
err = bt_le_per_adv_sync_create(&create_params, &per_adv_syncs[selected_per_adv_sync]);
2396+
if (err != 0) {
2397+
bt_shell_error("Could not create Broadcast PA sync: %d", err);
2398+
} else {
2399+
struct bt_le_per_adv_sync *pa_sync = per_adv_syncs[selected_per_adv_sync];
2400+
struct scan_delegator_sync_state *sync_state = NULL;
2401+
2402+
default_broadcast_sink.pa_sync = pa_sync;
2403+
2404+
sync_state = scan_delegator_sync_state_get_by_values(
2405+
auto_scan.broadcast_info.broadcast_id, info->addr->type, info->sid);
2406+
if (sync_state == NULL) {
2407+
sync_state = scan_delegator_sync_state_new();
2408+
2409+
if (sync_state == NULL) {
2410+
bt_shell_error("Could not get new sync state");
2411+
2412+
return;
2413+
}
2414+
}
2415+
2416+
sync_state->pa_sync = pa_sync;
2417+
sync_state->broadcast_id = auto_scan.broadcast_info.broadcast_id;
2418+
}
2419+
}
2420+
23662421
static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
23672422
{
23682423
struct bt_broadcast_info sr_info = {0};
@@ -2407,31 +2462,11 @@ static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct
24072462
return;
24082463
}
24092464

2410-
bt_shell_print("Found matched broadcast with address %s", addr_str);
2411-
2412-
if (identified_broadcast && (auto_scan.broadcast_sink != NULL) &&
2413-
(auto_scan.broadcast_sink->pa_sync == NULL)) {
2414-
struct bt_le_per_adv_sync_param create_params = {0};
2415-
int err;
2465+
bt_shell_print("Found matched broadcast with address %s%s", addr_str,
2466+
info->interval > 0U ? "" : " but is not syncable");
24162467

2417-
err = bt_le_scan_stop();
2418-
if (err != 0) {
2419-
bt_shell_error("Could not stop scan: %d", err);
2420-
}
2421-
2422-
bt_addr_le_copy(&create_params.addr, info->addr);
2423-
create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
2424-
create_params.sid = info->sid;
2425-
create_params.skip = PA_SYNC_SKIP;
2426-
create_params.timeout = interval_to_sync_timeout(info->interval);
2427-
2428-
bt_shell_print("Attempting to PA sync to the broadcaster");
2429-
err = bt_le_per_adv_sync_create(&create_params, auto_scan.out_sync);
2430-
if (err != 0) {
2431-
bt_shell_error("Could not create Broadcast PA sync: %d", err);
2432-
} else {
2433-
auto_scan.broadcast_sink->pa_sync = *auto_scan.out_sync;
2434-
}
2468+
if (info->interval > 0U && identified_broadcast && auto_scan.broadcast_sink != NULL) {
2469+
pa_sync_broadcast_sink(info);
24352470
}
24362471
}
24372472

@@ -2465,8 +2500,7 @@ static void syncable(struct bt_bap_broadcast_sink *sink, const struct bt_iso_big
24652500
static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
24662501
struct bt_le_per_adv_sync_synced_info *info)
24672502
{
2468-
if (auto_scan.broadcast_sink != NULL && auto_scan.out_sync != NULL &&
2469-
sync == *auto_scan.out_sync) {
2503+
if (auto_scan.broadcast_sink != NULL && auto_scan.broadcast_sink->pa_sync == sync) {
24702504
bt_shell_print("PA synced to broadcast with broadcast ID 0x%06x",
24712505
auto_scan.broadcast_info.broadcast_id);
24722506

@@ -3075,7 +3109,6 @@ static void clear_stream_data(struct shell_stream *sh_stream)
30753109
/* All streams in the broadcast sink has been terminated */
30763110
memset(&default_broadcast_sink.received_base, 0,
30773111
sizeof(default_broadcast_sink.received_base));
3078-
default_broadcast_sink.broadcast_id = 0;
30793112
default_broadcast_sink.syncable = false;
30803113
}
30813114
}
@@ -3326,13 +3359,20 @@ static int cmd_start_broadcast(const struct shell *sh, size_t argc,
33263359
char *argv[])
33273360
{
33283361
struct bt_le_ext_adv *adv = adv_sets[selected_adv];
3362+
struct bt_le_ext_adv_info adv_info;
33293363
int err;
33303364

33313365
if (adv == NULL) {
33323366
shell_info(sh, "Extended advertising set is NULL");
33333367
return -ENOEXEC;
33343368
}
33353369

3370+
err = bt_le_ext_adv_get_info(adv, &adv_info);
3371+
if (err != 0) {
3372+
shell_error(sh, "Failed to get adv info: %d\n", err);
3373+
return -ENOEXEC;
3374+
}
3375+
33363376
if (default_source.bap_source == NULL || default_source.is_cap) {
33373377
shell_info(sh, "Broadcast source not created");
33383378
return -ENOEXEC;
@@ -3344,6 +3384,9 @@ static int cmd_start_broadcast(const struct shell *sh, size_t argc,
33443384
return err;
33453385
}
33463386

3387+
default_source.addr_type = adv_info.addr->type;
3388+
default_source.adv_sid = adv_info.sid;
3389+
33473390
return 0;
33483391
}
33493392

@@ -3362,6 +3405,8 @@ static int cmd_stop_broadcast(const struct shell *sh, size_t argc, char *argv[])
33623405
return err;
33633406
}
33643407

3408+
default_source.adv_sid = BT_GAP_SID_INVALID;
3409+
33653410
return 0;
33663411
}
33673412

@@ -3426,7 +3471,6 @@ static int cmd_create_broadcast_sink(const struct shell *sh, size_t argc, char *
34263471

34273472
auto_scan.broadcast_sink = &default_broadcast_sink;
34283473
auto_scan.broadcast_info.broadcast_id = broadcast_id;
3429-
auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync];
34303474
} else {
34313475
shell_print(sh, "Creating broadcast sink with broadcast ID 0x%06X",
34323476
(uint32_t)broadcast_id);
@@ -3438,6 +3482,52 @@ static int cmd_create_broadcast_sink(const struct shell *sh, size_t argc, char *
34383482
shell_error(sh, "Failed to create broadcast sink: %d", err);
34393483

34403484
return -ENOEXEC;
3485+
} else {
3486+
struct scan_delegator_sync_state *sync_state = NULL;
3487+
3488+
default_broadcast_sink.pa_sync = per_adv_sync;
3489+
3490+
/* Lookup sync_state by PA sync or by values */
3491+
sync_state = scan_delegator_sync_state_get_by_pa(per_adv_sync);
3492+
if (sync_state == NULL) {
3493+
struct bt_le_per_adv_sync_info sync_info;
3494+
3495+
err = bt_le_per_adv_sync_get_info(per_adv_sync, &sync_info);
3496+
if (err != 0) {
3497+
bt_shell_error("Failed to get sync info: %d", err);
3498+
err = bt_bap_broadcast_sink_delete(
3499+
default_broadcast_sink.bap_sink);
3500+
if (err != 0) {
3501+
bt_shell_error(
3502+
"Failed to delete broadcast sink: %d", err);
3503+
}
3504+
3505+
return -ENOEXEC;
3506+
}
3507+
3508+
sync_state = scan_delegator_sync_state_get_by_values(
3509+
auto_scan.broadcast_info.broadcast_id, sync_info.addr.type,
3510+
sync_info.sid);
3511+
}
3512+
3513+
if (sync_state == NULL) {
3514+
sync_state = scan_delegator_sync_state_new();
3515+
3516+
if (sync_state == NULL) {
3517+
bt_shell_error("Could not get new sync state");
3518+
err = bt_bap_broadcast_sink_delete(
3519+
default_broadcast_sink.bap_sink);
3520+
if (err != 0) {
3521+
bt_shell_error(
3522+
"Failed to delete broadcast sink: %d", err);
3523+
}
3524+
3525+
return -ENOEXEC;
3526+
}
3527+
}
3528+
3529+
sync_state->pa_sync = per_adv_sync;
3530+
sync_state->broadcast_id = (uint32_t)broadcast_id;
34413531
}
34423532
}
34433533

@@ -3479,7 +3569,6 @@ static int cmd_create_sink_by_name(const struct shell *sh, size_t argc, char *ar
34793569

34803570
auto_scan.broadcast_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
34813571
auto_scan.broadcast_sink = &default_broadcast_sink;
3482-
auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync];
34833572

34843573
return 0;
34853574
}
@@ -3860,6 +3949,7 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
38603949
}
38613950

38623951
default_source.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
3952+
default_source.adv_sid = BT_GAP_SID_INVALID;
38633953
#endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
38643954

38653955
#if defined(CONFIG_LIBLC3)

0 commit comments

Comments
 (0)