1 /*
2 * Copyright (c) 2021-2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <zephyr/autoconf.h>
13 #include <zephyr/bluetooth/addr.h>
14 #include <zephyr/bluetooth/audio/audio.h>
15 #include <zephyr/bluetooth/audio/bap.h>
16 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
17 #include <zephyr/bluetooth/audio/pacs.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/gap.h>
21 #include <zephyr/bluetooth/gatt.h>
22 #include <zephyr/bluetooth/hci_types.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/kernel.h>
26 #include <zephyr/net_buf.h>
27 #include <zephyr/sys/atomic.h>
28 #include <zephyr/sys/atomic_types.h>
29 #include <zephyr/sys/printk.h>
30 #include <zephyr/sys/util.h>
31
32 #include "bap_stream_rx.h"
33 #include "bap_stream_tx.h"
34 #include "bstests.h"
35 #include "common.h"
36 #include "bap_common.h"
37
38 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
39
40 extern enum bst_result_t bst_result;
41
42 static struct audio_test_stream test_streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
43 static struct bt_bap_ep *g_sinks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
44 static struct bt_bap_ep *g_sources[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
45
46 static struct bt_bap_unicast_group_stream_pair_param pair_params[ARRAY_SIZE(test_streams)];
47 static struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(test_streams)];
48
49 /*Mandatory support preset by both client and server */
50 static struct bt_bap_lc3_preset preset_16_2_1 = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
51 BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
52
53 CREATE_FLAG(flag_mtu_exchanged);
54 CREATE_FLAG(flag_sink_discovered);
55 CREATE_FLAG(flag_source_discovered);
56 CREATE_FLAG(flag_codec_cap_found);
57 CREATE_FLAG(flag_endpoint_found);
58 CREATE_FLAG(flag_stream_codec_configured);
59 static atomic_t flag_stream_qos_configured;
60 CREATE_FLAG(flag_stream_enabled);
61 CREATE_FLAG(flag_stream_metadata);
62 CREATE_FLAG(flag_stream_started);
63 CREATE_FLAG(flag_stream_connected);
64 CREATE_FLAG(flag_stream_disconnected);
65 CREATE_FLAG(flag_stream_disabled);
66 CREATE_FLAG(flag_stream_stopped);
67 CREATE_FLAG(flag_stream_released);
68 CREATE_FLAG(flag_operation_success);
69
stream_configured(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg_pref * pref)70 static void stream_configured(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg_pref *pref)
71 {
72 printk("Configured stream %p\n", stream);
73
74 /* TODO: The preference should be used/taken into account when
75 * setting the QoS
76 */
77
78 SET_FLAG(flag_stream_codec_configured);
79 }
80
stream_qos_set(struct bt_bap_stream * stream)81 static void stream_qos_set(struct bt_bap_stream *stream)
82 {
83 struct audio_test_stream *test_stream = audio_test_stream_from_bap_stream(stream);
84
85 printk("QoS set stream %p\n", stream);
86
87 test_stream->tx_sdu_size = stream->qos->sdu;
88
89 atomic_inc(&flag_stream_qos_configured);
90 }
91
stream_enabled(struct bt_bap_stream * stream)92 static void stream_enabled(struct bt_bap_stream *stream)
93 {
94 printk("Enabled stream %p\n", stream);
95
96 SET_FLAG(flag_stream_enabled);
97 }
98
stream_started(struct bt_bap_stream * stream)99 static void stream_started(struct bt_bap_stream *stream)
100 {
101 printk("Started stream %p\n", stream);
102
103 if (bap_stream_tx_can_send(stream)) {
104 int err;
105
106 err = bap_stream_tx_register(stream);
107 if (err != 0) {
108 FAIL("Failed to register stream %p for TX: %d\n", stream, err);
109 return;
110 }
111 }
112
113 SET_FLAG(flag_stream_started);
114 }
115
stream_connected(struct bt_bap_stream * stream)116 static void stream_connected(struct bt_bap_stream *stream)
117 {
118 printk("Connected stream %p\n", stream);
119
120 SET_FLAG(flag_stream_connected);
121 }
122
stream_disconnected(struct bt_bap_stream * stream,uint8_t reason)123 static void stream_disconnected(struct bt_bap_stream *stream, uint8_t reason)
124 {
125 printk("Disconnected stream %p with reason %u\n", stream, reason);
126
127 SET_FLAG(flag_stream_disconnected);
128 }
129
stream_metadata_updated(struct bt_bap_stream * stream)130 static void stream_metadata_updated(struct bt_bap_stream *stream)
131 {
132 printk("Metadata updated stream %p\n", stream);
133
134 SET_FLAG(flag_stream_metadata);
135 }
136
stream_disabled(struct bt_bap_stream * stream)137 static void stream_disabled(struct bt_bap_stream *stream)
138 {
139 printk("Disabled stream %p\n", stream);
140
141 SET_FLAG(flag_stream_disabled);
142 }
143
stream_stopped(struct bt_bap_stream * stream,uint8_t reason)144 static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
145 {
146 printk("Stopped stream %p with reason 0x%02X\n", stream, reason);
147
148 if (bap_stream_tx_can_send(stream)) {
149 int err;
150
151 err = bap_stream_tx_unregister(stream);
152 if (err != 0) {
153 FAIL("Failed to unregister stream %p for TX: %d\n", stream, err);
154 return;
155 }
156 }
157
158 SET_FLAG(flag_stream_stopped);
159 }
160
stream_released(struct bt_bap_stream * stream)161 static void stream_released(struct bt_bap_stream *stream)
162 {
163 printk("Released stream %p\n", stream);
164
165 SET_FLAG(flag_stream_released);
166 }
167
168 static struct bt_bap_stream_ops stream_ops = {
169 .configured = stream_configured,
170 .qos_set = stream_qos_set,
171 .enabled = stream_enabled,
172 .started = stream_started,
173 .metadata_updated = stream_metadata_updated,
174 .disabled = stream_disabled,
175 .stopped = stream_stopped,
176 .released = stream_released,
177 .recv = bap_stream_rx_recv_cb,
178 .sent = bap_stream_tx_sent_cb,
179 .connected = stream_connected,
180 .disconnected = stream_disconnected,
181 };
182
unicast_client_location_cb(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_location loc)183 static void unicast_client_location_cb(struct bt_conn *conn,
184 enum bt_audio_dir dir,
185 enum bt_audio_location loc)
186 {
187 printk("dir %u loc %X\n", dir, loc);
188 }
189
available_contexts_cb(struct bt_conn * conn,enum bt_audio_context snk_ctx,enum bt_audio_context src_ctx)190 static void available_contexts_cb(struct bt_conn *conn,
191 enum bt_audio_context snk_ctx,
192 enum bt_audio_context src_ctx)
193 {
194 printk("snk ctx %u src ctx %u\n", snk_ctx, src_ctx);
195 }
196
197
config_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)198 static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
199 enum bt_bap_ascs_reason reason)
200 {
201 printk("stream %p config operation rsp_code %u reason %u\n", stream, rsp_code, reason);
202
203 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
204 SET_FLAG(flag_operation_success);
205 }
206 }
207
qos_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)208 static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
209 enum bt_bap_ascs_reason reason)
210 {
211 printk("stream %p qos operation rsp_code %u reason %u\n", stream, rsp_code, reason);
212
213 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
214 SET_FLAG(flag_operation_success);
215 }
216 }
217
enable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)218 static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
219 enum bt_bap_ascs_reason reason)
220 {
221 printk("stream %p enable operation rsp_code %u reason %u\n", stream, rsp_code, reason);
222
223 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
224 SET_FLAG(flag_operation_success);
225 }
226 }
227
start_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)228 static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
229 enum bt_bap_ascs_reason reason)
230 {
231 printk("stream %p start operation rsp_code %u reason %u\n", stream, rsp_code, reason);
232
233 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
234 SET_FLAG(flag_operation_success);
235 }
236 }
237
stop_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)238 static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
239 enum bt_bap_ascs_reason reason)
240 {
241 printk("stream %p stop operation rsp_code %u reason %u\n", stream, rsp_code, reason);
242
243 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
244 SET_FLAG(flag_operation_success);
245 }
246 }
247
disable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)248 static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
249 enum bt_bap_ascs_reason reason)
250 {
251 printk("stream %p disable operation rsp_code %u reason %u\n", stream, rsp_code, reason);
252
253 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
254 SET_FLAG(flag_operation_success);
255 }
256 }
257
metadata_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)258 static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
259 enum bt_bap_ascs_reason reason)
260 {
261 printk("stream %p metadata operation rsp_code %u reason %u\n", stream, rsp_code, reason);
262
263 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
264 SET_FLAG(flag_operation_success);
265 }
266 }
267
release_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)268 static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
269 enum bt_bap_ascs_reason reason)
270 {
271 printk("stream %p release operation rsp_code %u reason %u\n", stream, rsp_code, reason);
272
273 if (rsp_code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
274 SET_FLAG(flag_operation_success);
275 }
276 }
277
add_remote_sink(struct bt_bap_ep * ep)278 static void add_remote_sink(struct bt_bap_ep *ep)
279 {
280 for (size_t i = 0U; i < ARRAY_SIZE(g_sinks); i++) {
281 if (g_sinks[i] == NULL) {
282 printk("Sink #%zu: ep %p\n", i, ep);
283 g_sinks[i] = ep;
284 return;
285 }
286 }
287
288 FAIL("Could not add sink ep\n");
289 }
290
add_remote_source(struct bt_bap_ep * ep)291 static void add_remote_source(struct bt_bap_ep *ep)
292 {
293 for (size_t i = 0U; i < ARRAY_SIZE(g_sources); i++) {
294 if (g_sources[i] == NULL) {
295 printk("Source #%u: ep %p\n", i, ep);
296 g_sources[i] = ep;
297 return;
298 }
299 }
300
301 FAIL("Could not add source ep\n");
302 }
303
print_remote_codec_cap(const struct bt_audio_codec_cap * codec_cap,enum bt_audio_dir dir)304 static void print_remote_codec_cap(const struct bt_audio_codec_cap *codec_cap,
305 enum bt_audio_dir dir)
306 {
307 printk("codec %p dir 0x%02x\n", codec_cap, dir);
308
309 print_codec_cap(codec_cap);
310 }
311
discover_sinks_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)312 static void discover_sinks_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
313 {
314 if (err != 0) {
315 FAIL("Discovery failed: %d\n", err);
316 return;
317 }
318
319 printk("Discover complete\n");
320
321 SET_FLAG(flag_sink_discovered);
322 }
323
discover_sources_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)324 static void discover_sources_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
325 {
326 if (err != 0) {
327 FAIL("Discovery failed: %d\n", err);
328 return;
329 }
330
331 printk("Sources discover complete\n");
332
333 SET_FLAG(flag_source_discovered);
334 }
335
pac_record_cb(struct bt_conn * conn,enum bt_audio_dir dir,const struct bt_audio_codec_cap * codec_cap)336 static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir,
337 const struct bt_audio_codec_cap *codec_cap)
338 {
339 print_remote_codec_cap(codec_cap, dir);
340 SET_FLAG(flag_codec_cap_found);
341 }
342
endpoint_cb(struct bt_conn * conn,enum bt_audio_dir dir,struct bt_bap_ep * ep)343 static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
344 {
345 if (dir == BT_AUDIO_DIR_SINK) {
346 add_remote_sink(ep);
347 } else {
348 add_remote_source(ep);
349 }
350
351 SET_FLAG(flag_endpoint_found);
352 }
353
354 static struct bt_bap_unicast_client_cb unicast_client_cbs = {
355 .location = unicast_client_location_cb,
356 .available_contexts = available_contexts_cb,
357 .config = config_cb,
358 .qos = qos_cb,
359 .enable = enable_cb,
360 .start = start_cb,
361 .stop = stop_cb,
362 .disable = disable_cb,
363 .metadata = metadata_cb,
364 .release = release_cb,
365 .pac_record = pac_record_cb,
366 .endpoint = endpoint_cb,
367 };
368
att_mtu_updated(struct bt_conn * conn,uint16_t tx,uint16_t rx)369 static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
370 {
371 printk("MTU exchanged\n");
372 SET_FLAG(flag_mtu_exchanged);
373 }
374
375 static struct bt_gatt_cb gatt_callbacks = {
376 .att_mtu_updated = att_mtu_updated,
377 };
378
parse_ascs_ad_data(struct bt_data * data,void * user_data)379 static bool parse_ascs_ad_data(struct bt_data *data, void *user_data)
380 {
381 const struct bt_le_scan_recv_info *info = user_data;
382 uint16_t available_source_context;
383 uint16_t available_sink_context;
384 struct net_buf_simple net_buf;
385 struct bt_uuid_16 adv_uuid;
386 uint8_t announcement_type;
387 void *uuid;
388 int err;
389
390 const size_t min_data_len = BT_UUID_SIZE_16 + sizeof(announcement_type) +
391 sizeof(available_sink_context) +
392 sizeof(available_source_context);
393
394 if (data->type != BT_DATA_SVC_DATA16) {
395 return true;
396 }
397
398 if (data->data_len < min_data_len) {
399
400 return true;
401 }
402
403 net_buf_simple_init_with_data(&net_buf, (void *)data->data, data->data_len);
404
405 uuid = net_buf_simple_pull_mem(&net_buf, BT_UUID_SIZE_16);
406 if (!bt_uuid_create(&adv_uuid.uuid, uuid, BT_UUID_SIZE_16)) {
407 return true;
408 }
409
410 if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_ASCS)) {
411 return true;
412 }
413
414 announcement_type = net_buf_simple_pull_u8(&net_buf);
415 available_sink_context = net_buf_simple_pull_le16(&net_buf);
416 available_source_context = net_buf_simple_pull_le16(&net_buf);
417
418 printk("Found ASCS with announcement type 0x%02X, sink ctx 0x%04X, source ctx 0x%04X\n",
419 announcement_type, available_sink_context, available_source_context);
420
421 printk("Stopping scan\n");
422 if (bt_le_scan_stop()) {
423 FAIL("Could not stop scan");
424 return false;
425 }
426
427 err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, BT_BAP_CONN_PARAM_RELAXED,
428 &default_conn);
429 if (err) {
430 FAIL("Could not connect to peer: %d", err);
431 return false;
432 }
433
434 /* Stop parsing */
435 return false;
436 }
437
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)438 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
439 {
440 char addr_str[BT_ADDR_LE_STR_LEN];
441
442 if (default_conn) {
443 return;
444 }
445
446 /* We're only interested in connectable events */
447 if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) {
448 return;
449 }
450 /* connect only to devices in close proximity */
451 if (info->rssi < -70) {
452 return;
453 }
454
455 bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
456 printk("Device found: %s (RSSI %d)\n", addr_str, info->rssi);
457
458 bt_data_parse(ad, parse_ascs_ad_data, (void *)info);
459 }
460
461 static struct bt_le_scan_cb bap_scan_cb = {
462 .recv = broadcast_scan_recv,
463 };
464
init(void)465 static void init(void)
466 {
467 int err;
468
469 err = bt_enable(NULL);
470 if (err != 0) {
471 FAIL("Bluetooth enable failed (err %d)\n", err);
472 return;
473 }
474
475 printk("Bluetooth initialized\n");
476 bap_stream_tx_init();
477
478 for (size_t i = 0; i < ARRAY_SIZE(test_streams); i++) {
479 struct bt_bap_stream *bap_stream =
480 bap_stream_from_audio_test_stream(&test_streams[i]);
481
482 bap_stream->ops = &stream_ops;
483 }
484
485 bt_le_scan_cb_register(&bap_scan_cb);
486 bt_gatt_cb_register(&gatt_callbacks);
487
488 err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
489 if (err != 0) {
490 FAIL("Failed to register client callbacks: %d", err);
491 return;
492 }
493 }
494
scan_and_connect(void)495 static void scan_and_connect(void)
496 {
497 int err;
498
499 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, NULL);
500 if (err != 0) {
501 FAIL("Scanning failed to start (err %d)\n", err);
502 return;
503 }
504
505 printk("Scanning successfully started\n");
506 WAIT_FOR_FLAG(flag_connected);
507 }
508
disconnect_acl(void)509 static void disconnect_acl(void)
510 {
511 int err;
512
513 err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
514 if (err != 0) {
515 FAIL("Failed to disconnect (err %d)\n", err);
516 return;
517 }
518
519 WAIT_FOR_UNSET_FLAG(flag_connected);
520 }
521
exchange_mtu(void)522 static void exchange_mtu(void)
523 {
524 WAIT_FOR_FLAG(flag_mtu_exchanged);
525 }
526
discover_sinks(void)527 static void discover_sinks(void)
528 {
529 int err;
530
531 unicast_client_cbs.discover = discover_sinks_cb;
532
533 UNSET_FLAG(flag_codec_cap_found);
534 UNSET_FLAG(flag_sink_discovered);
535 UNSET_FLAG(flag_endpoint_found);
536
537 err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK);
538 if (err != 0) {
539 printk("Failed to discover sink: %d\n", err);
540 return;
541 }
542
543 memset(g_sinks, 0, sizeof(g_sinks));
544
545 WAIT_FOR_FLAG(flag_codec_cap_found);
546 WAIT_FOR_FLAG(flag_endpoint_found);
547 WAIT_FOR_FLAG(flag_sink_discovered);
548 }
549
discover_sources(void)550 static void discover_sources(void)
551 {
552 int err;
553
554 unicast_client_cbs.discover = discover_sources_cb;
555
556 UNSET_FLAG(flag_codec_cap_found);
557 UNSET_FLAG(flag_source_discovered);
558
559 err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SOURCE);
560 if (err != 0) {
561 printk("Failed to discover sink: %d\n", err);
562 return;
563 }
564
565 memset(g_sources, 0, sizeof(g_sources));
566
567 WAIT_FOR_FLAG(flag_codec_cap_found);
568 WAIT_FOR_FLAG(flag_source_discovered);
569 }
570
codec_configure_stream(struct bt_bap_stream * stream,struct bt_bap_ep * ep,struct bt_audio_codec_cfg * codec_cfg)571 static int codec_configure_stream(struct bt_bap_stream *stream, struct bt_bap_ep *ep,
572 struct bt_audio_codec_cfg *codec_cfg)
573 {
574 int err;
575
576 UNSET_FLAG(flag_stream_codec_configured);
577 UNSET_FLAG(flag_operation_success);
578
579 do {
580
581 err = bt_bap_stream_config(default_conn, stream, ep, codec_cfg);
582 if (err == -EBUSY) {
583 k_sleep(BAP_RETRY_WAIT);
584 } else if (err != 0) {
585 FAIL("Could not configure stream %p: %d\n", stream, err);
586 return err;
587 }
588 } while (err == -EBUSY);
589
590 WAIT_FOR_FLAG(flag_stream_codec_configured);
591 WAIT_FOR_FLAG(flag_operation_success);
592
593 return 0;
594 }
595
codec_configure_streams(size_t stream_cnt)596 static void codec_configure_streams(size_t stream_cnt)
597 {
598 for (size_t i = 0U; i < ARRAY_SIZE(pair_params); i++) {
599 if (pair_params[i].rx_param != NULL && g_sources[i] != NULL) {
600 struct bt_bap_stream *stream = pair_params[i].rx_param->stream;
601 const int err = codec_configure_stream(stream, g_sources[i],
602 &preset_16_2_1.codec_cfg);
603
604 if (err != 0) {
605 FAIL("Unable to configure source stream[%zu]: %d", i, err);
606 return;
607 }
608 }
609
610 if (pair_params[i].tx_param != NULL && g_sinks[i] != NULL) {
611 struct bt_bap_stream *stream = pair_params[i].tx_param->stream;
612 const int err = codec_configure_stream(stream, g_sinks[i],
613 &preset_16_2_1.codec_cfg);
614
615 if (err != 0) {
616 FAIL("Unable to configure sink stream[%zu]: %d", i, err);
617 return;
618 }
619 }
620 }
621 }
622
qos_configure_streams(struct bt_bap_unicast_group * unicast_group,size_t stream_cnt)623 static void qos_configure_streams(struct bt_bap_unicast_group *unicast_group,
624 size_t stream_cnt)
625 {
626 int err;
627
628 UNSET_FLAG(flag_stream_qos_configured);
629
630 do {
631 err = bt_bap_stream_qos(default_conn, unicast_group);
632 if (err == -EBUSY) {
633 k_sleep(BAP_RETRY_WAIT);
634 } else if (err != 0) {
635 FAIL("Unable to QoS configure streams: %d\n", err);
636 return;
637 }
638 } while (err == -EBUSY);
639
640 while (atomic_get(&flag_stream_qos_configured) != stream_cnt) {
641 (void)k_sleep(K_MSEC(1));
642 }
643 }
644
enable_stream(struct bt_bap_stream * stream)645 static int enable_stream(struct bt_bap_stream *stream)
646 {
647 int err;
648
649 UNSET_FLAG(flag_stream_enabled);
650
651 do {
652 err = bt_bap_stream_enable(stream, NULL, 0);
653 if (err == -EBUSY) {
654 k_sleep(BAP_RETRY_WAIT);
655 } else if (err != 0) {
656 FAIL("Could not enable stream %p: %d\n", stream, err);
657 return err;
658 }
659 } while (err == -EBUSY);
660
661 WAIT_FOR_FLAG(flag_stream_enabled);
662
663 return 0;
664 }
665
enable_streams(size_t stream_cnt)666 static void enable_streams(size_t stream_cnt)
667 {
668 for (size_t i = 0U; i < stream_cnt; i++) {
669 struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]);
670 int err;
671
672 err = enable_stream(stream);
673 if (err != 0) {
674 FAIL("Unable to enable stream[%zu]: %d", i, err);
675
676 return;
677 }
678 }
679 }
680
metadata_update_stream(struct bt_bap_stream * stream)681 static int metadata_update_stream(struct bt_bap_stream *stream)
682 {
683 const uint8_t new_meta[] = {
684 BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_VENDOR, LONG_META),
685 };
686 int err;
687
688 UNSET_FLAG(flag_stream_metadata);
689
690 do {
691 err = bt_bap_stream_metadata(stream, new_meta, ARRAY_SIZE(new_meta));
692 if (err == -EBUSY) {
693 k_sleep(BAP_RETRY_WAIT);
694 } else if (err != 0) {
695 FAIL("Could not metadata update stream %p: %d\n", stream, err);
696 return err;
697 }
698 } while (err == -EBUSY);
699
700 WAIT_FOR_FLAG(flag_stream_metadata);
701
702 return 0;
703 }
704
metadata_update_streams(size_t stream_cnt)705 static void metadata_update_streams(size_t stream_cnt)
706 {
707 for (size_t i = 0U; i < stream_cnt; i++) {
708 struct bt_bap_stream *stream = bap_stream_from_audio_test_stream(&test_streams[i]);
709 int err;
710
711 err = metadata_update_stream(stream);
712 if (err != 0) {
713 FAIL("Unable to metadata update stream[%zu]: %d", i, err);
714
715 return;
716 }
717 }
718 }
719
connect_stream(struct bt_bap_stream * stream)720 static int connect_stream(struct bt_bap_stream *stream)
721 {
722 int err;
723
724 UNSET_FLAG(flag_stream_started);
725
726 do {
727 err = bt_bap_stream_connect(stream);
728 if (err == -EALREADY) {
729 SET_FLAG(flag_stream_started);
730 } else if (err != 0) {
731 FAIL("Could not start stream %p: %d\n", stream, err);
732 return err;
733 }
734 } while (err == -EBUSY);
735
736 WAIT_FOR_FLAG(flag_stream_started);
737
738 return 0;
739 }
740
connect_streams(void)741 static void connect_streams(void)
742 {
743 struct bt_bap_stream *source_stream;
744 struct bt_bap_stream *sink_stream;
745
746 /* We only support a single CIS so far, so only start one. We can use the group pair
747 * params to start both a sink and source stream that use the same CIS
748 */
749
750 source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
751 sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream;
752
753 UNSET_FLAG(flag_stream_connected);
754
755 if (sink_stream != NULL) {
756 const int err = connect_stream(sink_stream);
757
758 if (err != 0) {
759 FAIL("Unable to connect sink: %d", err);
760
761 return;
762 }
763 }
764
765 if (source_stream != NULL) {
766 const int err = connect_stream(source_stream);
767
768 if (err != 0) {
769 FAIL("Unable to connect source stream: %d", err);
770
771 return;
772 }
773 }
774
775 WAIT_FOR_FLAG(flag_stream_connected);
776 }
777
start_stream(struct bt_bap_stream * stream)778 static int start_stream(struct bt_bap_stream *stream)
779 {
780 int err;
781
782 UNSET_FLAG(flag_stream_started);
783
784 do {
785 err = bt_bap_stream_start(stream);
786 if (err == -EBUSY) {
787 k_sleep(BAP_RETRY_WAIT);
788 } else if (err != 0) {
789 FAIL("Could not start stream %p: %d\n", stream, err);
790 return err;
791 }
792 } while (err == -EBUSY);
793
794 WAIT_FOR_FLAG(flag_stream_started);
795
796 return 0;
797 }
798
start_streams(void)799 static void start_streams(void)
800 {
801 struct bt_bap_stream *source_stream;
802
803 source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
804
805 if (source_stream != NULL) {
806 const int err = start_stream(source_stream);
807
808 if (err != 0) {
809 FAIL("Unable to start source stream: %d", err);
810
811 return;
812 }
813 }
814 }
815
transceive_streams(void)816 static void transceive_streams(void)
817 {
818 struct bt_bap_stream *source_stream;
819 struct bt_bap_stream *sink_stream;
820
821 source_stream = pair_params[0].rx_param == NULL ? NULL : pair_params[0].rx_param->stream;
822 sink_stream = pair_params[0].tx_param == NULL ? NULL : pair_params[0].tx_param->stream;
823
824 if (sink_stream != NULL) {
825 struct audio_test_stream *test_stream =
826 audio_test_stream_from_bap_stream(sink_stream);
827
828 /* Keep sending until we reach the minimum expected */
829 while (test_stream->tx_cnt < MIN_SEND_COUNT) {
830 k_sleep(K_MSEC(100));
831 }
832 }
833
834 if (source_stream != NULL) {
835 printk("Waiting for data\n");
836 WAIT_FOR_FLAG(flag_audio_received);
837 }
838 }
839
disable_streams(size_t stream_cnt)840 static void disable_streams(size_t stream_cnt)
841 {
842 for (size_t i = 0; i < stream_cnt; i++) {
843 int err;
844
845 UNSET_FLAG(flag_operation_success);
846 UNSET_FLAG(flag_stream_disabled);
847
848 do {
849 err = bt_bap_stream_disable(
850 bap_stream_from_audio_test_stream(&test_streams[i]));
851 if (err == -EBUSY) {
852 k_sleep(BAP_RETRY_WAIT);
853 } else if (err != 0) {
854 FAIL("Could not disable stream: %d\n", err);
855 return;
856 }
857 } while (err == -EBUSY);
858
859 WAIT_FOR_FLAG(flag_operation_success);
860 WAIT_FOR_FLAG(flag_stream_disabled);
861 }
862 }
863
stop_streams(size_t stream_cnt)864 static void stop_streams(size_t stream_cnt)
865 {
866 UNSET_FLAG(flag_stream_disconnected);
867
868 for (size_t i = 0; i < stream_cnt; i++) {
869 struct bt_bap_stream *source_stream;
870 int err;
871
872 /* We can only stop source streams */
873 source_stream =
874 pair_params[i].rx_param == NULL ? NULL : pair_params[i].rx_param->stream;
875
876 if (source_stream == NULL) {
877 continue;
878 }
879
880 UNSET_FLAG(flag_operation_success);
881 UNSET_FLAG(flag_stream_stopped);
882
883 do {
884 err = bt_bap_stream_stop(source_stream);
885 if (err == -EBUSY) {
886 k_sleep(BAP_RETRY_WAIT);
887 } else if (err != 0) {
888 FAIL("Could not stop stream: %d\n", err);
889 return;
890 }
891 } while (err == -EBUSY);
892
893 WAIT_FOR_FLAG(flag_operation_success);
894 WAIT_FOR_FLAG(flag_stream_stopped);
895 }
896
897 WAIT_FOR_FLAG(flag_stream_disconnected);
898 }
899
release_streams(size_t stream_cnt)900 static void release_streams(size_t stream_cnt)
901 {
902 for (size_t i = 0; i < stream_cnt; i++) {
903 int err;
904
905 UNSET_FLAG(flag_operation_success);
906 UNSET_FLAG(flag_stream_released);
907
908 do {
909 err = bt_bap_stream_release(
910 bap_stream_from_audio_test_stream(&test_streams[i]));
911 if (err == -EBUSY) {
912 k_sleep(BAP_RETRY_WAIT);
913 } else if (err != 0) {
914 FAIL("Could not release stream: %d\n", err);
915 return;
916 }
917 } while (err == -EBUSY);
918
919 WAIT_FOR_FLAG(flag_operation_success);
920 WAIT_FOR_FLAG(flag_stream_released);
921 }
922 }
923
create_unicast_group(struct bt_bap_unicast_group ** unicast_group)924 static size_t create_unicast_group(struct bt_bap_unicast_group **unicast_group)
925 {
926 struct bt_bap_unicast_group_param param;
927 size_t stream_cnt = 0;
928 size_t pair_cnt = 0;
929 int err;
930
931 memset(stream_params, 0, sizeof(stream_params));
932 memset(pair_params, 0, sizeof(pair_params));
933
934 for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sinks), ARRAY_SIZE(test_streams)); i++) {
935 if (g_sinks[i] == NULL) {
936 break;
937 }
938
939 stream_params[stream_cnt].stream =
940 bap_stream_from_audio_test_stream(&test_streams[stream_cnt]);
941 stream_params[stream_cnt].qos = &preset_16_2_1.qos;
942 pair_params[i].tx_param = &stream_params[stream_cnt];
943
944 stream_cnt++;
945
946 break;
947 }
948
949 for (size_t i = 0U; i < MIN(ARRAY_SIZE(g_sources), ARRAY_SIZE(test_streams)); i++) {
950 if (g_sources[i] == NULL) {
951 break;
952 }
953
954 stream_params[stream_cnt].stream =
955 bap_stream_from_audio_test_stream(&test_streams[stream_cnt]);
956 stream_params[stream_cnt].qos = &preset_16_2_1.qos;
957 pair_params[i].rx_param = &stream_params[stream_cnt];
958
959 stream_cnt++;
960
961 break;
962 }
963
964 for (pair_cnt = 0U; pair_cnt < ARRAY_SIZE(pair_params); pair_cnt++) {
965 if (pair_params[pair_cnt].rx_param == NULL &&
966 pair_params[pair_cnt].tx_param == NULL) {
967 break;
968 }
969 }
970
971 if (stream_cnt == 0U) {
972 FAIL("No streams added to group");
973
974 return 0;
975 }
976
977 param.params = pair_params;
978 param.params_count = pair_cnt;
979 param.packing = BT_ISO_PACKING_SEQUENTIAL;
980
981 /* Require controller support for CIGs */
982 err = bt_bap_unicast_group_create(¶m, unicast_group);
983 if (err != 0) {
984 FAIL("Unable to create unicast group: %d", err);
985
986 return 0;
987 }
988
989 return stream_cnt;
990 }
991
delete_unicast_group(struct bt_bap_unicast_group * unicast_group)992 static void delete_unicast_group(struct bt_bap_unicast_group *unicast_group)
993 {
994 int err;
995
996 /* Require controller support for CIGs */
997 err = bt_bap_unicast_group_delete(unicast_group);
998 if (err != 0) {
999 FAIL("Unable to delete unicast group: %d", err);
1000 return;
1001 }
1002 }
1003
test_main(void)1004 static void test_main(void)
1005 {
1006 /* TODO: Temporarily reduce to 1 due to bug in controller. Set to > 1 value again when
1007 * https://github.com/zephyrproject-rtos/zephyr/issues/57904 has been resolved.
1008 */
1009 const unsigned int iterations = 1;
1010
1011 init();
1012
1013 scan_and_connect();
1014
1015 exchange_mtu();
1016
1017 discover_sinks();
1018 discover_sinks(); /* test that we can discover twice */
1019
1020 discover_sources();
1021 discover_sources(); /* test that we can discover twice */
1022
1023 /* Run the stream setup multiple time to ensure states are properly
1024 * set and reset
1025 */
1026 for (unsigned int i = 0U; i < iterations; i++) {
1027 struct bt_bap_unicast_group *unicast_group;
1028 size_t stream_cnt;
1029
1030 printk("\n########### Running iteration #%u\n\n", i);
1031
1032 printk("Creating unicast group\n");
1033 stream_cnt = create_unicast_group(&unicast_group);
1034
1035 printk("Codec configuring streams\n");
1036 codec_configure_streams(stream_cnt);
1037
1038 printk("QoS configuring streams\n");
1039 qos_configure_streams(unicast_group, stream_cnt);
1040
1041 printk("Enabling streams\n");
1042 enable_streams(stream_cnt);
1043
1044 printk("Metadata update streams\n");
1045 metadata_update_streams(stream_cnt);
1046
1047 printk("Connecting streams\n");
1048 connect_streams();
1049
1050 printk("Starting streams\n");
1051 start_streams();
1052
1053 printk("Starting transceiving\n");
1054 transceive_streams();
1055
1056 printk("Disabling streams\n");
1057 disable_streams(stream_cnt);
1058
1059 printk("Stopping streams\n");
1060 stop_streams(stream_cnt);
1061
1062 printk("Releasing streams\n");
1063 release_streams(stream_cnt);
1064
1065 /* Test removing streams from group after creation */
1066 printk("Deleting unicast group\n");
1067 delete_unicast_group(unicast_group);
1068 unicast_group = NULL;
1069 }
1070
1071 disconnect_acl();
1072
1073 PASS("Unicast client passed\n");
1074 }
1075
test_main_acl_disconnect(void)1076 static void test_main_acl_disconnect(void)
1077 {
1078 struct bt_bap_unicast_group *unicast_group;
1079 size_t stream_cnt;
1080
1081 init();
1082
1083 stream_ops.recv = NULL; /* We do not care about data in this test */
1084
1085 scan_and_connect();
1086
1087 exchange_mtu();
1088
1089 discover_sinks();
1090
1091 discover_sources();
1092
1093 printk("Creating unicast group\n");
1094 stream_cnt = create_unicast_group(&unicast_group);
1095
1096 printk("Codec configuring streams\n");
1097 codec_configure_streams(stream_cnt);
1098
1099 printk("QoS configuring streams\n");
1100 qos_configure_streams(unicast_group, stream_cnt);
1101
1102 printk("Enabling streams\n");
1103 enable_streams(stream_cnt);
1104
1105 printk("Metadata update streams\n");
1106 metadata_update_streams(stream_cnt);
1107
1108 printk("Connecting streams\n");
1109 connect_streams();
1110
1111 printk("Starting streams\n");
1112 start_streams();
1113
1114 disconnect_acl();
1115
1116 printk("Deleting unicast group\n");
1117 delete_unicast_group(unicast_group);
1118 unicast_group = NULL;
1119
1120 /* Reconnect */
1121 scan_and_connect();
1122
1123 disconnect_acl();
1124
1125 PASS("Unicast client ACL disconnect passed\n");
1126 }
1127
test_main_async_group(void)1128 static void test_main_async_group(void)
1129 {
1130 struct bt_bap_stream rx_stream = {0};
1131 struct bt_bap_stream tx_stream = {0};
1132 struct bt_bap_qos_cfg rx_qos = BT_BAP_QOS_CFG_UNFRAMED(7500U, 30U, 2U, 75U, 40000U);
1133 struct bt_bap_qos_cfg tx_qos = BT_BAP_QOS_CFG_UNFRAMED(10000U, 40U, 2U, 100U, 40000U);
1134 struct bt_bap_unicast_group_stream_param rx_param = {
1135 .qos = &rx_qos,
1136 .stream = &rx_stream,
1137 };
1138 struct bt_bap_unicast_group_stream_param tx_param = {
1139 .qos = &tx_qos,
1140 .stream = &tx_stream,
1141 };
1142 struct bt_bap_unicast_group_stream_pair_param pair_param = {
1143 .rx_param = &rx_param,
1144 .tx_param = &tx_param,
1145 };
1146 struct bt_bap_unicast_group_param param = {
1147 .params = &pair_param,
1148 .params_count = 1U,
1149 .packing = BT_ISO_PACKING_SEQUENTIAL,
1150 };
1151 struct bt_bap_unicast_group *unicast_group;
1152 int err;
1153
1154 init();
1155
1156 err = bt_bap_unicast_group_create(¶m, &unicast_group);
1157 if (err != 0) {
1158 FAIL("Unable to create unicast group: %d", err);
1159
1160 return;
1161 }
1162
1163 PASS("Unicast client async group parameters passed\n");
1164 }
1165
test_main_reconf_group(void)1166 static void test_main_reconf_group(void)
1167 {
1168 static struct bt_bap_lc3_preset preset_16_2_2 = BT_BAP_LC3_UNICAST_PRESET_16_2_2(
1169 BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
1170 struct bt_bap_stream rx_stream = {0};
1171 struct bt_bap_stream tx_stream = {0};
1172 struct bt_bap_unicast_group_stream_param rx_param = {
1173 .qos = &preset_16_2_1.qos,
1174 .stream = &rx_stream,
1175 };
1176 struct bt_bap_unicast_group_stream_param tx_param = {
1177 .qos = &preset_16_2_1.qos,
1178 .stream = &tx_stream,
1179 };
1180 struct bt_bap_unicast_group_stream_pair_param pair_param = {
1181 .rx_param = &rx_param,
1182 .tx_param = &tx_param,
1183 };
1184 struct bt_bap_unicast_group_param param = {
1185 .params = &pair_param,
1186 .params_count = 1U,
1187 .packing = BT_ISO_PACKING_SEQUENTIAL,
1188 };
1189 struct bt_bap_unicast_group *unicast_group;
1190 int err;
1191
1192 init();
1193
1194 err = bt_bap_unicast_group_create(¶m, &unicast_group);
1195 if (err != 0) {
1196 FAIL("Unable to create unicast group: %d", err);
1197
1198 return;
1199 }
1200
1201 rx_param.qos = &preset_16_2_2.qos;
1202 tx_param.qos = &preset_16_2_2.qos;
1203 err = bt_bap_unicast_group_reconfig(unicast_group, ¶m);
1204 if (err != 0) {
1205 FAIL("Unable to reconfigure unicast group: %d", err);
1206
1207 return;
1208 }
1209
1210 PASS("Unicast client async group parameters passed\n");
1211 }
1212
1213 static const struct bst_test_instance test_unicast_client[] = {
1214 {
1215 .test_id = "unicast_client",
1216 .test_pre_init_f = test_init,
1217 .test_tick_f = test_tick,
1218 .test_main_f = test_main,
1219 },
1220 {
1221 .test_id = "unicast_client_acl_disconnect",
1222 .test_pre_init_f = test_init,
1223 .test_tick_f = test_tick,
1224 .test_main_f = test_main_acl_disconnect,
1225 },
1226 {
1227 .test_id = "unicast_client_async_group",
1228 .test_pre_init_f = test_init,
1229 .test_tick_f = test_tick,
1230 .test_main_f = test_main_async_group,
1231 .test_descr = "Tests that a unicast group (CIG) can be created with different "
1232 "values in each direction, such as 10000us SDU interval in C to P "
1233 "and 7500us for P to C",
1234 },
1235 {
1236 .test_id = "unicast_client_reconf_group",
1237 .test_pre_init_f = test_init,
1238 .test_tick_f = test_tick,
1239 .test_main_f = test_main_reconf_group,
1240 .test_descr = "Tests that a unicast group (CIG) can be reconfigred with new values",
1241 },
1242 BSTEST_END_MARKER,
1243 };
1244
test_unicast_client_install(struct bst_test_list * tests)1245 struct bst_test_list *test_unicast_client_install(struct bst_test_list *tests)
1246 {
1247 return bst_add_tests(tests, test_unicast_client);
1248 }
1249
1250 #else /* !(CONFIG_BT_BAP_UNICAST_CLIENT) */
1251
test_unicast_client_install(struct bst_test_list * tests)1252 struct bst_test_list *test_unicast_client_install(struct bst_test_list *tests)
1253 {
1254 return tests;
1255 }
1256
1257 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1258