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