1 /*
2  * Copyright (c) 2021-2025 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 
13 #include <zephyr/autoconf.h>
14 #include <zephyr/bluetooth/addr.h>
15 #include <zephyr/bluetooth/att.h>
16 #include <zephyr/bluetooth/audio/audio.h>
17 #include <zephyr/bluetooth/audio/bap.h>
18 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
19 #include <zephyr/bluetooth/bluetooth.h>
20 #include <zephyr/bluetooth/conn.h>
21 #include <zephyr/bluetooth/gap.h>
22 #include <zephyr/bluetooth/gatt.h>
23 #include <zephyr/bluetooth/hci.h>
24 #include <zephyr/bluetooth/hci_types.h>
25 #include <zephyr/bluetooth/iso.h>
26 #include <zephyr/bluetooth/uuid.h>
27 #include <zephyr/kernel.h>
28 #include <zephyr/net_buf.h>
29 #include <zephyr/sys/__assert.h>
30 #include <zephyr/sys/byteorder.h>
31 #include <zephyr/sys/printk.h>
32 #include <zephyr/sys/util.h>
33 #include <zephyr/sys/util_macro.h>
34 #include <zephyr/types.h>
35 
36 #include "stream_tx.h"
37 
38 static void start_scan(void);
39 
40 uint64_t unicast_audio_recv_ctr; /* This value is exposed to test code */
41 
42 static struct bt_bap_unicast_client_cb unicast_client_cbs;
43 static struct bt_conn *default_conn;
44 static struct bt_bap_unicast_group *unicast_group;
45 static struct audio_sink {
46 	struct bt_bap_ep *ep;
47 	uint16_t seq_num;
48 } sinks[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
49 static struct bt_bap_ep *sources[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
50 
51 static struct bt_bap_stream streams[CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT +
52 				      CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
53 static size_t configured_sink_stream_count;
54 static size_t configured_source_stream_count;
55 
56 #define configured_stream_count (configured_sink_stream_count + \
57 				 configured_source_stream_count)
58 
59 /* Select a codec configuration to apply that is mandatory to support by both client and server.
60  * Allows this sample application to work without logic to parse the codec capabilities of the
61  * server and selection of an appropriate codec configuration.
62  */
63 static struct bt_bap_lc3_preset codec_configuration = BT_BAP_LC3_UNICAST_PRESET_16_2_1(
64 	BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED);
65 
66 static K_SEM_DEFINE(sem_connected, 0, 1);
67 static K_SEM_DEFINE(sem_disconnected, 0, 1);
68 static K_SEM_DEFINE(sem_mtu_exchanged, 0, 1);
69 static K_SEM_DEFINE(sem_security_updated, 0, 1);
70 static K_SEM_DEFINE(sem_sinks_discovered, 0, 1);
71 static K_SEM_DEFINE(sem_sources_discovered, 0, 1);
72 static K_SEM_DEFINE(sem_stream_configured, 0, 1);
73 static K_SEM_DEFINE(sem_stream_qos, 0, ARRAY_SIZE(sinks) + ARRAY_SIZE(sources));
74 static K_SEM_DEFINE(sem_stream_enabled, 0, 1);
75 static K_SEM_DEFINE(sem_stream_started, 0, 1);
76 static K_SEM_DEFINE(sem_stream_connected, 0, 1);
77 
print_hex(const uint8_t * ptr,size_t len)78 static void print_hex(const uint8_t *ptr, size_t len)
79 {
80 	while (len-- != 0) {
81 		printk("%02x", *ptr++);
82 	}
83 }
84 
print_cb(struct bt_data * data,void * user_data)85 static bool print_cb(struct bt_data *data, void *user_data)
86 {
87 	const char *str = (const char *)user_data;
88 
89 	printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
90 	print_hex(data->data, data->data_len);
91 	printk("\n");
92 
93 	return true;
94 }
95 
print_codec_cap(const struct bt_audio_codec_cap * codec_cap)96 static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
97 {
98 	printk("codec id 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cap->id, codec_cap->cid,
99 	       codec_cap->vid, codec_cap->data_len);
100 
101 	if (codec_cap->id == BT_HCI_CODING_FORMAT_LC3) {
102 		bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
103 	} else { /* If not LC3, we cannot assume it's LTV */
104 		printk("data: ");
105 		print_hex(codec_cap->data, codec_cap->data_len);
106 		printk("\n");
107 	}
108 
109 	bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
110 }
111 
check_audio_support_and_connect(struct bt_data * data,void * user_data)112 static bool check_audio_support_and_connect(struct bt_data *data,
113 					    void *user_data)
114 {
115 	struct net_buf_simple ascs_svc_data;
116 	bt_addr_le_t *addr = user_data;
117 	uint8_t announcement_type;
118 	uint32_t audio_contexts;
119 	const struct bt_uuid *uuid;
120 	uint16_t uuid_val;
121 	uint8_t meta_len;
122 	size_t min_size;
123 	int err;
124 
125 	printk("[AD]: %u data_len %u\n", data->type, data->data_len);
126 
127 	if (data->type != BT_DATA_SVC_DATA16) {
128 		return true; /* Continue parsing to next AD data type */
129 	}
130 
131 	if (data->data_len < sizeof(uuid_val)) {
132 		printk("AD invalid size %u\n", data->data_len);
133 		return true; /* Continue parsing to next AD data type */
134 	}
135 
136 	net_buf_simple_init_with_data(&ascs_svc_data, (void *)data->data,
137 				      data->data_len);
138 
139 	uuid_val = net_buf_simple_pull_le16(&ascs_svc_data);
140 	uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(uuid_val));
141 	if (bt_uuid_cmp(uuid, BT_UUID_ASCS) != 0) {
142 		/* We are looking for the ASCS service data */
143 		return true; /* Continue parsing to next AD data type */
144 	}
145 
146 	min_size = sizeof(announcement_type) + sizeof(audio_contexts) + sizeof(meta_len);
147 	if (ascs_svc_data.len < min_size) {
148 		printk("AD invalid size %u\n", data->data_len);
149 		return false; /* Stop parsing */
150 	}
151 
152 	announcement_type = net_buf_simple_pull_u8(&ascs_svc_data);
153 	audio_contexts = net_buf_simple_pull_le32(&ascs_svc_data);
154 	meta_len = net_buf_simple_pull_u8(&ascs_svc_data);
155 
156 	err = bt_le_scan_stop();
157 	if (err != 0) {
158 		printk("Failed to stop scan: %d\n", err);
159 		return false; /* Stop parsing */
160 	}
161 
162 	printk("Audio server found with type %u, contexts 0x%08x and meta_len %u; connecting\n",
163 	       announcement_type, audio_contexts, meta_len);
164 
165 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_BAP_CONN_PARAM_RELAXED,
166 				&default_conn);
167 	if (err != 0) {
168 		printk("Create conn to failed (%u)\n", err);
169 		start_scan();
170 	}
171 
172 	return false; /* Stop parsing */
173 }
174 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)175 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
176 			 struct net_buf_simple *ad)
177 {
178 	char addr_str[BT_ADDR_LE_STR_LEN];
179 
180 	if (default_conn != NULL) {
181 		/* Already connected */
182 		return;
183 	}
184 
185 	/* We're only interested in connectable events */
186 	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
187 	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND &&
188 	    type != BT_GAP_ADV_TYPE_EXT_ADV) {
189 		return;
190 	}
191 
192 	(void)bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
193 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
194 
195 	/* connect only to devices in close proximity */
196 	if (rssi < -50) {
197 		return;
198 	}
199 
200 	bt_data_parse(ad, check_audio_support_and_connect, (void *)addr);
201 }
202 
start_scan(void)203 static void start_scan(void)
204 {
205 	int err;
206 
207 	/* This demo doesn't require active scan */
208 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
209 	if (err != 0) {
210 		printk("Scanning failed to start (err %d)\n", err);
211 		return;
212 	}
213 
214 	printk("Scanning successfully started\n");
215 }
216 
stream_configured(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg_pref * pref)217 static void stream_configured(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg_pref *pref)
218 {
219 	printk("Audio Stream %p configured\n", stream);
220 
221 	k_sem_give(&sem_stream_configured);
222 }
223 
stream_qos_set(struct bt_bap_stream * stream)224 static void stream_qos_set(struct bt_bap_stream *stream)
225 {
226 	struct bt_iso_info info;
227 	int err;
228 
229 	err = bt_iso_chan_get_info(stream->iso, &info);
230 	__ASSERT(err == 0, "Failed to get ISO chan info: %d", err);
231 
232 	printk("Audio Stream %p QoS set with CIG_ID %u and CIS_ID %u\n", stream,
233 	       info.unicast.cig_id, info.unicast.cis_id);
234 
235 	k_sem_give(&sem_stream_qos);
236 }
237 
stream_enabled(struct bt_bap_stream * stream)238 static void stream_enabled(struct bt_bap_stream *stream)
239 {
240 	printk("Audio Stream %p enabled\n", stream);
241 
242 	k_sem_give(&sem_stream_enabled);
243 }
244 
stream_tx_can_send(const struct bt_bap_stream * stream)245 static bool stream_tx_can_send(const struct bt_bap_stream *stream)
246 {
247 	struct bt_bap_ep_info info;
248 	int err;
249 
250 	if (stream == NULL || stream->ep == NULL) {
251 		return false;
252 	}
253 
254 	err = bt_bap_ep_get_info(stream->ep, &info);
255 	if (err != 0) {
256 		return false;
257 	}
258 
259 	return info.can_send;
260 }
261 
stream_connected_cb(struct bt_bap_stream * stream)262 static void stream_connected_cb(struct bt_bap_stream *stream)
263 {
264 	printk("Audio Stream %p connected\n", stream);
265 
266 	/* Reset sequence number for sinks */
267 	for (size_t i = 0U; i < configured_sink_stream_count; i++) {
268 		if (stream->ep == sinks[i].ep) {
269 			sinks[i].seq_num = 0U;
270 			break;
271 		}
272 	}
273 
274 	k_sem_give(&sem_stream_connected);
275 }
276 
stream_started(struct bt_bap_stream * stream)277 static void stream_started(struct bt_bap_stream *stream)
278 {
279 	printk("Audio Stream %p started\n", stream);
280 	unicast_audio_recv_ctr = 0U;
281 
282 	/* Register the stream for TX if it can send */
283 	if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_tx_can_send(stream)) {
284 		const int err = stream_tx_register(stream);
285 
286 		if (err != 0) {
287 			printk("Failed to register stream %p for TX: %d\n", stream, err);
288 		}
289 	}
290 
291 	k_sem_give(&sem_stream_started);
292 }
293 
stream_metadata_updated(struct bt_bap_stream * stream)294 static void stream_metadata_updated(struct bt_bap_stream *stream)
295 {
296 	printk("Audio Stream %p metadata updated\n", stream);
297 }
298 
stream_disabled(struct bt_bap_stream * stream)299 static void stream_disabled(struct bt_bap_stream *stream)
300 {
301 	printk("Audio Stream %p disabled\n", stream);
302 }
303 
stream_stopped(struct bt_bap_stream * stream,uint8_t reason)304 static void stream_stopped(struct bt_bap_stream *stream, uint8_t reason)
305 {
306 	printk("Audio Stream %p stopped with reason 0x%02X\n", stream, reason);
307 
308 	/* Unregister the stream for TX if it can send */
309 	if (IS_ENABLED(CONFIG_BT_AUDIO_TX) && stream_tx_can_send(stream)) {
310 		const int err = stream_tx_unregister(stream);
311 
312 		if (err != 0) {
313 			printk("Failed to unregister stream %p for TX: %d", stream, err);
314 		}
315 	}
316 }
317 
stream_released(struct bt_bap_stream * stream)318 static void stream_released(struct bt_bap_stream *stream)
319 {
320 	printk("Audio Stream %p released\n", stream);
321 }
322 
stream_recv(struct bt_bap_stream * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)323 static void stream_recv(struct bt_bap_stream *stream,
324 			const struct bt_iso_recv_info *info,
325 			struct net_buf *buf)
326 {
327 	if (info->flags & BT_ISO_FLAGS_VALID) {
328 		unicast_audio_recv_ctr++;
329 
330 		if (CONFIG_INFO_REPORTING_INTERVAL > 0 &&
331 		    (unicast_audio_recv_ctr % CONFIG_INFO_REPORTING_INTERVAL) == 0U) {
332 			printk("Incoming audio on stream %p len %u (%" PRIu64 ")\n", stream,
333 			       buf->len, unicast_audio_recv_ctr);
334 		}
335 	}
336 }
337 
338 static struct bt_bap_stream_ops stream_ops = {
339 	.configured = stream_configured,
340 	.qos_set = stream_qos_set,
341 	.enabled = stream_enabled,
342 	.started = stream_started,
343 	.metadata_updated = stream_metadata_updated,
344 	.disabled = stream_disabled,
345 	.stopped = stream_stopped,
346 	.released = stream_released,
347 	.recv = stream_recv,
348 	.connected = stream_connected_cb,
349 };
350 
add_remote_source(struct bt_bap_ep * ep)351 static void add_remote_source(struct bt_bap_ep *ep)
352 {
353 	for (size_t i = 0U; i < ARRAY_SIZE(sources); i++) {
354 		if (sources[i] == NULL) {
355 			printk("Source #%zu: ep %p\n", i, ep);
356 			sources[i] = ep;
357 			return;
358 		}
359 	}
360 
361 	printk("Could not add source ep\n");
362 }
363 
add_remote_sink(struct bt_bap_ep * ep)364 static void add_remote_sink(struct bt_bap_ep *ep)
365 {
366 	for (size_t i = 0U; i < ARRAY_SIZE(sinks); i++) {
367 		if (sinks[i].ep == NULL) {
368 			printk("Sink #%zu: ep %p\n", i, ep);
369 			sinks[i].ep = ep;
370 			return;
371 		}
372 	}
373 
374 	printk("Could not add sink ep\n");
375 }
376 
print_remote_codec_cap(const struct bt_audio_codec_cap * codec_cap,enum bt_audio_dir dir)377 static void print_remote_codec_cap(const struct bt_audio_codec_cap *codec_cap,
378 				   enum bt_audio_dir dir)
379 {
380 	printk("codec_cap %p dir 0x%02x\n", codec_cap, dir);
381 
382 	print_codec_cap(codec_cap);
383 }
384 
discover_sinks_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)385 static void discover_sinks_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
386 {
387 	if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
388 		printk("Discovery failed: %d\n", err);
389 		return;
390 	}
391 
392 	if (err == BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
393 		printk("Discover sinks completed without finding any sink ASEs\n");
394 	} else {
395 		printk("Discover sinks complete: err %d\n", err);
396 	}
397 
398 	k_sem_give(&sem_sinks_discovered);
399 }
400 
discover_sources_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)401 static void discover_sources_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
402 {
403 	if (err != 0 && err != BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
404 		printk("Discovery failed: %d\n", err);
405 		return;
406 	}
407 
408 	if (err == BT_ATT_ERR_ATTRIBUTE_NOT_FOUND) {
409 		printk("Discover sinks completed without finding any source ASEs\n");
410 	} else {
411 		printk("Discover sources complete: err %d\n", err);
412 	}
413 
414 	k_sem_give(&sem_sources_discovered);
415 }
416 
connected(struct bt_conn * conn,uint8_t err)417 static void connected(struct bt_conn *conn, uint8_t err)
418 {
419 	char addr[BT_ADDR_LE_STR_LEN];
420 
421 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
422 
423 	if (err != 0) {
424 		printk("Failed to connect to %s %u %s\n", addr, err, bt_hci_err_to_str(err));
425 
426 		bt_conn_unref(default_conn);
427 		default_conn = NULL;
428 
429 		start_scan();
430 		return;
431 	}
432 
433 	if (conn != default_conn) {
434 		return;
435 	}
436 
437 	printk("Connected: %s\n", addr);
438 	k_sem_give(&sem_connected);
439 }
440 
disconnected(struct bt_conn * conn,uint8_t reason)441 static void disconnected(struct bt_conn *conn, uint8_t reason)
442 {
443 	char addr[BT_ADDR_LE_STR_LEN];
444 
445 	if (conn != default_conn) {
446 		return;
447 	}
448 
449 	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
450 
451 	printk("Disconnected: %s, reason 0x%02x %s\n", addr, reason, bt_hci_err_to_str(reason));
452 
453 	bt_conn_unref(default_conn);
454 	default_conn = NULL;
455 
456 	k_sem_give(&sem_disconnected);
457 }
458 
security_changed_cb(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)459 static void security_changed_cb(struct bt_conn *conn, bt_security_t level,
460 				enum bt_security_err err)
461 {
462 	if (err == 0) {
463 		k_sem_give(&sem_security_updated);
464 	} else {
465 		printk("Failed to set security level: %s(%u)", bt_security_err_to_str(err), err);
466 	}
467 }
468 
469 BT_CONN_CB_DEFINE(conn_callbacks) = {
470 	.connected = connected,
471 	.disconnected = disconnected,
472 	.security_changed = security_changed_cb
473 };
474 
att_mtu_updated(struct bt_conn * conn,uint16_t tx,uint16_t rx)475 static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
476 {
477 	printk("MTU exchanged: %u/%u\n", tx, rx);
478 	k_sem_give(&sem_mtu_exchanged);
479 }
480 
481 static struct bt_gatt_cb gatt_callbacks = {
482 	.att_mtu_updated = att_mtu_updated,
483 };
484 
unicast_client_location_cb(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_location loc)485 static void unicast_client_location_cb(struct bt_conn *conn,
486 				      enum bt_audio_dir dir,
487 				      enum bt_audio_location loc)
488 {
489 	printk("dir %u loc %X\n", dir, loc);
490 }
491 
available_contexts_cb(struct bt_conn * conn,enum bt_audio_context snk_ctx,enum bt_audio_context src_ctx)492 static void available_contexts_cb(struct bt_conn *conn,
493 				  enum bt_audio_context snk_ctx,
494 				  enum bt_audio_context src_ctx)
495 {
496 	printk("snk ctx %u src ctx %u\n", snk_ctx, src_ctx);
497 }
498 
pac_record_cb(struct bt_conn * conn,enum bt_audio_dir dir,const struct bt_audio_codec_cap * codec_cap)499 static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir,
500 			  const struct bt_audio_codec_cap *codec_cap)
501 {
502 	print_remote_codec_cap(codec_cap, dir);
503 }
504 
endpoint_cb(struct bt_conn * conn,enum bt_audio_dir dir,struct bt_bap_ep * ep)505 static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
506 {
507 	if (dir == BT_AUDIO_DIR_SOURCE) {
508 		add_remote_source(ep);
509 	} else if (dir == BT_AUDIO_DIR_SINK) {
510 		add_remote_sink(ep);
511 	}
512 }
513 
514 static struct bt_bap_unicast_client_cb unicast_client_cbs = {
515 	.location = unicast_client_location_cb,
516 	.available_contexts = available_contexts_cb,
517 	.pac_record = pac_record_cb,
518 	.endpoint = endpoint_cb,
519 };
520 
init(void)521 static int init(void)
522 {
523 	int err;
524 
525 	err = bt_enable(NULL);
526 	if (err != 0) {
527 		printk("Bluetooth enable failed (err %d)\n", err);
528 		return err;
529 	}
530 
531 	for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
532 		streams[i].ops = &stream_ops;
533 	}
534 
535 	bt_gatt_cb_register(&gatt_callbacks);
536 
537 	if (IS_ENABLED(CONFIG_BT_AUDIO_TX)) {
538 		stream_tx_init();
539 	}
540 
541 	return 0;
542 }
543 
scan_and_connect(void)544 static int scan_and_connect(void)
545 {
546 	int err;
547 
548 	start_scan();
549 
550 	err = k_sem_take(&sem_connected, K_FOREVER);
551 	if (err != 0) {
552 		printk("failed to take sem_connected (err %d)\n", err);
553 		return err;
554 	}
555 
556 	err = k_sem_take(&sem_mtu_exchanged, K_FOREVER);
557 	if (err != 0) {
558 		printk("failed to take sem_mtu_exchanged (err %d)\n", err);
559 		return err;
560 	}
561 
562 	err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
563 	if (err != 0) {
564 		printk("failed to set security (err %d)\n", err);
565 		return err;
566 	}
567 
568 	err = k_sem_take(&sem_security_updated, K_FOREVER);
569 	if (err != 0) {
570 		printk("failed to take sem_security_updated (err %d)\n", err);
571 		return err;
572 	}
573 
574 	return 0;
575 }
576 
discover_sinks(void)577 static int discover_sinks(void)
578 {
579 	int err;
580 
581 	unicast_client_cbs.discover = discover_sinks_cb;
582 
583 	err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SINK);
584 	if (err != 0) {
585 		printk("Failed to discover sinks: %d\n", err);
586 		return err;
587 	}
588 
589 	err = k_sem_take(&sem_sinks_discovered, K_FOREVER);
590 	if (err != 0) {
591 		printk("failed to take sem_sinks_discovered (err %d)\n", err);
592 		return err;
593 	}
594 
595 	return 0;
596 }
597 
discover_sources(void)598 static int discover_sources(void)
599 {
600 	int err;
601 
602 	unicast_client_cbs.discover = discover_sources_cb;
603 
604 	err = bt_bap_unicast_client_discover(default_conn, BT_AUDIO_DIR_SOURCE);
605 	if (err != 0) {
606 		printk("Failed to discover sources: %d\n", err);
607 		return err;
608 	}
609 
610 	err = k_sem_take(&sem_sources_discovered, K_FOREVER);
611 	if (err != 0) {
612 		printk("failed to take sem_sources_discovered (err %d)\n", err);
613 		return err;
614 	}
615 
616 	return 0;
617 }
618 
configure_stream(struct bt_bap_stream * stream,struct bt_bap_ep * ep)619 static int configure_stream(struct bt_bap_stream *stream, struct bt_bap_ep *ep)
620 {
621 	int err;
622 
623 	err = bt_bap_stream_config(default_conn, stream, ep, &codec_configuration.codec_cfg);
624 	if (err != 0) {
625 		return err;
626 	}
627 
628 	err = k_sem_take(&sem_stream_configured, K_FOREVER);
629 	if (err != 0) {
630 		printk("failed to take sem_stream_configured (err %d)\n", err);
631 		return err;
632 	}
633 
634 	return 0;
635 }
636 
configure_streams(void)637 static int configure_streams(void)
638 {
639 	int err;
640 
641 	for (size_t i = 0; i < ARRAY_SIZE(sinks); i++) {
642 		struct bt_bap_ep *ep = sinks[i].ep;
643 		struct bt_bap_stream *stream = &streams[i];
644 
645 		if (ep == NULL) {
646 			continue;
647 		}
648 
649 		err = configure_stream(stream, ep);
650 		if (err != 0) {
651 			printk("Could not configure sink stream[%zu]: %d\n",
652 			       i, err);
653 			return err;
654 		}
655 
656 		printk("Configured sink stream[%zu]\n", i);
657 		configured_sink_stream_count++;
658 	}
659 
660 	for (size_t i = 0; i < ARRAY_SIZE(sources); i++) {
661 		struct bt_bap_ep *ep = sources[i];
662 		struct bt_bap_stream *stream = &streams[i + configured_sink_stream_count];
663 
664 		if (ep == NULL) {
665 			continue;
666 		}
667 
668 		err = configure_stream(stream, ep);
669 		if (err != 0) {
670 			printk("Could not configure source stream[%zu]: %d\n",
671 			       i, err);
672 			return err;
673 		}
674 
675 		printk("Configured source stream[%zu]\n", i);
676 		configured_source_stream_count++;
677 	}
678 
679 	return 0;
680 }
681 
create_group(void)682 static int create_group(void)
683 {
684 	const size_t params_count = MAX(configured_sink_stream_count,
685 					configured_source_stream_count);
686 	struct bt_bap_unicast_group_stream_pair_param pair_params[params_count];
687 	struct bt_bap_unicast_group_stream_param stream_params[configured_stream_count];
688 	struct bt_bap_unicast_group_param param;
689 	int err;
690 
691 	for (size_t i = 0U; i < configured_stream_count; i++) {
692 		stream_params[i].stream = &streams[i];
693 		stream_params[i].qos = &codec_configuration.qos;
694 	}
695 
696 	for (size_t i = 0U; i < params_count; i++) {
697 		if (i < configured_sink_stream_count) {
698 			pair_params[i].tx_param = &stream_params[i];
699 		} else {
700 			pair_params[i].tx_param = NULL;
701 		}
702 
703 		if (i < configured_source_stream_count) {
704 			pair_params[i].rx_param = &stream_params[i + configured_sink_stream_count];
705 		} else {
706 			pair_params[i].rx_param = NULL;
707 		}
708 	}
709 
710 	param.params = pair_params;
711 	param.params_count = params_count;
712 	param.packing = BT_ISO_PACKING_SEQUENTIAL;
713 
714 	err = bt_bap_unicast_group_create(&param, &unicast_group);
715 	if (err != 0) {
716 		printk("Could not create unicast group (err %d)\n", err);
717 		return err;
718 	}
719 
720 	return 0;
721 }
722 
delete_group(void)723 static int delete_group(void)
724 {
725 	int err;
726 
727 	err = bt_bap_unicast_group_delete(unicast_group);
728 	if (err != 0) {
729 		printk("Could not create unicast group (err %d)\n", err);
730 		return err;
731 	}
732 
733 	return 0;
734 }
735 
set_stream_qos(void)736 static int set_stream_qos(void)
737 {
738 	int err;
739 
740 	err = bt_bap_stream_qos(default_conn, unicast_group);
741 	if (err != 0) {
742 		printk("Unable to setup QoS: %d\n", err);
743 		return err;
744 	}
745 
746 	for (size_t i = 0U; i < configured_stream_count; i++) {
747 		printk("QoS: waiting for %zu streams\n", configured_stream_count);
748 		err = k_sem_take(&sem_stream_qos, K_FOREVER);
749 		if (err != 0) {
750 			printk("failed to take sem_stream_qos (err %d)\n", err);
751 			return err;
752 		}
753 	}
754 
755 	return 0;
756 }
757 
enable_streams(void)758 static int enable_streams(void)
759 {
760 	for (size_t i = 0U; i < configured_stream_count; i++) {
761 		int err;
762 
763 		err = bt_bap_stream_enable(&streams[i], codec_configuration.codec_cfg.meta,
764 					   codec_configuration.codec_cfg.meta_len);
765 		if (err != 0) {
766 			printk("Unable to enable stream: %d\n", err);
767 			return err;
768 		}
769 
770 		err = k_sem_take(&sem_stream_enabled, K_FOREVER);
771 		if (err != 0) {
772 			printk("failed to take sem_stream_enabled (err %d)\n", err);
773 			return err;
774 		}
775 	}
776 
777 	return 0;
778 }
779 
connect_streams(void)780 static int connect_streams(void)
781 {
782 	for (size_t i = 0U; i < configured_stream_count; i++) {
783 		int err;
784 
785 		k_sem_reset(&sem_stream_connected);
786 
787 		err = bt_bap_stream_connect(&streams[i]);
788 		if (err == -EALREADY) {
789 			/* We have already connected a paired stream */
790 			continue;
791 		} else if (err != 0) {
792 			printk("Unable to start stream: %d\n", err);
793 			return err;
794 		}
795 
796 		err = k_sem_take(&sem_stream_connected, K_FOREVER);
797 		if (err != 0) {
798 			printk("failed to take sem_stream_connected (err %d)\n", err);
799 			return err;
800 		}
801 	}
802 
803 	return 0;
804 }
805 
stream_dir(const struct bt_bap_stream * stream)806 static enum bt_audio_dir stream_dir(const struct bt_bap_stream *stream)
807 {
808 	struct bt_bap_ep_info ep_info;
809 	int err;
810 
811 	err = bt_bap_ep_get_info(stream->ep, &ep_info);
812 	if (err != 0) {
813 		printk("Failed to get ep info for %p: %d\n", stream, err);
814 		__ASSERT_NO_MSG(false);
815 
816 		return 0;
817 	}
818 
819 	return ep_info.dir;
820 }
821 
start_streams(void)822 static int start_streams(void)
823 {
824 	for (size_t i = 0U; i < configured_stream_count; i++) {
825 		struct bt_bap_stream *stream = &streams[i];
826 		int err;
827 
828 		if (stream_dir(stream) == BT_AUDIO_DIR_SOURCE) {
829 			err = bt_bap_stream_start(&streams[i]);
830 			if (err != 0) {
831 				printk("Unable to start stream: %d\n", err);
832 				return err;
833 			}
834 		} /* Sink streams are started by the unicast server */
835 
836 		err = k_sem_take(&sem_stream_started, K_FOREVER);
837 		if (err != 0) {
838 			printk("failed to take sem_stream_started (err %d)\n", err);
839 			return err;
840 		}
841 	}
842 
843 	return 0;
844 }
845 
reset_data(void)846 static void reset_data(void)
847 {
848 	k_sem_reset(&sem_connected);
849 	k_sem_reset(&sem_disconnected);
850 	k_sem_reset(&sem_mtu_exchanged);
851 	k_sem_reset(&sem_security_updated);
852 	k_sem_reset(&sem_sinks_discovered);
853 	k_sem_reset(&sem_sources_discovered);
854 	k_sem_reset(&sem_stream_configured);
855 	k_sem_reset(&sem_stream_qos);
856 	k_sem_reset(&sem_stream_enabled);
857 	k_sem_reset(&sem_stream_started);
858 	k_sem_reset(&sem_stream_connected);
859 
860 	configured_sink_stream_count = 0;
861 	configured_source_stream_count = 0;
862 	memset(sinks, 0, sizeof(sinks));
863 	memset(sources, 0, sizeof(sources));
864 }
865 
main(void)866 int main(void)
867 {
868 	int err;
869 
870 	printk("Initializing\n");
871 	err = init();
872 	if (err != 0) {
873 		return 0;
874 	}
875 	printk("Initialized\n");
876 
877 	err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
878 	if (err != 0) {
879 		printk("Failed to register client callbacks: %d", err);
880 		return 0;
881 	}
882 
883 	while (true) {
884 		reset_data();
885 
886 		printk("Waiting for connection\n");
887 		err = scan_and_connect();
888 		if (err != 0) {
889 			return 0;
890 		}
891 		printk("Connected\n");
892 
893 		printk("Discovering sinks\n");
894 		err = discover_sinks();
895 		if (err != 0) {
896 			return 0;
897 		}
898 		printk("Sinks discovered\n");
899 
900 		printk("Discovering sources\n");
901 		err = discover_sources();
902 		if (err != 0) {
903 			return 0;
904 		}
905 		printk("Sources discovered\n");
906 
907 		printk("Configuring streams\n");
908 		err = configure_streams();
909 		if (err != 0) {
910 			return 0;
911 		}
912 
913 		if (configured_stream_count == 0U) {
914 			printk("No streams were configured\n");
915 			return 0;
916 		}
917 
918 		printk("Creating unicast group\n");
919 		err = create_group();
920 		if (err != 0) {
921 			return 0;
922 		}
923 		printk("Unicast group created\n");
924 
925 		printk("Setting stream QoS\n");
926 		err = set_stream_qos();
927 		if (err != 0) {
928 			return 0;
929 		}
930 		printk("Stream QoS Set\n");
931 
932 		printk("Enabling streams\n");
933 		err = enable_streams();
934 		if (err != 0) {
935 			return 0;
936 		}
937 		printk("Streams enabled\n");
938 
939 		printk("Connecting streams\n");
940 		err = connect_streams();
941 		if (err != 0) {
942 			return 0;
943 		}
944 		printk("Streams connected\n");
945 
946 		printk("Starting streams\n");
947 		err = start_streams();
948 		if (err != 0) {
949 			return 0;
950 		}
951 		printk("Streams started\n");
952 
953 		/* Wait for disconnect */
954 		err = k_sem_take(&sem_disconnected, K_FOREVER);
955 		if (err != 0) {
956 			printk("failed to take sem_disconnected (err %d)\n", err);
957 			return 0;
958 		}
959 
960 		printk("Deleting group\n");
961 		err = delete_group();
962 		if (err != 0) {
963 			return 0;
964 		}
965 		printk("Group deleted\n");
966 	}
967 }
968