1 /*
2 * Copyright (c) 2023-2025 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <errno.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <stddef.h>
11 #include <string.h>
12
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/addr.h>
15 #include <zephyr/bluetooth/audio/audio.h>
16 #include <zephyr/bluetooth/audio/cap.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/audio/csip.h>
19 #include <zephyr/bluetooth/audio/gmap.h>
20 #include <zephyr/bluetooth/audio/gmap_lc3_preset.h>
21 #include <zephyr/bluetooth/bluetooth.h>
22 #include <zephyr/bluetooth/byteorder.h>
23 #include <zephyr/bluetooth/conn.h>
24 #include <zephyr/bluetooth/crypto.h>
25 #include <zephyr/bluetooth/gap.h>
26 #include <zephyr/bluetooth/gatt.h>
27 #include <zephyr/bluetooth/hci_types.h>
28 #include <zephyr/bluetooth/iso.h>
29 #include <zephyr/bluetooth/uuid.h>
30 #include <zephyr/kernel.h>
31 #include <zephyr/net_buf.h>
32 #include <zephyr/sys/byteorder.h>
33 #include <zephyr/sys/printk.h>
34 #include <zephyr/sys/util.h>
35 #include <zephyr/sys/util_macro.h>
36 #include <zephyr/toolchain.h>
37
38 #include "bap_stream_tx.h"
39 #include "bap_stream_rx.h"
40 #include "bstests.h"
41 #include "common.h"
42 #include "bap_common.h"
43
44 #if defined(CONFIG_BT_GMAP)
45
46 #define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0)
47 #define UNICAST_SRC_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0)
48
49 #define CONTEXT (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_GAME)
50 #define LOCATION (BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT)
51
52 #define GMAP_BROADCAST_AC_MAX_STREAM 2
53 #define GMAP_UNICAST_AC_MAX_CONN 2U
54 #define GMAP_UNICAST_AC_MAX_SNK (2U * GMAP_UNICAST_AC_MAX_CONN)
55 #define GMAP_UNICAST_AC_MAX_SRC (2U * GMAP_UNICAST_AC_MAX_CONN)
56 #define GMAP_UNICAST_AC_MAX_PAIR MAX(GMAP_UNICAST_AC_MAX_SNK, GMAP_UNICAST_AC_MAX_SRC)
57 #define GMAP_UNICAST_AC_MAX_STREAM (GMAP_UNICAST_AC_MAX_SNK + GMAP_UNICAST_AC_MAX_SRC)
58
59 extern enum bst_result_t bst_result;
60 static const struct named_lc3_preset *snk_named_preset;
61 static const struct named_lc3_preset *src_named_preset;
62 static const struct named_lc3_preset *broadcast_named_preset;
63
64 struct gmap_unicast_ac_param {
65 char *name;
66 size_t conn_cnt;
67 size_t snk_cnt[GMAP_UNICAST_AC_MAX_CONN];
68 size_t src_cnt[GMAP_UNICAST_AC_MAX_CONN];
69 size_t snk_chan_cnt;
70 const struct named_lc3_preset *snk_named_preset;
71 const struct named_lc3_preset *src_named_preset;
72 };
73 struct gmap_broadcast_ac_param {
74 char *name;
75 size_t stream_cnt;
76 size_t chan_cnt;
77 const struct named_lc3_preset *named_preset;
78 };
79
80 static struct named_lc3_preset gmap_unicast_snk_presets[] = {
81 {"32_1_gr", BT_GMAP_LC3_PRESET_32_1_GR(LOCATION, CONTEXT)},
82 {"32_2_gr", BT_GMAP_LC3_PRESET_32_2_GR(LOCATION, CONTEXT)},
83 {"48_1_gr", BT_GMAP_LC3_PRESET_48_1_GR(LOCATION, CONTEXT)},
84 {"48_2_gr", BT_GMAP_LC3_PRESET_48_2_GR(LOCATION, CONTEXT)},
85 {"48_3_gr", BT_GMAP_LC3_PRESET_48_3_GR(LOCATION, CONTEXT)},
86 {"48_4_gr", BT_GMAP_LC3_PRESET_48_4_GR(LOCATION, CONTEXT)},
87 };
88
89 static struct named_lc3_preset gmap_unicast_src_presets[] = {
90 {"16_1_gs", BT_GMAP_LC3_PRESET_16_1_GS(LOCATION, CONTEXT)},
91 {"16_2_gs", BT_GMAP_LC3_PRESET_16_2_GS(LOCATION, CONTEXT)},
92 {"32_1_gs", BT_GMAP_LC3_PRESET_32_1_GS(LOCATION, CONTEXT)},
93 {"32_2_gs", BT_GMAP_LC3_PRESET_32_2_GS(LOCATION, CONTEXT)},
94 {"48_1_gs", BT_GMAP_LC3_PRESET_48_1_GS(LOCATION, CONTEXT)},
95 {"48_2_gs", BT_GMAP_LC3_PRESET_48_2_GS(LOCATION, CONTEXT)},
96 };
97
98 static struct named_lc3_preset gmap_broadcast_presets[] = {
99 {"48_1_g", BT_GMAP_LC3_PRESET_48_1_G(LOCATION, CONTEXT)},
100 {"48_2_g", BT_GMAP_LC3_PRESET_48_2_G(LOCATION, CONTEXT)},
101 {"48_3_g", BT_GMAP_LC3_PRESET_48_3_G(LOCATION, CONTEXT)},
102 {"48_4_g", BT_GMAP_LC3_PRESET_48_4_G(LOCATION, CONTEXT)},
103 };
104
105 struct named_lc3_preset named_preset;
106
107 static struct audio_test_stream broadcast_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
108 static struct unicast_stream unicast_streams[GMAP_UNICAST_AC_MAX_STREAM];
109 static struct bt_cap_stream *started_unicast_streams[GMAP_UNICAST_AC_MAX_STREAM];
110 static size_t started_unicast_streams_cnt;
111 static struct bt_bap_ep
112 *sink_eps[GMAP_UNICAST_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
113 static struct bt_bap_ep
114 *source_eps[GMAP_UNICAST_AC_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
115 static struct bt_conn *connected_conns[GMAP_UNICAST_AC_MAX_CONN];
116 static size_t connected_conn_cnt;
117
118 static K_SEM_DEFINE(sem_stream_started, 0U,
119 MAX(ARRAY_SIZE(unicast_streams), ARRAY_SIZE(broadcast_streams)));
120 static K_SEM_DEFINE(sem_stream_stopped, 0U,
121 MAX(ARRAY_SIZE(unicast_streams), ARRAY_SIZE(broadcast_streams)));
122
123 CREATE_FLAG(flag_cas_discovered);
124 CREATE_FLAG(flag_started);
125 CREATE_FLAG(flag_updated);
126 CREATE_FLAG(flag_stopped);
127 CREATE_FLAG(flag_mtu_exchanged);
128 CREATE_FLAG(flag_sink_discovered);
129 CREATE_FLAG(flag_source_discovered);
130 CREATE_FLAG(flag_gmap_discovered);
131
gmap_get_named_preset(bool is_unicast,enum bt_audio_dir dir,const char * preset_arg)132 const struct named_lc3_preset *gmap_get_named_preset(bool is_unicast, enum bt_audio_dir dir,
133 const char *preset_arg)
134 {
135 if (is_unicast) {
136 if (dir == BT_AUDIO_DIR_SINK) {
137 for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_snk_presets); i++) {
138 if (!strcmp(preset_arg, gmap_unicast_snk_presets[i].name)) {
139 return &gmap_unicast_snk_presets[i];
140 }
141 }
142 } else if (dir == BT_AUDIO_DIR_SOURCE) {
143 for (size_t i = 0U; i < ARRAY_SIZE(gmap_unicast_src_presets); i++) {
144 if (!strcmp(preset_arg, gmap_unicast_src_presets[i].name)) {
145 return &gmap_unicast_src_presets[i];
146 }
147 }
148 }
149 } else {
150
151 for (size_t i = 0U; i < ARRAY_SIZE(gmap_broadcast_presets); i++) {
152 if (!strcmp(preset_arg, gmap_broadcast_presets[i].name)) {
153 return &gmap_broadcast_presets[i];
154 }
155 }
156 }
157
158 return NULL;
159 }
160
stream_configured_cb(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg_pref * pref)161 static void stream_configured_cb(struct bt_bap_stream *stream,
162 const struct bt_bap_qos_cfg_pref *pref)
163 {
164 printk("Configured stream %p\n", stream);
165
166 /* TODO: The preference should be used/taken into account when
167 * setting the QoS
168 */
169 }
170
stream_qos_set_cb(struct bt_bap_stream * stream)171 static void stream_qos_set_cb(struct bt_bap_stream *stream)
172 {
173 printk("QoS set stream %p\n", stream);
174 }
175
stream_enabled_cb(struct bt_bap_stream * stream)176 static void stream_enabled_cb(struct bt_bap_stream *stream)
177 {
178 printk("Enabled stream %p\n", stream);
179 }
180
stream_started_cb(struct bt_bap_stream * stream)181 static void stream_started_cb(struct bt_bap_stream *stream)
182 {
183 struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream);
184
185 memset(&test_stream->last_info, 0, sizeof(test_stream->last_info));
186 test_stream->rx_cnt = 0U;
187 test_stream->valid_rx_cnt = 0U;
188 test_stream->seq_num = 0U;
189 test_stream->tx_cnt = 0U;
190
191 printk("Started stream %p\n", stream);
192
193 if (bap_stream_tx_can_send(stream)) {
194 int err;
195
196 err = bap_stream_tx_register(stream);
197 if (err != 0) {
198 FAIL("Failed to register stream %p for TX: %d\n", stream, err);
199 return;
200 }
201 }
202
203 k_sem_give(&sem_stream_started);
204 }
205
stream_metadata_updated_cb(struct bt_bap_stream * stream)206 static void stream_metadata_updated_cb(struct bt_bap_stream *stream)
207 {
208 printk("Metadata updated stream %p\n", stream);
209 }
210
stream_disabled_cb(struct bt_bap_stream * stream)211 static void stream_disabled_cb(struct bt_bap_stream *stream)
212 {
213 printk("Disabled stream %p\n", stream);
214 }
215
stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)216 static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
217 {
218 printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
219
220 if (bap_stream_tx_can_send(stream)) {
221 int err;
222
223 err = bap_stream_tx_unregister(stream);
224 if (err != 0) {
225 FAIL("Failed to unregister stream %p for TX: %d\n", stream, err);
226 return;
227 }
228 }
229
230 k_sem_give(&sem_stream_stopped);
231 }
232
stream_released_cb(struct bt_bap_stream * stream)233 static void stream_released_cb(struct bt_bap_stream *stream)
234 {
235 printk("Released stream %p\n", stream);
236 }
237
238 static struct bt_bap_stream_ops stream_ops = {
239 .configured = stream_configured_cb,
240 .qos_set = stream_qos_set_cb,
241 .enabled = stream_enabled_cb,
242 .started = stream_started_cb,
243 .metadata_updated = stream_metadata_updated_cb,
244 .disabled = stream_disabled_cb,
245 .stopped = stream_stopped_cb,
246 .released = stream_released_cb,
247 .sent = bap_stream_tx_sent_cb,
248 .recv = bap_stream_rx_recv_cb,
249 };
250
cap_discovery_complete_cb(struct bt_conn * conn,int err,const struct bt_csip_set_coordinator_set_member * member,const struct bt_csip_set_coordinator_csis_inst * csis_inst)251 static void cap_discovery_complete_cb(struct bt_conn *conn, int err,
252 const struct bt_csip_set_coordinator_set_member *member,
253 const struct bt_csip_set_coordinator_csis_inst *csis_inst)
254 {
255 if (err != 0) {
256 FAIL("Failed to discover CAS: %d\n", err);
257
258 return;
259 }
260
261 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR_SET_MEMBER)) {
262 if (csis_inst == NULL) {
263 FAIL("Failed to discover CAS CSIS\n");
264
265 return;
266 }
267
268 printk("Found CAS with CSIS %p\n", csis_inst);
269 } else {
270 printk("Found CAS\n");
271 }
272
273 SET_FLAG(flag_cas_discovered);
274 }
275
unicast_start_complete_cb(int err,struct bt_conn * conn)276 static void unicast_start_complete_cb(int err, struct bt_conn *conn)
277 {
278 if (err != 0) {
279 FAIL("Failed to start (failing conn %p): %d\n", conn, err);
280
281 return;
282 }
283
284 SET_FLAG(flag_started);
285 }
286
unicast_update_complete_cb(int err,struct bt_conn * conn)287 static void unicast_update_complete_cb(int err, struct bt_conn *conn)
288 {
289 if (err != 0) {
290 FAIL("Failed to update (failing conn %p): %d\n", conn, err);
291
292 return;
293 }
294
295 SET_FLAG(flag_updated);
296 }
297
unicast_stop_complete_cb(int err,struct bt_conn * conn)298 static void unicast_stop_complete_cb(int err, struct bt_conn *conn)
299 {
300 if (err != 0) {
301 FAIL("Failed to stop (failing conn %p): %d\n", conn, err);
302
303 return;
304 }
305
306 SET_FLAG(flag_stopped);
307 }
308
309 static struct bt_cap_initiator_cb cap_cb = {
310 .unicast_discovery_complete = cap_discovery_complete_cb,
311 .unicast_start_complete = unicast_start_complete_cb,
312 .unicast_update_complete = unicast_update_complete_cb,
313 .unicast_stop_complete = unicast_stop_complete_cb,
314 };
315
add_remote_sink_ep(struct bt_conn * conn,struct bt_bap_ep * ep)316 static void add_remote_sink_ep(struct bt_conn *conn, struct bt_bap_ep *ep)
317 {
318 for (size_t i = 0U; i < ARRAY_SIZE(sink_eps[bt_conn_index(conn)]); i++) {
319 if (sink_eps[bt_conn_index(conn)][i] == NULL) {
320 printk("Conn %p: Sink #%zu: ep %p\n", conn, i, ep);
321 sink_eps[bt_conn_index(conn)][i] = ep;
322 break;
323 }
324 }
325 }
326
add_remote_source_ep(struct bt_conn * conn,struct bt_bap_ep * ep)327 static void add_remote_source_ep(struct bt_conn *conn, struct bt_bap_ep *ep)
328 {
329 for (size_t i = 0U; i < ARRAY_SIZE(source_eps[bt_conn_index(conn)]); i++) {
330 if (source_eps[bt_conn_index(conn)][i] == NULL) {
331 printk("Conn %p: Source #%zu: ep %p\n", conn, i, ep);
332 source_eps[bt_conn_index(conn)][i] = ep;
333 break;
334 }
335 }
336 }
337
bap_pac_record_cb(struct bt_conn * conn,enum bt_audio_dir dir,const struct bt_audio_codec_cap * codec_cap)338 static void bap_pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir,
339 const struct bt_audio_codec_cap *codec_cap)
340 {
341 printk("conn %p codec_cap %p dir 0x%02x\n", conn, codec_cap, dir);
342
343 print_codec_cap(codec_cap);
344 }
345
bap_endpoint_cb(struct bt_conn * conn,enum bt_audio_dir dir,struct bt_bap_ep * ep)346 static void bap_endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
347 {
348 if (dir == BT_AUDIO_DIR_SINK) {
349 add_remote_sink_ep(conn, ep);
350 } else if (dir == BT_AUDIO_DIR_SOURCE) {
351 add_remote_source_ep(conn, ep);
352 }
353 }
354
bap_discover_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)355 static void bap_discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
356 {
357 if (err != 0) {
358 FAIL("Discovery failed for dir %u: %d\n", dir, err);
359 return;
360 }
361
362 if (dir == BT_AUDIO_DIR_SINK) {
363 printk("Sink discover complete\n");
364 SET_FLAG(flag_sink_discovered);
365 } else if (dir == BT_AUDIO_DIR_SOURCE) {
366 printk("Source discover complete\n");
367 SET_FLAG(flag_source_discovered);
368 }
369 }
370
371 static struct bt_bap_unicast_client_cb unicast_client_cbs = {
372 .pac_record = bap_pac_record_cb,
373 .endpoint = bap_endpoint_cb,
374 .discover = bap_discover_cb,
375 };
376
att_mtu_updated(struct bt_conn * conn,uint16_t tx,uint16_t rx)377 static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
378 {
379 printk("MTU exchanged\n");
380 SET_FLAG(flag_mtu_exchanged);
381 }
382
383 static struct bt_gatt_cb gatt_callbacks = {
384 .att_mtu_updated = att_mtu_updated,
385 };
386
gmap_discover_cb(struct bt_conn * conn,int err,enum bt_gmap_role role,struct bt_gmap_feat features)387 static void gmap_discover_cb(struct bt_conn *conn, int err, enum bt_gmap_role role,
388 struct bt_gmap_feat features)
389 {
390 enum bt_gmap_ugt_feat ugt_feat;
391
392 if (err != 0) {
393 FAIL("gmap discovery (err %d)\n", err);
394 return;
395 }
396
397 printk("GMAP discovered for conn %p:\n\trole 0x%02x\n\tugg_feat 0x%02x\n\tugt_feat "
398 "0x%02x\n\tbgs_feat 0x%02x\n\tbgr_feat 0x%02x\n",
399 conn, role, features.ugg_feat, features.ugt_feat, features.bgs_feat,
400 features.bgr_feat);
401
402 if ((role & BT_GMAP_ROLE_UGT) == 0) {
403 FAIL("Remote GMAP device is not a UGT\n");
404 return;
405 }
406
407 ugt_feat = features.ugt_feat;
408 if ((ugt_feat & BT_GMAP_UGT_FEAT_SOURCE) == 0 ||
409 (ugt_feat & BT_GMAP_UGT_FEAT_80KBPS_SOURCE) == 0 ||
410 (ugt_feat & BT_GMAP_UGT_FEAT_SINK) == 0 ||
411 (ugt_feat & BT_GMAP_UGT_FEAT_64KBPS_SINK) == 0 ||
412 (ugt_feat & BT_GMAP_UGT_FEAT_MULTIPLEX) == 0 ||
413 (ugt_feat & BT_GMAP_UGT_FEAT_MULTISINK) == 0 ||
414 (ugt_feat & BT_GMAP_UGT_FEAT_MULTISOURCE) == 0) {
415 FAIL("Remote GMAP device does not have expected UGT features: %d\n", ugt_feat);
416 return;
417 }
418
419 SET_FLAG(flag_gmap_discovered);
420 }
421
422 static const struct bt_gmap_cb gmap_cb = {
423 .discover = gmap_discover_cb,
424 };
425
scan_recv_cb(const struct bt_le_scan_recv_info * info,struct net_buf_simple * buf)426 static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
427 {
428 char addr_str[BT_ADDR_LE_STR_LEN];
429 struct bt_conn *conn;
430 int err;
431
432 /* Check for connectable, extended advertising */
433 if (((info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) == 0) ||
434 ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE)) == 0) {
435 /* We're only interested in connectable extended advertising */
436 }
437
438 conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, info->addr);
439 if (conn != NULL) {
440 /* Already connected to this device */
441 bt_conn_unref(conn);
442 return;
443 }
444
445 bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
446 printk("Device found: %s (RSSI %d)\n", addr_str, info->rssi);
447
448 /* connect only to devices in close proximity */
449 if (info->rssi < -70) {
450 FAIL("RSSI too low");
451 return;
452 }
453
454 printk("Stopping scan\n");
455 if (bt_le_scan_stop()) {
456 FAIL("Could not stop scan");
457 return;
458 }
459
460 err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN,
461 BT_LE_CONN_PARAM(BT_GAP_INIT_CONN_INT_MIN, BT_GAP_INIT_CONN_INT_MIN,
462 0, BT_GAP_MS_TO_CONN_TIMEOUT(4000)),
463 &connected_conns[connected_conn_cnt]);
464 if (err != 0) {
465 FAIL("Could not connect to peer: %d", err);
466 }
467 }
468
init(void)469 static void init(void)
470 {
471 const struct bt_gmap_feat features = {
472 .ugg_feat = (BT_GMAP_UGG_FEAT_MULTIPLEX | BT_GMAP_UGG_FEAT_96KBPS_SOURCE |
473 BT_GMAP_UGG_FEAT_MULTISINK),
474 };
475 const enum bt_gmap_role role = BT_GMAP_ROLE_UGG;
476 static struct bt_le_scan_cb scan_cb = {
477 .recv = scan_recv_cb,
478 };
479 int err;
480
481 err = bt_enable(NULL);
482 if (err != 0) {
483 FAIL("Bluetooth enable failed (err %d)\n", err);
484 return;
485 }
486
487 printk("Bluetooth initialized\n");
488 bap_stream_tx_init();
489
490 bt_gatt_cb_register(&gatt_callbacks);
491 err = bt_le_scan_cb_register(&scan_cb);
492 if (err != 0) {
493 FAIL("Failed to register scan callbacks (err %d)\n", err);
494 return;
495 }
496
497 err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
498 if (err != 0) {
499 FAIL("Failed to register BAP callbacks (err %d)\n", err);
500 return;
501 }
502
503 err = bt_cap_initiator_register_cb(&cap_cb);
504 if (err != 0) {
505 FAIL("Failed to register CAP callbacks (err %d)\n", err);
506 return;
507 }
508
509 for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) {
510 bt_cap_stream_ops_register(
511 cap_stream_from_audio_test_stream(&unicast_streams[i].stream), &stream_ops);
512 }
513
514 for (size_t i = 0; i < ARRAY_SIZE(broadcast_streams); i++) {
515 bt_cap_stream_ops_register(cap_stream_from_audio_test_stream(&broadcast_streams[i]),
516 &stream_ops);
517 }
518
519 err = bt_gmap_register(role, features);
520 if (err != 0) {
521 FAIL("Failed to register GMAS (err %d)\n", err);
522
523 return;
524 }
525
526 err = bt_gmap_cb_register(&gmap_cb);
527 if (err != 0) {
528 FAIL("Failed to register callbacks (err %d)\n", err);
529
530 return;
531 }
532 }
533
scan_and_connect(void)534 static void scan_and_connect(void)
535 {
536 int err;
537
538 UNSET_FLAG(flag_connected);
539
540 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
541 if (err != 0) {
542 FAIL("Scanning failed to start (err %d)\n", err);
543 return;
544 }
545
546 printk("Scanning successfully started\n");
547 WAIT_FOR_FLAG(flag_connected);
548 connected_conn_cnt++;
549 }
550
discover_sink(struct bt_conn * conn)551 static void discover_sink(struct bt_conn *conn)
552 {
553 int err;
554
555 UNSET_FLAG(flag_sink_discovered);
556
557 err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SINK);
558 if (err != 0) {
559 printk("Failed to discover sink: %d\n", err);
560 return;
561 }
562
563 WAIT_FOR_FLAG(flag_sink_discovered);
564 }
565
discover_source(struct bt_conn * conn)566 static void discover_source(struct bt_conn *conn)
567 {
568 int err;
569
570 UNSET_FLAG(flag_source_discovered);
571
572 err = bt_bap_unicast_client_discover(conn, BT_AUDIO_DIR_SOURCE);
573 if (err != 0) {
574 printk("Failed to discover source: %d\n", err);
575 return;
576 }
577
578 WAIT_FOR_FLAG(flag_source_discovered);
579 }
580
discover_gmas(struct bt_conn * conn)581 static void discover_gmas(struct bt_conn *conn)
582 {
583 int err;
584
585 UNSET_FLAG(flag_gmap_discovered);
586
587 err = bt_gmap_discover(conn);
588 if (err != 0) {
589 printk("Failed to discover GMAS: %d\n", err);
590 return;
591 }
592
593 WAIT_FOR_FLAG(flag_gmap_discovered);
594 }
595
discover_cas(struct bt_conn * conn)596 static void discover_cas(struct bt_conn *conn)
597 {
598 int err;
599
600 UNSET_FLAG(flag_cas_discovered);
601
602 err = bt_cap_initiator_unicast_discover(conn);
603 if (err != 0) {
604 printk("Failed to discover CAS: %d\n", err);
605 return;
606 }
607
608 WAIT_FOR_FLAG(flag_cas_discovered);
609 }
610
gmap_unicast_ac_create_unicast_group(const struct gmap_unicast_ac_param * param,struct unicast_stream * snk_uni_streams[],size_t snk_cnt,struct unicast_stream * src_uni_streams[],size_t src_cnt,struct bt_bap_unicast_group ** unicast_group)611 static int gmap_unicast_ac_create_unicast_group(const struct gmap_unicast_ac_param *param,
612 struct unicast_stream *snk_uni_streams[],
613 size_t snk_cnt,
614 struct unicast_stream *src_uni_streams[],
615 size_t src_cnt,
616 struct bt_bap_unicast_group **unicast_group)
617 {
618 struct bt_bap_unicast_group_stream_param
619 snk_group_stream_params[GMAP_UNICAST_AC_MAX_SNK] = {0};
620 struct bt_bap_unicast_group_stream_param
621 src_group_stream_params[GMAP_UNICAST_AC_MAX_SRC] = {0};
622 struct bt_bap_unicast_group_stream_pair_param pair_params[GMAP_UNICAST_AC_MAX_PAIR] = {0};
623 struct bt_bap_unicast_group_param group_param = {0};
624 size_t snk_stream_cnt = 0U;
625 size_t src_stream_cnt = 0U;
626 size_t pair_cnt = 0U;
627
628 /* Create Group
629 *
630 * First setup the individual stream parameters and then match them in pairs by connection
631 * and direction
632 */
633 for (size_t i = 0U; i < snk_cnt; i++) {
634 snk_group_stream_params[i].qos = &snk_uni_streams[i]->qos;
635 snk_group_stream_params[i].stream =
636 bap_stream_from_audio_test_stream(&snk_uni_streams[i]->stream);
637 }
638 for (size_t i = 0U; i < src_cnt; i++) {
639 src_group_stream_params[i].qos = &src_uni_streams[i]->qos;
640 src_group_stream_params[i].stream =
641 bap_stream_from_audio_test_stream(&src_uni_streams[i]->stream);
642 }
643
644 for (size_t i = 0U; i < param->conn_cnt; i++) {
645 for (size_t j = 0; j < MAX(param->snk_cnt[i], param->src_cnt[i]); j++) {
646 if (param->snk_cnt[i] > j) {
647 pair_params[pair_cnt].tx_param =
648 &snk_group_stream_params[snk_stream_cnt++];
649 } else {
650 pair_params[pair_cnt].tx_param = NULL;
651 }
652
653 if (param->src_cnt[i] > j) {
654 pair_params[pair_cnt].rx_param =
655 &src_group_stream_params[src_stream_cnt++];
656 } else {
657 pair_params[pair_cnt].rx_param = NULL;
658 }
659
660 pair_cnt++;
661 }
662 }
663
664 group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
665 group_param.params = pair_params;
666 group_param.params_count = pair_cnt;
667
668 return bt_bap_unicast_group_create(&group_param, unicast_group);
669 }
670
gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param * param,struct unicast_stream * snk_uni_streams[],size_t snk_cnt,struct unicast_stream * src_uni_streams[],size_t src_cnt,struct bt_bap_unicast_group * unicast_group)671 static int gmap_ac_cap_unicast_start(const struct gmap_unicast_ac_param *param,
672 struct unicast_stream *snk_uni_streams[], size_t snk_cnt,
673 struct unicast_stream *src_uni_streams[], size_t src_cnt,
674 struct bt_bap_unicast_group *unicast_group)
675 {
676 struct bt_cap_unicast_audio_start_stream_param stream_params[GMAP_UNICAST_AC_MAX_STREAM] = {
677 0};
678 struct bt_audio_codec_cfg *snk_codec_cfgs[GMAP_UNICAST_AC_MAX_SNK] = {0};
679 struct bt_audio_codec_cfg *src_codec_cfgs[GMAP_UNICAST_AC_MAX_SRC] = {0};
680 struct bt_cap_stream *snk_cap_streams[GMAP_UNICAST_AC_MAX_SNK] = {0};
681 struct bt_cap_stream *src_cap_streams[GMAP_UNICAST_AC_MAX_SRC] = {0};
682 struct bt_cap_unicast_audio_start_param start_param = {0};
683 struct bt_bap_ep *snk_eps[GMAP_UNICAST_AC_MAX_SNK] = {0};
684 struct bt_bap_ep *src_eps[GMAP_UNICAST_AC_MAX_SRC] = {0};
685 size_t snk_stream_cnt = 0U;
686 size_t src_stream_cnt = 0U;
687 size_t stream_cnt = 0U;
688 size_t snk_ep_cnt = 0U;
689 size_t src_ep_cnt = 0U;
690 int err;
691
692 for (size_t i = 0U; i < param->conn_cnt; i++) {
693 #if UNICAST_SINK_SUPPORTED
694 for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
695 snk_eps[snk_ep_cnt] = sink_eps[bt_conn_index(connected_conns[i])][j];
696 if (snk_eps[snk_ep_cnt] == NULL) {
697 FAIL("No sink[%zu][%zu] endpoint available\n", i, j);
698
699 return -ENODEV;
700 }
701 snk_ep_cnt++;
702 }
703 #endif /* UNICAST_SINK_SUPPORTED */
704
705 #if UNICAST_SRC_SUPPORTED
706 for (size_t j = 0U; j < param->src_cnt[i]; j++) {
707 src_eps[src_ep_cnt] = source_eps[bt_conn_index(connected_conns[i])][j];
708 if (src_eps[src_ep_cnt] == NULL) {
709 FAIL("No source[%zu][%zu] endpoint available\n", i, j);
710
711 return -ENODEV;
712 }
713 src_ep_cnt++;
714 }
715 #endif /* UNICAST_SRC_SUPPORTED > 0 */
716 }
717
718 if (snk_ep_cnt != snk_cnt) {
719 FAIL("Sink endpoint and stream count mismatch: %zu != %zu\n", snk_ep_cnt, snk_cnt);
720
721 return -EINVAL;
722 }
723
724 if (src_ep_cnt != src_cnt) {
725 FAIL("Source endpoint and stream count mismatch: %zu != %zu\n", src_ep_cnt,
726 src_cnt);
727
728 return -EINVAL;
729 }
730
731 /* Setup arrays of parameters based on the preset for easier access. This also copies the
732 * preset so that we can modify them (e.g. update the metadata)
733 */
734 for (size_t i = 0U; i < snk_cnt; i++) {
735 snk_cap_streams[i] = cap_stream_from_audio_test_stream(&snk_uni_streams[i]->stream);
736 snk_codec_cfgs[i] = &snk_uni_streams[i]->codec_cfg;
737 }
738
739 for (size_t i = 0U; i < src_cnt; i++) {
740 src_cap_streams[i] = cap_stream_from_audio_test_stream(&src_uni_streams[i]->stream);
741 src_codec_cfgs[i] = &src_uni_streams[i]->codec_cfg;
742 }
743
744 /* CAP Start */
745 for (size_t i = 0U; i < param->conn_cnt; i++) {
746 for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
747 struct bt_cap_unicast_audio_start_stream_param *stream_param =
748 &stream_params[stream_cnt];
749
750 stream_param->member.member = connected_conns[i];
751 stream_param->codec_cfg = snk_codec_cfgs[snk_stream_cnt];
752 stream_param->ep = snk_eps[snk_stream_cnt];
753 stream_param->stream = snk_cap_streams[snk_stream_cnt];
754
755 snk_stream_cnt++;
756 stream_cnt++;
757
758 /* If we have more than 1 connection or stream in one direction, we set the
759 * location bit accordingly
760 */
761 if (param->conn_cnt > 1U || param->snk_cnt[i] > 1U) {
762 const int err = bt_audio_codec_cfg_set_chan_allocation(
763 stream_param->codec_cfg, (enum bt_audio_location)BIT(i));
764
765 if (err < 0) {
766 FAIL("Failed to set channel allocation: %d\n", err);
767 return err;
768 }
769 }
770 }
771
772 for (size_t j = 0U; j < param->src_cnt[i]; j++) {
773 struct bt_cap_unicast_audio_start_stream_param *stream_param =
774 &stream_params[stream_cnt];
775
776 stream_param->member.member = connected_conns[i];
777 stream_param->codec_cfg = src_codec_cfgs[src_stream_cnt];
778 stream_param->ep = src_eps[src_stream_cnt];
779 stream_param->stream = src_cap_streams[src_stream_cnt];
780
781 src_stream_cnt++;
782 stream_cnt++;
783
784 /* If we have more than 1 connection or stream in one direction, we set the
785 * location bit accordingly
786 */
787 if (param->conn_cnt > 1U || param->src_cnt[i] > 1U) {
788 const int err = bt_audio_codec_cfg_set_chan_allocation(
789 stream_param->codec_cfg, (enum bt_audio_location)BIT(i));
790
791 if (err < 0) {
792 FAIL("Failed to set channel allocation: %d\n", err);
793 return err;
794 }
795 }
796 }
797 }
798
799 start_param.stream_params = stream_params;
800 start_param.count = stream_cnt;
801 start_param.type = BT_CAP_SET_TYPE_AD_HOC;
802
803 err = bt_cap_initiator_unicast_audio_start(&start_param);
804 if (err == 0) {
805 for (size_t i = 0U; i < start_param.count; i++) {
806 started_unicast_streams[i] = start_param.stream_params[i].stream;
807 }
808
809 started_unicast_streams_cnt = start_param.count;
810 }
811
812 return err;
813 }
814
gmap_ac_unicast(const struct gmap_unicast_ac_param * param,struct bt_bap_unicast_group ** unicast_group)815 static int gmap_ac_unicast(const struct gmap_unicast_ac_param *param,
816 struct bt_bap_unicast_group **unicast_group)
817 {
818 /* Allocate params large enough for any params, but only use what is required */
819 struct unicast_stream *snk_uni_streams[GMAP_UNICAST_AC_MAX_SNK];
820 struct unicast_stream *src_uni_streams[GMAP_UNICAST_AC_MAX_SRC];
821 size_t snk_cnt = 0;
822 size_t src_cnt = 0;
823 int err;
824
825 if (param->conn_cnt > GMAP_UNICAST_AC_MAX_CONN) {
826 FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt);
827
828 return -EINVAL;
829 }
830
831 for (size_t i = 0; i < param->conn_cnt; i++) {
832 /* Verify conn values */
833 if (param->snk_cnt[i] > GMAP_UNICAST_AC_MAX_SNK) {
834 FAIL("Invalid conn_snk_cnt[%zu]: %zu\n", i, param->snk_cnt[i]);
835
836 return -EINVAL;
837 }
838
839 if (param->src_cnt[i] > GMAP_UNICAST_AC_MAX_SRC) {
840 FAIL("Invalid conn_src_cnt[%zu]: %zu\n", i, param->src_cnt[i]);
841
842 return -EINVAL;
843 }
844 }
845
846 /* Get total count of sink and source streams to setup */
847 for (size_t i = 0U; i < param->conn_cnt; i++) {
848 for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
849 snk_cnt++;
850 }
851
852 for (size_t j = 0U; j < param->src_cnt[i]; j++) {
853 src_cnt++;
854 }
855 }
856
857 /* Setup arrays of parameters based on the preset for easier access. This also copies the
858 * preset so that we can modify them (e.g. update the metadata)
859 */
860 for (size_t i = 0U; i < snk_cnt; i++) {
861 snk_uni_streams[i] = &unicast_streams[i];
862
863 copy_unicast_stream_preset(snk_uni_streams[i], param->snk_named_preset);
864
865 /* Some audio configuration requires multiple sink channels,
866 * so multiply the SDU based on the channel count
867 */
868 snk_uni_streams[i]->qos.sdu *= param->snk_chan_cnt;
869 }
870
871 for (size_t i = 0U; i < src_cnt; i++) {
872 src_uni_streams[i] = &unicast_streams[i + snk_cnt];
873 copy_unicast_stream_preset(src_uni_streams[i], param->src_named_preset);
874 }
875
876 err = gmap_unicast_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams,
877 src_cnt, unicast_group);
878 if (err != 0) {
879 FAIL("Failed to create group: %d\n", err);
880
881 return err;
882 }
883
884 UNSET_FLAG(flag_started);
885
886 printk("Starting %zu streams for %s\n", snk_cnt + src_cnt, param->name);
887 err = gmap_ac_cap_unicast_start(param, snk_uni_streams, snk_cnt, src_uni_streams, src_cnt,
888 *unicast_group);
889 if (err != 0) {
890 FAIL("Failed to start unicast audio: %d\n\n", err);
891
892 return err;
893 }
894
895 WAIT_FOR_FLAG(flag_started);
896
897 /* let other devices know we have started what we wanted */
898 backchannel_sync_send_all();
899
900 return 0;
901 }
902
unicast_audio_stop(struct bt_bap_unicast_group * unicast_group)903 static void unicast_audio_stop(struct bt_bap_unicast_group *unicast_group)
904 {
905 struct bt_cap_unicast_audio_stop_param param;
906 int err;
907
908 UNSET_FLAG(flag_stopped);
909
910 param.type = BT_CAP_SET_TYPE_AD_HOC;
911 param.count = started_unicast_streams_cnt;
912 param.streams = started_unicast_streams;
913 param.release = true;
914
915 err = bt_cap_initiator_unicast_audio_stop(¶m);
916 if (err != 0) {
917 FAIL("Failed to start unicast audio: %d\n", err);
918 return;
919 }
920
921 WAIT_FOR_FLAG(flag_stopped);
922
923 started_unicast_streams_cnt = 0U;
924 memset(started_unicast_streams, 0, sizeof(started_unicast_streams));
925 }
926
unicast_group_delete(struct bt_bap_unicast_group * unicast_group)927 static void unicast_group_delete(struct bt_bap_unicast_group *unicast_group)
928 {
929 int err;
930
931 err = bt_bap_unicast_group_delete(unicast_group);
932 if (err != 0) {
933 FAIL("Failed to create group: %d\n", err);
934 return;
935 }
936 }
937
test_gmap_ugg_unicast_ac(const struct gmap_unicast_ac_param * param)938 static void test_gmap_ugg_unicast_ac(const struct gmap_unicast_ac_param *param)
939 {
940 struct bt_bap_unicast_group *unicast_group;
941 bool expect_tx = false;
942 bool expect_rx = false;
943
944 printk("Running test for %s with Sink Preset %s and Source Preset %s\n", param->name,
945 param->snk_named_preset != NULL ? param->snk_named_preset->name : "None",
946 param->src_named_preset != NULL ? param->src_named_preset->name : "None");
947
948 if (param->conn_cnt > GMAP_UNICAST_AC_MAX_CONN) {
949 FAIL("Invalid conn_cnt: %zu\n", param->conn_cnt);
950 return;
951 }
952
953 init();
954
955 for (size_t i = 0U; i < param->conn_cnt; i++) {
956 UNSET_FLAG(flag_mtu_exchanged);
957
958 scan_and_connect();
959
960 WAIT_FOR_FLAG(flag_mtu_exchanged);
961
962 printk("Connected %zu/%zu\n", i + 1, param->conn_cnt);
963 }
964
965 if (connected_conn_cnt < param->conn_cnt) {
966 FAIL("Only %zu/%u connected devices, please connect additional devices for this "
967 "audio configuration\n",
968 connected_conn_cnt, param->conn_cnt);
969 return;
970 }
971
972 for (size_t i = 0U; i < param->conn_cnt; i++) {
973 discover_cas(connected_conns[i]);
974
975 if (param->snk_cnt[i] > 0U) {
976 discover_sink(connected_conns[i]);
977 expect_tx = true;
978 }
979
980 if (param->src_cnt[i] > 0U) {
981 discover_source(connected_conns[i]);
982 expect_rx = true;
983 }
984
985 discover_gmas(connected_conns[i]);
986 discover_gmas(connected_conns[i]); /* test that we can discover twice */
987 }
988
989 gmap_ac_unicast(param, &unicast_group);
990
991 if (expect_tx) {
992 /* Wait until acceptors have received expected data */
993 backchannel_sync_wait_all();
994 }
995
996 if (expect_rx) {
997 printk("Waiting for data\n");
998 WAIT_FOR_FLAG(flag_audio_received);
999 }
1000
1001 unicast_audio_stop(unicast_group);
1002
1003 unicast_group_delete(unicast_group);
1004 unicast_group = NULL;
1005
1006 for (size_t i = 0U; i < param->conn_cnt; i++) {
1007 const int err =
1008 bt_conn_disconnect(connected_conns[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
1009
1010 if (err != 0) {
1011 FAIL("Failed to disconnect conn[%zu]: %d\n", i, err);
1012 }
1013
1014 bt_conn_unref(connected_conns[i]);
1015 connected_conns[i] = NULL;
1016 }
1017
1018 PASS("GMAP UGG passed for %s with Sink Preset %s and Source Preset %s\n", param->name,
1019 param->snk_named_preset != NULL ? param->snk_named_preset->name : "None",
1020 param->src_named_preset != NULL ? param->src_named_preset->name : "None");
1021 }
1022
setup_extended_adv_data(struct bt_cap_broadcast_source * source,struct bt_le_ext_adv * adv)1023 static void setup_extended_adv_data(struct bt_cap_broadcast_source *source,
1024 struct bt_le_ext_adv *adv)
1025 {
1026 /* Broadcast Audio Streaming Endpoint advertising data */
1027 NET_BUF_SIMPLE_DEFINE(ad_buf, BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE);
1028 NET_BUF_SIMPLE_DEFINE(base_buf, 128);
1029 struct bt_data ext_ad;
1030 struct bt_data per_ad;
1031 uint32_t broadcast_id;
1032 int err;
1033
1034 err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
1035 if (err) {
1036 FAIL("Unable to generate broadcast ID: %d\n", err);
1037 return;
1038 }
1039
1040 /* Setup extended advertising data */
1041 net_buf_simple_add_le16(&ad_buf, BT_UUID_BROADCAST_AUDIO_VAL);
1042 net_buf_simple_add_le24(&ad_buf, broadcast_id);
1043 ext_ad.type = BT_DATA_SVC_DATA16;
1044 ext_ad.data_len = ad_buf.len;
1045 ext_ad.data = ad_buf.data;
1046 err = bt_le_ext_adv_set_data(adv, &ext_ad, 1, NULL, 0);
1047 if (err != 0) {
1048 FAIL("Failed to set extended advertising data: %d\n", err);
1049 return;
1050 }
1051
1052 /* Setup periodic advertising data */
1053 err = bt_cap_initiator_broadcast_get_base(source, &base_buf);
1054 if (err != 0) {
1055 FAIL("Failed to get encoded BASE: %d\n", err);
1056 return;
1057 }
1058
1059 per_ad.type = BT_DATA_SVC_DATA16;
1060 per_ad.data_len = base_buf.len;
1061 per_ad.data = base_buf.data;
1062 err = bt_le_per_adv_set_data(adv, &per_ad, 1);
1063 if (err != 0) {
1064 FAIL("Failed to set periodic advertising data: %d\n", err);
1065 return;
1066 }
1067 }
1068
start_extended_adv(struct bt_le_ext_adv * adv)1069 static void start_extended_adv(struct bt_le_ext_adv *adv)
1070 {
1071 int err;
1072
1073 /* Start extended advertising */
1074 err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
1075 if (err) {
1076 FAIL("Failed to start extended advertising: %d\n", err);
1077 return;
1078 }
1079
1080 /* Enable Periodic Advertising */
1081 err = bt_le_per_adv_start(adv);
1082 if (err) {
1083 FAIL("Failed to enable periodic advertising: %d\n", err);
1084 return;
1085 }
1086 }
1087
stop_and_delete_extended_adv(struct bt_le_ext_adv * adv)1088 static void stop_and_delete_extended_adv(struct bt_le_ext_adv *adv)
1089 {
1090 int err;
1091
1092 /* Stop extended advertising */
1093 err = bt_le_per_adv_stop(adv);
1094 if (err) {
1095 FAIL("Failed to stop periodic advertising: %d\n", err);
1096 return;
1097 }
1098
1099 err = bt_le_ext_adv_stop(adv);
1100 if (err) {
1101 FAIL("Failed to stop extended advertising: %d\n", err);
1102 return;
1103 }
1104
1105 err = bt_le_ext_adv_delete(adv);
1106 if (err) {
1107 FAIL("Failed to delete extended advertising: %d\n", err);
1108 return;
1109 }
1110 }
1111
broadcast_audio_start(struct bt_cap_broadcast_source * broadcast_source,struct bt_le_ext_adv * adv)1112 static void broadcast_audio_start(struct bt_cap_broadcast_source *broadcast_source,
1113 struct bt_le_ext_adv *adv)
1114 {
1115 int err;
1116
1117 err = bt_cap_initiator_broadcast_audio_start(broadcast_source, adv);
1118 if (err != 0) {
1119 FAIL("Unable to start broadcast source: %d\n", err);
1120 return;
1121 }
1122
1123 printk("Broadcast source created\n");
1124 }
1125
broadcast_audio_stop(struct bt_cap_broadcast_source * broadcast_source,size_t stream_count)1126 static void broadcast_audio_stop(struct bt_cap_broadcast_source *broadcast_source,
1127 size_t stream_count)
1128 {
1129 int err;
1130
1131 printk("Stopping broadcast source\n");
1132
1133 err = bt_cap_initiator_broadcast_audio_stop(broadcast_source);
1134 if (err != 0) {
1135 FAIL("Failed to stop broadcast source: %d\n", err);
1136 return;
1137 }
1138
1139 /* Wait for all to be stopped */
1140 printk("Waiting for broadcast_streams to be stopped\n");
1141 for (size_t i = 0U; i < stream_count; i++) {
1142 k_sem_take(&sem_stream_stopped, K_FOREVER);
1143 }
1144
1145 printk("Broadcast source stopped\n");
1146 }
1147
broadcast_audio_delete(struct bt_cap_broadcast_source * broadcast_source)1148 static void broadcast_audio_delete(struct bt_cap_broadcast_source *broadcast_source)
1149 {
1150 int err;
1151
1152 printk("Deleting broadcast source\n");
1153
1154 err = bt_cap_initiator_broadcast_audio_delete(broadcast_source);
1155 if (err != 0) {
1156 FAIL("Failed to stop broadcast source: %d\n", err);
1157 return;
1158 }
1159
1160 printk("Broadcast source deleted\n");
1161 }
1162
test_gmap_ugg_broadcast_ac(const struct gmap_broadcast_ac_param * param)1163 static int test_gmap_ugg_broadcast_ac(const struct gmap_broadcast_ac_param *param)
1164 {
1165 uint8_t stereo_data[] = {
1166 BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1167 BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)};
1168 uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1169 BT_AUDIO_LOCATION_FRONT_RIGHT)};
1170 uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1171 BT_AUDIO_LOCATION_FRONT_LEFT)};
1172 struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0};
1173 struct bt_cap_initiator_broadcast_create_param create_param = {0};
1174 struct bt_cap_initiator_broadcast_stream_param
1175 stream_params[GMAP_BROADCAST_AC_MAX_STREAM] = {0};
1176 struct bt_cap_broadcast_source *broadcast_source;
1177 struct bt_audio_codec_cfg codec_cfg;
1178 struct bt_bap_qos_cfg qos;
1179 struct bt_le_ext_adv *adv;
1180 int err;
1181
1182 for (size_t i = 0U; i < param->stream_cnt; i++) {
1183 stream_params[i].stream = cap_stream_from_audio_test_stream(&broadcast_streams[i]);
1184
1185 if (param->stream_cnt == 1U) {
1186 stream_params[i].data_len = ARRAY_SIZE(stereo_data);
1187 stream_params[i].data = stereo_data;
1188 } else if (i == 0U) {
1189 stream_params[i].data_len = ARRAY_SIZE(left_data);
1190 stream_params[i].data = left_data;
1191 } else if (i == 1U) {
1192 stream_params[i].data_len = ARRAY_SIZE(right_data);
1193 stream_params[i].data = right_data;
1194 }
1195 }
1196
1197 memcpy(&codec_cfg, &broadcast_named_preset->preset.codec_cfg, sizeof(codec_cfg));
1198 memcpy(&qos, &broadcast_named_preset->preset.qos, sizeof(qos));
1199 qos.sdu *= param->chan_cnt;
1200
1201 subgroup_param.stream_count = param->stream_cnt;
1202 subgroup_param.stream_params = stream_params;
1203 subgroup_param.codec_cfg = &codec_cfg;
1204 create_param.subgroup_count = 1U;
1205 create_param.subgroup_params = &subgroup_param;
1206 create_param.qos = &qos;
1207
1208 init();
1209 setup_broadcast_adv(&adv);
1210
1211 err = bt_cap_initiator_broadcast_audio_create(&create_param, &broadcast_source);
1212 if (err != 0) {
1213 FAIL("Failed to create broadcast source: %d\n", err);
1214 return -ENOEXEC;
1215 }
1216
1217 for (size_t i = 0U; i < param->stream_cnt; i++) {
1218 struct audio_test_stream *test_stream = &broadcast_streams[i];
1219
1220 test_stream->tx_sdu_size = create_param.qos->sdu;
1221 }
1222
1223 broadcast_audio_start(broadcast_source, adv);
1224 setup_extended_adv_data(broadcast_source, adv);
1225 start_extended_adv(adv);
1226
1227 /* Wait for all to be started */
1228 printk("Waiting for broadcast_streams to be started\n");
1229 for (size_t i = 0U; i < param->stream_cnt; i++) {
1230 k_sem_take(&sem_stream_started, K_FOREVER);
1231 }
1232
1233 /* Wait for other devices to have received what they wanted */
1234 backchannel_sync_wait_any();
1235
1236 broadcast_audio_stop(broadcast_source, param->stream_cnt);
1237
1238 broadcast_audio_delete(broadcast_source);
1239 broadcast_source = NULL;
1240
1241 stop_and_delete_extended_adv(adv);
1242 adv = NULL;
1243
1244 PASS("CAP initiator broadcast passed\n");
1245
1246 return 0;
1247 }
1248
test_gmap_ac_1(void)1249 static void test_gmap_ac_1(void)
1250 {
1251 const struct gmap_unicast_ac_param param = {
1252 .name = "ac_1",
1253 .conn_cnt = 1U,
1254 .snk_cnt = {1U},
1255 .src_cnt = {0U},
1256 .snk_chan_cnt = 1U,
1257 .snk_named_preset = snk_named_preset,
1258 .src_named_preset = NULL,
1259 };
1260
1261 test_gmap_ugg_unicast_ac(¶m);
1262 }
1263
test_gmap_ac_2(void)1264 static void test_gmap_ac_2(void)
1265 {
1266 const struct gmap_unicast_ac_param param = {
1267 .name = "ac_2",
1268 .conn_cnt = 1U,
1269 .snk_cnt = {0U},
1270 .src_cnt = {1U},
1271 .snk_chan_cnt = 1U,
1272 .snk_named_preset = NULL,
1273 .src_named_preset = src_named_preset,
1274 };
1275
1276 test_gmap_ugg_unicast_ac(¶m);
1277 }
1278
test_gmap_ac_3(void)1279 static void test_gmap_ac_3(void)
1280 {
1281 const struct gmap_unicast_ac_param param = {
1282 .name = "ac_3",
1283 .conn_cnt = 1U,
1284 .snk_cnt = {1U},
1285 .src_cnt = {1U},
1286 .snk_chan_cnt = 1U,
1287 .snk_named_preset = snk_named_preset,
1288 .src_named_preset = src_named_preset,
1289 };
1290
1291 test_gmap_ugg_unicast_ac(¶m);
1292 }
1293
test_gmap_ac_4(void)1294 static void test_gmap_ac_4(void)
1295 {
1296 const struct gmap_unicast_ac_param param = {
1297 .name = "ac_4",
1298 .conn_cnt = 1U,
1299 .snk_cnt = {1U},
1300 .src_cnt = {0U},
1301 .snk_chan_cnt = 2U,
1302 .snk_named_preset = snk_named_preset,
1303 .src_named_preset = NULL,
1304 };
1305
1306 test_gmap_ugg_unicast_ac(¶m);
1307 }
1308
test_gmap_ac_5(void)1309 static void test_gmap_ac_5(void)
1310 {
1311 const struct gmap_unicast_ac_param param = {
1312 .name = "ac_5",
1313 .conn_cnt = 1U,
1314 .snk_cnt = {1U},
1315 .src_cnt = {1U},
1316 .snk_chan_cnt = 2U,
1317 .snk_named_preset = snk_named_preset,
1318 .src_named_preset = src_named_preset,
1319 };
1320
1321 test_gmap_ugg_unicast_ac(¶m);
1322 }
1323
test_gmap_ac_6_i(void)1324 static void test_gmap_ac_6_i(void)
1325 {
1326 const struct gmap_unicast_ac_param param = {
1327 .name = "ac_6_i",
1328 .conn_cnt = 1U,
1329 .snk_cnt = {2U},
1330 .src_cnt = {0U},
1331 .snk_chan_cnt = 1U,
1332 .snk_named_preset = snk_named_preset,
1333 .src_named_preset = NULL,
1334 };
1335
1336 test_gmap_ugg_unicast_ac(¶m);
1337 }
1338
test_gmap_ac_6_ii(void)1339 static void test_gmap_ac_6_ii(void)
1340 {
1341 const struct gmap_unicast_ac_param param = {
1342 .name = "ac_6_ii",
1343 .conn_cnt = 2U,
1344 .snk_cnt = {1U, 1U},
1345 .src_cnt = {0U, 0U},
1346 .snk_chan_cnt = 1U,
1347 .snk_named_preset = snk_named_preset,
1348 .src_named_preset = NULL,
1349 };
1350
1351 test_gmap_ugg_unicast_ac(¶m);
1352 }
1353
test_gmap_ac_7_ii(void)1354 static void test_gmap_ac_7_ii(void)
1355 {
1356 const struct gmap_unicast_ac_param param = {
1357 .name = "ac_7_ii",
1358 .conn_cnt = 2U,
1359 .snk_cnt = {1U, 0U},
1360 .src_cnt = {0U, 1U},
1361 .snk_chan_cnt = 1U,
1362 .snk_named_preset = snk_named_preset,
1363 .src_named_preset = src_named_preset,
1364 };
1365
1366 test_gmap_ugg_unicast_ac(¶m);
1367 }
1368
test_gmap_ac_8_i(void)1369 static void test_gmap_ac_8_i(void)
1370 {
1371 const struct gmap_unicast_ac_param param = {
1372 .name = "ac_8_i",
1373 .conn_cnt = 1U,
1374 .snk_cnt = {2U},
1375 .src_cnt = {1U},
1376 .snk_chan_cnt = 1U,
1377 .snk_named_preset = snk_named_preset,
1378 .src_named_preset = src_named_preset,
1379 };
1380
1381 test_gmap_ugg_unicast_ac(¶m);
1382 }
1383
test_gmap_ac_8_ii(void)1384 static void test_gmap_ac_8_ii(void)
1385 {
1386 const struct gmap_unicast_ac_param param = {
1387 .name = "ac_8_ii",
1388 .conn_cnt = 2U,
1389 .snk_cnt = {1U, 1U},
1390 .src_cnt = {1U, 0U},
1391 .snk_chan_cnt = 1U,
1392 .snk_named_preset = snk_named_preset,
1393 .src_named_preset = src_named_preset,
1394 };
1395
1396 test_gmap_ugg_unicast_ac(¶m);
1397 }
1398
test_gmap_ac_11_i(void)1399 static void test_gmap_ac_11_i(void)
1400 {
1401 const struct gmap_unicast_ac_param param = {
1402 .name = "ac_11_i",
1403 .conn_cnt = 1U,
1404 .snk_cnt = {2U},
1405 .src_cnt = {2U},
1406 .snk_chan_cnt = 1U,
1407 .snk_named_preset = snk_named_preset,
1408 .src_named_preset = src_named_preset,
1409 };
1410
1411 test_gmap_ugg_unicast_ac(¶m);
1412 }
1413
test_gmap_ac_11_ii(void)1414 static void test_gmap_ac_11_ii(void)
1415 {
1416 const struct gmap_unicast_ac_param param = {
1417 .name = "ac_11_ii",
1418 .conn_cnt = 2U,
1419 .snk_cnt = {1U, 1U},
1420 .src_cnt = {1U, 1U},
1421 .snk_chan_cnt = 1U,
1422 .snk_named_preset = snk_named_preset,
1423 .src_named_preset = src_named_preset,
1424 };
1425
1426 test_gmap_ugg_unicast_ac(¶m);
1427 }
1428
test_gmap_ac_12(void)1429 static void test_gmap_ac_12(void)
1430 {
1431 const struct gmap_broadcast_ac_param param = {
1432 .name = "ac_12",
1433 .stream_cnt = 1U,
1434 .chan_cnt = 1U,
1435 .named_preset = broadcast_named_preset,
1436 };
1437
1438 test_gmap_ugg_broadcast_ac(¶m);
1439 }
1440
1441 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM
test_gmap_ac_13(void)1442 static void test_gmap_ac_13(void)
1443 {
1444 const struct gmap_broadcast_ac_param param = {
1445 .name = "ac_13",
1446 .stream_cnt = 2U,
1447 .chan_cnt = 1U,
1448 .named_preset = broadcast_named_preset,
1449 };
1450
1451 test_gmap_ugg_broadcast_ac(¶m);
1452 }
1453 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM */
1454
test_gmap_ac_14(void)1455 static void test_gmap_ac_14(void)
1456 {
1457 const struct gmap_broadcast_ac_param param = {
1458 .name = "ac_14",
1459 .stream_cnt = 1U,
1460 .chan_cnt = 2U,
1461 .named_preset = broadcast_named_preset,
1462 };
1463
1464 test_gmap_ugg_broadcast_ac(¶m);
1465 }
1466
test_args(int argc,char * argv[])1467 static void test_args(int argc, char *argv[])
1468 {
1469 for (size_t argn = 0; argn < argc; argn++) {
1470 const char *arg = argv[argn];
1471
1472 if (strcmp(arg, "sink_preset") == 0) {
1473 const char *preset_arg = argv[++argn];
1474
1475 snk_named_preset =
1476 gmap_get_named_preset(true, BT_AUDIO_DIR_SINK, preset_arg);
1477 if (snk_named_preset == NULL) {
1478 FAIL("Failed to get sink preset from %s\n", preset_arg);
1479 }
1480 } else if (strcmp(arg, "source_preset") == 0) {
1481 const char *preset_arg = argv[++argn];
1482
1483 src_named_preset =
1484 gmap_get_named_preset(true, BT_AUDIO_DIR_SOURCE, preset_arg);
1485 if (src_named_preset == NULL) {
1486 FAIL("Failed to get source preset from %s\n", preset_arg);
1487 }
1488 } else if (strcmp(arg, "broadcast_preset") == 0) {
1489 const char *preset_arg = argv[++argn];
1490
1491 broadcast_named_preset = gmap_get_named_preset(
1492 false, BT_AUDIO_DIR_SINK /* unused */, preset_arg);
1493 if (broadcast_named_preset == NULL) {
1494 FAIL("Failed to get broadcast preset from %s\n", preset_arg);
1495 }
1496 } else {
1497 FAIL("Invalid arg: %s\n", arg);
1498 }
1499 }
1500 }
1501
1502 static const struct bst_test_instance test_gmap_ugg[] = {
1503 {
1504 .test_id = "gmap_ugg_ac_1",
1505 .test_pre_init_f = test_init,
1506 .test_tick_f = test_tick,
1507 .test_main_f = test_gmap_ac_1,
1508 .test_args_f = test_args,
1509 },
1510 {
1511 .test_id = "gmap_ugg_ac_2",
1512 .test_pre_init_f = test_init,
1513 .test_tick_f = test_tick,
1514 .test_main_f = test_gmap_ac_2,
1515 .test_args_f = test_args,
1516 },
1517 {
1518 .test_id = "gmap_ugg_ac_3",
1519 .test_pre_init_f = test_init,
1520 .test_tick_f = test_tick,
1521 .test_main_f = test_gmap_ac_3,
1522 .test_args_f = test_args,
1523 },
1524 {
1525 .test_id = "gmap_ugg_ac_4",
1526 .test_pre_init_f = test_init,
1527 .test_tick_f = test_tick,
1528 .test_main_f = test_gmap_ac_4,
1529 .test_args_f = test_args,
1530 },
1531 {
1532 .test_id = "gmap_ugg_ac_5",
1533 .test_pre_init_f = test_init,
1534 .test_tick_f = test_tick,
1535 .test_main_f = test_gmap_ac_5,
1536 .test_args_f = test_args,
1537 },
1538 {
1539 .test_id = "gmap_ugg_ac_6_i",
1540 .test_pre_init_f = test_init,
1541 .test_tick_f = test_tick,
1542 .test_main_f = test_gmap_ac_6_i,
1543 .test_args_f = test_args,
1544 },
1545 {
1546 .test_id = "gmap_ugg_ac_6_ii",
1547 .test_pre_init_f = test_init,
1548 .test_tick_f = test_tick,
1549 .test_main_f = test_gmap_ac_6_ii,
1550 .test_args_f = test_args,
1551 },
1552 {
1553 .test_id = "gmap_ugg_ac_7_ii",
1554 .test_pre_init_f = test_init,
1555 .test_tick_f = test_tick,
1556 .test_main_f = test_gmap_ac_7_ii,
1557 .test_args_f = test_args,
1558 },
1559 {
1560 .test_id = "gmap_ugg_ac_8_i",
1561 .test_pre_init_f = test_init,
1562 .test_tick_f = test_tick,
1563 .test_main_f = test_gmap_ac_8_i,
1564 .test_args_f = test_args,
1565 },
1566 {
1567 .test_id = "gmap_ugg_ac_8_ii",
1568 .test_pre_init_f = test_init,
1569 .test_tick_f = test_tick,
1570 .test_main_f = test_gmap_ac_8_ii,
1571 .test_args_f = test_args,
1572 },
1573 {
1574 .test_id = "gmap_ugg_ac_11_i",
1575 .test_pre_init_f = test_init,
1576 .test_tick_f = test_tick,
1577 .test_main_f = test_gmap_ac_11_i,
1578 .test_args_f = test_args,
1579 },
1580 {
1581 .test_id = "gmap_ugg_ac_11_ii",
1582 .test_pre_init_f = test_init,
1583 .test_tick_f = test_tick,
1584 .test_main_f = test_gmap_ac_11_ii,
1585 .test_args_f = test_args,
1586 },
1587 {
1588 .test_id = "gmap_ugg_ac_12",
1589 .test_pre_init_f = test_init,
1590 .test_tick_f = test_tick,
1591 .test_main_f = test_gmap_ac_12,
1592 .test_args_f = test_args,
1593 },
1594 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM
1595 {
1596 .test_id = "gmap_ugg_ac_13",
1597 .test_pre_init_f = test_init,
1598 .test_tick_f = test_tick,
1599 .test_main_f = test_gmap_ac_13,
1600 .test_args_f = test_args,
1601 },
1602 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT >= GMAP_BROADCAST_AC_MAX_STREAM */
1603 {
1604 .test_id = "gmap_ugg_ac_14",
1605 .test_pre_init_f = test_init,
1606 .test_tick_f = test_tick,
1607 .test_main_f = test_gmap_ac_14,
1608 .test_args_f = test_args,
1609 },
1610 BSTEST_END_MARKER,
1611 };
1612
test_gmap_ugg_install(struct bst_test_list * tests)1613 struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests)
1614 {
1615 return bst_add_tests(tests, test_gmap_ugg);
1616 }
1617
1618 #else /* !(CONFIG_BT_GMAP) */
1619
test_gmap_ugg_install(struct bst_test_list * tests)1620 struct bst_test_list *test_gmap_ugg_install(struct bst_test_list *tests)
1621 {
1622 return tests;
1623 }
1624
1625 #endif /* CONFIG_BT_GMAP */
1626