1 /*
2 * Copyright (c) 2022-2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <string.h>
12
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/addr.h>
15 #include <zephyr/bluetooth/audio/aics.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
19 #include <zephyr/bluetooth/audio/cap.h>
20 #include <zephyr/bluetooth/audio/csip.h>
21 #include <zephyr/bluetooth/audio/lc3.h>
22 #include <zephyr/bluetooth/audio/pacs.h>
23 #include <zephyr/bluetooth/audio/micp.h>
24 #include <zephyr/bluetooth/audio/vcp.h>
25 #include <zephyr/bluetooth/bluetooth.h>
26 #include <zephyr/bluetooth/byteorder.h>
27 #include <zephyr/bluetooth/gap.h>
28 #include <zephyr/bluetooth/iso.h>
29 #include <zephyr/bluetooth/uuid.h>
30 #include <zephyr/kernel.h>
31 #include <zephyr/logging/log.h>
32 #include <zephyr/logging/log_core.h>
33 #include <zephyr/net_buf.h>
34 #include <zephyr/sys/byteorder.h>
35 #include <zephyr/sys/util.h>
36 #include <zephyr/sys/util_macro.h>
37
38 #include "bap_stream_rx.h"
39 #include "bstests.h"
40 #include "common.h"
41 #include "bap_common.h"
42
43 LOG_MODULE_REGISTER(cap_handover_peripheral, LOG_LEVEL_DBG);
44
45 #if defined(CONFIG_BT_CAP_ACCEPTOR)
46 extern enum bst_result_t bst_result;
47
48 #define CAP_INITIATOR_DEV_ID 0 /* CAP initiator shall be ID 0 for these tests */
49
50 CREATE_FLAG(flag_broadcast_code);
51 CREATE_FLAG(flag_base_received);
52 CREATE_FLAG(flag_pa_synced);
53 CREATE_FLAG(flag_syncable);
54 CREATE_FLAG(flag_pa_sync_lost);
55 CREATE_FLAG(flag_pa_request);
56 CREATE_FLAG(flag_bis_sync_requested);
57 CREATE_FLAG(flag_base_metadata_updated);
58 CREATE_FLAG(flag_stream_configured);
59 CREATE_FLAG(flag_stream_started);
60 CREATE_FLAG(flag_stream_stopped);
61 CREATE_FLAG(flag_broadcast_started);
62 CREATE_FLAG(flag_broadcast_stopped);
63
64 static struct bt_bap_broadcast_sink *broadcast_sink;
65 static struct bt_le_per_adv_sync *pa_sync;
66 static const struct bt_bap_scan_delegator_recv_state *cached_recv_state;
67 static uint32_t cached_bis_sync_req;
68 static uint16_t cached_pa_interval;
69 static struct audio_test_stream
70 streams[MIN(CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT,
71 CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT + CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT)];
72 static uint8_t received_base[UINT8_MAX];
73 static size_t received_base_size;
74
75 static const struct bt_bap_qos_cfg_pref unicast_qos_pref =
76 BT_BAP_QOS_CFG_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 20000u, 40000u, 20000u, 40000u);
77
subgroup_data_func_cb(struct bt_data * data,void * user_data)78 static bool subgroup_data_func_cb(struct bt_data *data, void *user_data)
79 {
80 bool *stream_context_found = (bool *)user_data;
81
82 LOG_DBG("type %u len %u", data->type, data->data_len);
83
84 if (!valid_metadata_type(data->type, data->data_len)) {
85 return false;
86 }
87
88 if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
89 if (data->data_len != 2) { /* Stream context size */
90 return false;
91 }
92
93 *stream_context_found = true;
94 return false;
95 }
96
97 return true;
98 }
99
valid_subgroup_metadata_cb(const struct bt_bap_base_subgroup * subgroup,void * user_data)100 static bool valid_subgroup_metadata_cb(const struct bt_bap_base_subgroup *subgroup, void *user_data)
101 {
102 static uint8_t metadata[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
103 static size_t metadata_size;
104 bool stream_context_found = false;
105 uint8_t *meta;
106 int ret;
107
108 ret = bt_bap_base_get_subgroup_codec_meta(subgroup, &meta);
109 if (ret < 0) {
110 FAIL("Could not get subgroup meta: %d\n", ret);
111 return false;
112 }
113
114 if (TEST_FLAG(flag_base_received) && (!util_eq(meta, ret, metadata, metadata_size))) {
115 LOG_DBG("Metadata updated");
116 SET_FLAG(flag_base_metadata_updated);
117 }
118
119 metadata_size = (size_t)ret;
120
121 ret = bt_audio_data_parse(meta, (size_t)ret, subgroup_data_func_cb, &stream_context_found);
122 if (ret != 0 && ret != -ECANCELED) {
123 return false;
124 }
125
126 if (!stream_context_found) {
127 LOG_DBG("Subgroup did not have streaming context");
128 }
129
130 /* if this is false, the iterator will return early with an error */
131 return stream_context_found;
132 }
133
base_recv_cb(struct bt_bap_broadcast_sink * sink,const struct bt_bap_base * base,size_t base_size)134 static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base,
135 size_t base_size)
136 {
137 int ret;
138
139 if (TEST_FLAG(flag_base_received)) {
140 /* Don't expect any BASE updates */
141 return;
142 }
143
144 ret = bt_bap_base_get_subgroup_count(base);
145 if (ret < 0) {
146 FAIL("Failed to get subgroup count: %d\n", ret);
147 return;
148 } else if (ret == 0) {
149 FAIL("subgroup_count was 0\n");
150 return;
151 }
152
153 LOG_DBG("Received BASE with %d subgroups from broadcast sink %p", ret, sink);
154
155 ret = bt_bap_base_foreach_subgroup(base, valid_subgroup_metadata_cb, NULL);
156 if (ret != 0) {
157 FAIL("Failed to parse subgroups: %d\n", ret);
158 return;
159 }
160
161 (void)memcpy(received_base, base, base_size);
162 received_base_size = base_size;
163
164 SET_FLAG(flag_base_received);
165 }
166
syncable_cb(struct bt_bap_broadcast_sink * sink,const struct bt_iso_biginfo * biginfo)167 static void syncable_cb(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo)
168 {
169 LOG_DBG("Broadcast sink %p syncable with%s encryption", sink,
170 biginfo->encryption ? "" : "out");
171 SET_FLAG(flag_syncable);
172 }
173
broadcast_sink_started_cb(struct bt_bap_broadcast_sink * sink)174 static void broadcast_sink_started_cb(struct bt_bap_broadcast_sink *sink)
175 {
176 SET_FLAG(flag_broadcast_started);
177 }
178
broadcast_sink_stopped_cb(struct bt_bap_broadcast_sink * sink,uint8_t reason)179 static void broadcast_sink_stopped_cb(struct bt_bap_broadcast_sink *sink, uint8_t reason)
180 {
181 SET_FLAG(flag_broadcast_stopped);
182 }
183
bap_pa_sync_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)184 static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
185 struct bt_le_per_adv_sync_synced_info *info)
186 {
187 if (sync == pa_sync) {
188 LOG_DBG("PA sync %p synced for broadcast sink with broadcast ID 0x%06X", sync,
189 cached_recv_state->broadcast_id);
190
191 SET_FLAG(flag_pa_synced);
192 } else {
193 FAIL("Unexpected PA sync: %p\n");
194 }
195 }
196
bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)197 static void bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync,
198 const struct bt_le_per_adv_sync_term_info *info)
199 {
200 if (sync == pa_sync) {
201 LOG_DBG("PA sync %p lost with reason %u", sync, info->reason);
202 pa_sync = NULL;
203
204 SET_FLAG(flag_pa_sync_lost);
205 }
206 }
207
stream_enabled_cb(struct bt_bap_stream * stream)208 static void stream_enabled_cb(struct bt_bap_stream *stream)
209 {
210 struct bt_bap_ep_info ep_info;
211 int err;
212
213 LOG_DBG("Enabled: stream %p ", stream);
214
215 err = bt_bap_ep_get_info(stream->ep, &ep_info);
216 if (err != 0) {
217 FAIL("Failed to get ep info: %d\n", err);
218 return;
219 }
220
221 if (ep_info.dir == BT_AUDIO_DIR_SINK) {
222 /* Automatically do the receiver start ready operation */
223 err = bt_bap_stream_start(stream);
224
225 if (err != 0) {
226 FAIL("Failed to start stream: %d\n", err);
227 return;
228 }
229 }
230 }
231
stream_started_cb(struct bt_bap_stream * stream)232 static void stream_started_cb(struct bt_bap_stream *stream)
233 {
234 struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream);
235
236 memset(&test_stream->last_info, 0, sizeof(test_stream->last_info));
237 test_stream->rx_cnt = 0U;
238 test_stream->valid_rx_cnt = 0U;
239 test_stream->seq_num = 0U;
240 test_stream->tx_cnt = 0U;
241
242 LOG_DBG("Started stream %p", stream);
243
244 SET_FLAG(flag_stream_started);
245 }
246
stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)247 static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
248 {
249 LOG_DBG("Stopped stream %p with reason 0x%02X", stream, reason);
250
251 SET_FLAG(flag_stream_stopped);
252 }
253
pa_sync_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,bool past_avail,uint16_t pa_interval)254 static int pa_sync_req_cb(struct bt_conn *conn,
255 const struct bt_bap_scan_delegator_recv_state *recv_state,
256 bool past_avail, uint16_t pa_interval)
257 {
258 if (recv_state->pa_sync_state == BT_BAP_PA_STATE_SYNCED ||
259 recv_state->pa_sync_state == BT_BAP_PA_STATE_INFO_REQ) {
260 /* Already syncing */
261 /* TODO: Terminate existing sync and then sync to new?*/
262 return -EALREADY;
263 }
264
265 LOG_DBG("Sync request");
266
267 cached_pa_interval = pa_interval;
268 cached_recv_state = recv_state;
269
270 SET_FLAG(flag_pa_request);
271
272 return 0;
273 }
274
pa_sync_term_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state)275 static int pa_sync_term_req_cb(struct bt_conn *conn,
276 const struct bt_bap_scan_delegator_recv_state *recv_state)
277 {
278 if (pa_sync == NULL || recv_state->pa_sync_state == BT_BAP_PA_STATE_NOT_SYNCED) {
279 return -EALREADY;
280 }
281
282 UNSET_FLAG(flag_pa_request);
283
284 return 0;
285 }
286
bis_sync_req_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS])287 static int bis_sync_req_cb(struct bt_conn *conn,
288 const struct bt_bap_scan_delegator_recv_state *recv_state,
289 const uint32_t bis_sync_req[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS])
290 {
291 cached_bis_sync_req = 0U;
292
293 for (uint8_t i = 0U; i < recv_state->num_subgroups; i++) {
294 cached_bis_sync_req |= bis_sync_req[i];
295 }
296
297 if (cached_bis_sync_req != 0U) {
298 SET_FLAG(flag_bis_sync_requested);
299 } else {
300 UNSET_FLAG(flag_bis_sync_requested);
301 }
302
303 LOG_DBG("bis_sync_req 0x%08X", cached_bis_sync_req);
304
305 cached_recv_state = recv_state;
306
307 return 0;
308 }
309
broadcast_code_cb(struct bt_conn * conn,const struct bt_bap_scan_delegator_recv_state * recv_state,const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])310 static void broadcast_code_cb(struct bt_conn *conn,
311 const struct bt_bap_scan_delegator_recv_state *recv_state,
312 const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
313 {
314 LOG_DBG("Broadcast code received for %p", recv_state);
315
316 if (memcmp(broadcast_code, BROADCAST_CODE, sizeof(BROADCAST_CODE)) != 0) {
317 FAIL("Failed to receive correct broadcast code\n");
318 return;
319 }
320
321 SET_FLAG(flag_broadcast_code);
322 }
323
stream_alloc(void)324 static struct bt_bap_stream *stream_alloc(void)
325 {
326 for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
327 struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&streams[i]);
328
329 if (!stream->conn) {
330 return stream;
331 }
332 }
333
334 return NULL;
335 }
336
unicast_server_config(struct bt_conn * conn,const struct bt_bap_ep * ep,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_stream ** stream,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)337 static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *ep,
338 enum bt_audio_dir dir, const struct bt_audio_codec_cfg *codec_cfg,
339 struct bt_bap_stream **stream,
340 struct bt_bap_qos_cfg_pref *const pref,
341 struct bt_bap_ascs_rsp *rsp)
342 {
343 LOG_DBG("ASE Codec Config: conn %p ep %p dir %u", conn, ep, dir);
344
345 print_codec_cfg(codec_cfg);
346
347 *stream = stream_alloc();
348 if (*stream == NULL) {
349 LOG_DBG("No streams available");
350 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
351
352 return -ENOMEM;
353 }
354
355 LOG_DBG("ASE Codec Config stream %p", *stream);
356
357 SET_FLAG(flag_stream_configured);
358
359 *pref = unicast_qos_pref;
360
361 return 0;
362 }
363
unicast_server_reconfig(struct bt_bap_stream * stream,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)364 static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
365 const struct bt_audio_codec_cfg *codec_cfg,
366 struct bt_bap_qos_cfg_pref *const pref,
367 struct bt_bap_ascs_rsp *rsp)
368 {
369 LOG_DBG("ASE Codec Reconfig: stream %p", stream);
370
371 print_codec_cfg(codec_cfg);
372
373 *pref = unicast_qos_pref;
374
375 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
376
377 /* We only support one QoS at the moment, reject changes */
378 return -ENOEXEC;
379 }
380
unicast_server_qos(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg * qos,struct bt_bap_ascs_rsp * rsp)381 static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg *qos,
382 struct bt_bap_ascs_rsp *rsp)
383 {
384 LOG_DBG("QoS: stream %p qos %p", stream, qos);
385
386 print_qos(qos);
387
388 return 0;
389 }
390
ascs_data_func_cb(struct bt_data * data,void * user_data)391 static bool ascs_data_func_cb(struct bt_data *data, void *user_data)
392 {
393 struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
394
395 if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
396 LOG_DBG("Invalid metadata type %u or length %u", data->type, data->data_len);
397 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
398 return false;
399 }
400
401 return true;
402 }
403
unicast_server_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)404 static int unicast_server_enable(struct bt_bap_stream *stream, const uint8_t meta[],
405 size_t meta_len, struct bt_bap_ascs_rsp *rsp)
406 {
407 LOG_DBG("Enable: stream %p meta_len %zu", stream, meta_len);
408
409 return bt_audio_data_parse(meta, meta_len, ascs_data_func_cb, rsp);
410 }
411
unicast_server_start(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)412 static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
413 {
414 LOG_DBG("Start: stream %p", stream);
415
416 return 0;
417 }
418
unicast_server_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)419 static int unicast_server_metadata(struct bt_bap_stream *stream, const uint8_t meta[],
420 size_t meta_len, struct bt_bap_ascs_rsp *rsp)
421 {
422 LOG_DBG("Metadata: stream %p meta_len %zu", stream, meta_len);
423
424 return bt_audio_data_parse(meta, meta_len, ascs_data_func_cb, rsp);
425 }
426
unicast_server_disable(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)427 static int unicast_server_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
428 {
429 LOG_DBG("Disable: stream %p", stream);
430
431 return 0;
432 }
433
unicast_server_stop(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)434 static int unicast_server_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
435 {
436 LOG_DBG("Stop: stream %p", stream);
437
438 return 0;
439 }
440
unicast_server_release(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)441 static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
442 {
443 LOG_DBG("Release: stream %p", stream);
444
445 return 0;
446 }
447
set_location(void)448 static void set_location(void)
449 {
450 int err;
451
452 if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
453 err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, BT_AUDIO_LOCATION_FRONT_CENTER);
454 if (err != 0) {
455 FAIL("Failed to set sink location (err %d)\n", err);
456 return;
457 }
458 }
459
460 if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
461 err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE,
462 BT_AUDIO_LOCATION_FRONT_LEFT |
463 BT_AUDIO_LOCATION_FRONT_RIGHT);
464 if (err != 0) {
465 FAIL("Failed to set source location (err %d)\n", err);
466 return;
467 }
468 }
469
470 LOG_DBG("Location successfully set");
471 }
472
set_supported_contexts(void)473 static void set_supported_contexts(void)
474 {
475 int err;
476
477 if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
478 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK, SINK_CONTEXT);
479 if (err != 0) {
480 FAIL("Failed to set sink supported contexts (err %d)\n", err);
481 return;
482 }
483
484 LOG_DBG("Supported sink contexts successfully set to 0x%04X", SINK_CONTEXT);
485 }
486
487 if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
488 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE, SOURCE_CONTEXT);
489 if (err != 0) {
490 FAIL("Failed to set source supported contexts (err %d)\n", err);
491 return;
492 }
493
494 LOG_DBG("Supported source contexts successfully set to 0x%04X", SOURCE_CONTEXT);
495 }
496 }
497
set_available_contexts(void)498 static void set_available_contexts(void)
499 {
500 if (IS_ENABLED(CONFIG_BT_PAC_SNK)) {
501 const int err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK, SINK_CONTEXT);
502
503 if (err != 0) {
504 FAIL("Failed to set sink available contexts (err %d)\n", err);
505 return;
506 }
507
508 LOG_DBG("Available sink contexts successfully set to 0x%04X", SINK_CONTEXT);
509 }
510
511 if (IS_ENABLED(CONFIG_BT_PAC_SRC)) {
512 const int err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE, SOURCE_CONTEXT);
513
514 if (err != 0) {
515 FAIL("Failed to set source available contexts (err %d)\n", err);
516 return;
517 }
518
519 LOG_DBG("Available source contexts successfully set to 0x%04X", SOURCE_CONTEXT);
520 }
521 }
522
test_start_adv(void)523 static void test_start_adv(void)
524 {
525 struct bt_le_ext_adv *ext_adv;
526
527 setup_connectable_adv(&ext_adv);
528 }
529
register_callbacks(void)530 static void register_callbacks(void)
531 {
532 static struct bt_bap_broadcast_sink_cb broadcast_sink_cbs = {
533 .base_recv = base_recv_cb,
534 .syncable = syncable_cb,
535 .started = broadcast_sink_started_cb,
536 .stopped = broadcast_sink_stopped_cb,
537 };
538 static struct bt_bap_scan_delegator_cb scan_delegator_cbs = {
539 .pa_sync_req = pa_sync_req_cb,
540 .pa_sync_term_req = pa_sync_term_req_cb,
541 .bis_sync_req = bis_sync_req_cb,
542 .broadcast_code = broadcast_code_cb,
543 };
544 static struct bt_bap_unicast_server_cb unicast_server_cbs = {
545 .config = unicast_server_config,
546 .reconfig = unicast_server_reconfig,
547 .qos = unicast_server_qos,
548 .enable = unicast_server_enable,
549 .start = unicast_server_start,
550 .metadata = unicast_server_metadata,
551 .disable = unicast_server_disable,
552 .stop = unicast_server_stop,
553 .release = unicast_server_release,
554 };
555 static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = {
556 .synced = bap_pa_sync_synced_cb,
557 .term = bap_pa_sync_terminated_cb,
558 };
559 static struct bt_bap_stream_ops stream_ops = {
560 .enabled = stream_enabled_cb,
561 .started = stream_started_cb,
562 .stopped = stream_stopped_cb,
563 .recv = bap_stream_rx_recv_cb,
564 };
565 int err;
566
567 err = bt_bap_unicast_server_register_cb(&unicast_server_cbs);
568 if (err != 0) {
569 FAIL("Failed to register unicast server callbacks (err %d)\n", err);
570
571 return;
572 }
573
574 err = bt_bap_scan_delegator_register(&scan_delegator_cbs);
575 if (err != 0) {
576 FAIL("Scan deligator register failed (err %d)\n", err);
577
578 return;
579 }
580
581 err = bt_bap_broadcast_sink_register_cb(&broadcast_sink_cbs);
582 if (err != 0) {
583 FAIL("Scan deligator register failed (err %d)\n", err);
584
585 return;
586 }
587
588 err = bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
589 if (err != 0) {
590 FAIL("Scan deligator register failed (err %d)\n", err);
591
592 return;
593 }
594
595 ARRAY_FOR_EACH_PTR(streams, stream) {
596 bt_cap_stream_ops_register(cap_stream_from_audio_test_stream(stream), &stream_ops);
597 }
598 }
599
init(void)600 static void init(void)
601 {
602 static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
603 BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY,
604 BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, 2,
605 (BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | BT_AUDIO_CONTEXT_TYPE_MEDIA));
606 const struct bt_pacs_register_param pacs_param = {
607 #if defined(CONFIG_BT_PAC_SNK)
608 .snk_pac = true,
609 #endif /* CONFIG_BT_PAC_SNK */
610 #if defined(CONFIG_BT_PAC_SNK_LOC)
611 .snk_loc = true,
612 #endif /* CONFIG_BT_PAC_SNK_LOC */
613 #if defined(CONFIG_BT_PAC_SRC)
614 .src_pac = true,
615 #endif /* CONFIG_BT_PAC_SRC */
616 #if defined(CONFIG_BT_PAC_SRC_LOC)
617 .src_loc = true,
618 #endif /* CONFIG_BT_PAC_SRC_LOC */
619 };
620 const struct bt_csip_set_member_register_param csip_set_member_param = {
621 .set_size = 3,
622 .rank = 1,
623 .lockable = true,
624 .sirk = TEST_SAMPLE_SIRK,
625 };
626 static struct bt_bap_unicast_server_register_param param = {
627 .snk_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT,
628 .src_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT,
629 };
630 static struct bt_csip_set_member_svc_inst *csip_set_member;
631 static struct bt_pacs_cap pacs_cap = {
632 .codec_cap = &codec_cap,
633 };
634
635 int err;
636
637 err = bt_enable(NULL);
638 if (err != 0) {
639 FAIL("Bluetooth enable failed (err %d)\n", err);
640 return;
641 }
642
643 LOG_DBG("Bluetooth initialized");
644
645 err = bt_pacs_register(&pacs_param);
646 if (err) {
647 FAIL("Could not register PACS (err %d)\n", err);
648 return;
649 }
650
651 err = bt_cap_acceptor_register(&csip_set_member_param, &csip_set_member);
652 if (err != 0) {
653 FAIL("CAP acceptor failed to register (err %d)\n", err);
654 return;
655 }
656
657 err = bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &pacs_cap);
658 if (err != 0) {
659 FAIL("Broadcast capability register failed (err %d)\n", err);
660
661 return;
662 }
663
664 err = bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &pacs_cap);
665 if (err != 0) {
666 FAIL("Broadcast capability register failed (err %d)\n", err);
667
668 return;
669 }
670
671 err = bt_bap_unicast_server_register(¶m);
672 if (err != 0) {
673 FAIL("Failed to register unicast server (err %d)\n", err);
674
675 return;
676 }
677
678 set_supported_contexts();
679 set_available_contexts();
680 set_location();
681
682 register_callbacks();
683 }
684
pa_sync_create(void)685 static void pa_sync_create(void)
686 {
687 struct bt_le_per_adv_sync_param create_params = {0};
688 int err;
689
690 bt_addr_le_copy(&create_params.addr, &cached_recv_state->addr);
691 create_params.options = BT_LE_PER_ADV_SYNC_OPT_NONE;
692 create_params.sid = cached_recv_state->adv_sid;
693 create_params.skip = PA_SYNC_SKIP;
694 create_params.timeout = interval_to_sync_timeout(cached_pa_interval);
695
696 err = bt_le_per_adv_sync_create(&create_params, &pa_sync);
697 if (err != 0) {
698 FAIL("Could not create Broadcast PA sync: %d\n", err);
699 return;
700 }
701
702 LOG_DBG("Waiting for PA sync");
703 WAIT_FOR_FLAG(flag_pa_synced);
704 }
705
create_and_sync_sink(void)706 static void create_and_sync_sink(void)
707 {
708 struct bt_bap_stream *broadcast_streams[ARRAY_SIZE(streams)];
709 int err;
710
711 LOG_DBG("Creating the broadcast sink");
712 err = bt_bap_broadcast_sink_create(pa_sync, cached_recv_state->broadcast_id,
713 &broadcast_sink);
714 if (err != 0) {
715 FAIL("Unable to create the sink: %d\n", err);
716 return;
717 }
718
719 LOG_DBG("Broadcast source PA synced, waiting for BASE");
720 WAIT_FOR_FLAG(flag_base_received);
721 LOG_DBG("BASE received");
722
723 LOG_DBG("Waiting for BIG syncable");
724 WAIT_FOR_FLAG(flag_syncable);
725
726 for (size_t i = 0U; i < ARRAY_SIZE(streams); i++) {
727 broadcast_streams[i] = bap_stream_from_audio_test_stream(&streams[i]);
728 }
729
730 if (cached_bis_sync_req == 0U) {
731 FAIL("Invalid cached_bis_sync_req: %u", cached_bis_sync_req);
732 return;
733 }
734
735 LOG_DBG("Syncing the sink to 0x%08x", cached_bis_sync_req);
736
737 err = bt_bap_broadcast_sink_sync(broadcast_sink, cached_bis_sync_req, broadcast_streams,
738 NULL);
739 if (err != 0) {
740 FAIL("Unable to sync the sink: %d\n", err);
741 return;
742 }
743
744 /* Wait for all to be started */
745 LOG_DBG("Waiting for broadcast streams to be started");
746 WAIT_FOR_FLAG(flag_broadcast_started);
747 }
748
wait_for_data(void)749 static void wait_for_data(void)
750 {
751 UNSET_FLAG(flag_audio_received);
752
753 LOG_DBG("Waiting for data");
754 WAIT_FOR_FLAG(flag_audio_received);
755 LOG_DBG("Data received");
756 }
757
test_cap_handover_peripheral_unicast_to_broadcast(void)758 static void test_cap_handover_peripheral_unicast_to_broadcast(void)
759 {
760 init();
761
762 test_start_adv();
763
764 WAIT_FOR_FLAG(flag_connected);
765
766 /* Wait until initiator is done starting streams */
767 WAIT_FOR_FLAG(flag_stream_started);
768 backchannel_sync_wait(CAP_INITIATOR_DEV_ID);
769
770 wait_for_data();
771
772 /* let initiator know we have received what we wanted */
773 backchannel_sync_send(CAP_INITIATOR_DEV_ID);
774
775 /* Wait for unicast to be stopped */
776 WAIT_FOR_FLAG(flag_stream_stopped);
777
778 /* Wait for a PA sync request to switch from unicast to broadcast */
779 LOG_DBG("Waiting for PA sync request");
780 WAIT_FOR_FLAG(flag_pa_request);
781 pa_sync_create();
782
783 /* Wait for a BIG sync request to sync to broadcast */
784 WAIT_FOR_FLAG(flag_bis_sync_requested);
785 create_and_sync_sink();
786
787 wait_for_data();
788
789 /* let initiator know we have received what we wanted */
790 backchannel_sync_send(CAP_INITIATOR_DEV_ID);
791
792 /* Wait for broadcast to be stopped */
793 WAIT_FOR_FLAG(flag_broadcast_stopped);
794
795 PASS("CAP acceptor unicast passed\n");
796 }
797
798 static const struct bst_test_instance test_cap_handover_peripheral[] = {
799 {
800 .test_id = "cap_handover_peripheral_unicast_to_broadcast",
801 .test_pre_init_f = test_init,
802 .test_tick_f = test_tick,
803 .test_main_f = test_cap_handover_peripheral_unicast_to_broadcast,
804 },
805 BSTEST_END_MARKER,
806 };
807
test_cap_handover_peripheral_install(struct bst_test_list * tests)808 struct bst_test_list *test_cap_handover_peripheral_install(struct bst_test_list *tests)
809 {
810 return bst_add_tests(tests, test_cap_handover_peripheral);
811 }
812
813 #else /* !(CONFIG_BT_CAP_ACCEPTOR) */
814
test_cap_handover_peripheral_install(struct bst_test_list * tests)815 struct bst_test_list *test_cap_handover_peripheral_install(struct bst_test_list *tests)
816 {
817 return tests;
818 }
819
820 #endif /* CONFIG_BT_CAP_ACCEPTOR */
821