1 /**
2  * @file
3  * @brief Shell APIs for Bluetooth CAP initiator
4  *
5  * Copyright (c) 2022-2023 Nordic Semiconductor ASA
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 
17 #include <zephyr/autoconf.h>
18 #include <zephyr/bluetooth/audio/audio.h>
19 #include <zephyr/bluetooth/audio/bap.h>
20 #include <zephyr/bluetooth/audio/csip.h>
21 #include <zephyr/bluetooth/crypto.h>
22 #include <zephyr/bluetooth/gap.h>
23 #include <zephyr/bluetooth/iso.h>
24 #include <zephyr/bluetooth/uuid.h>
25 #include <zephyr/net_buf.h>
26 #include <zephyr/shell/shell_string_conv.h>
27 #include <zephyr/sys/byteorder.h>
28 #include <zephyr/sys/printk.h>
29 #include <zephyr/sys/util.h>
30 #include <zephyr/types.h>
31 #include <zephyr/shell/shell.h>
32 #include <zephyr/bluetooth/conn.h>
33 #include <zephyr/bluetooth/gatt.h>
34 #include <zephyr/bluetooth/bluetooth.h>
35 #include <zephyr/bluetooth/audio/cap.h>
36 
37 #include "common/bt_shell_private.h"
38 #include "host/shell/bt.h"
39 #include "audio.h"
40 
41 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
42 #define UNICAST_SINK_SUPPORTED (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0)
43 #define UNICAST_SRC_SUPPORTED  (CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0)
44 
45 #define CAP_UNICAST_CLIENT_STREAM_COUNT ARRAY_SIZE(unicast_streams)
46 
cap_discover_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)47 static void cap_discover_cb(struct bt_conn *conn, int err,
48 			    const struct bt_csip_set_coordinator_set_member *member,
49 			    const struct bt_csip_set_coordinator_csis_inst *csis_inst)
50 {
51 	if (err != 0) {
52 		bt_shell_error("discover failed (%d)", err);
53 		return;
54 	}
55 
56 	bt_shell_print("discovery completed%s",
57 		       csis_inst == NULL ? "" : " with CSIS");
58 }
59 
cap_unicast_start_complete_cb(int err,struct bt_conn * conn)60 static void cap_unicast_start_complete_cb(int err, struct bt_conn *conn)
61 {
62 	if (err == -ECANCELED) {
63 		bt_shell_print("Unicast start was cancelled for conn %p", conn);
64 	} else if (err != 0) {
65 		bt_shell_error("Unicast start failed for conn %p (%d)", conn, err);
66 	} else {
67 		bt_shell_print("Unicast start completed");
68 	}
69 }
70 
unicast_update_complete_cb(int err,struct bt_conn * conn)71 static void unicast_update_complete_cb(int err, struct bt_conn *conn)
72 {
73 	if (err == -ECANCELED) {
74 		bt_shell_print("Unicast update was cancelled for conn %p", conn);
75 	} else if (err != 0) {
76 		bt_shell_error("Unicast update failed for conn %p (%d)", conn, err);
77 	} else {
78 		bt_shell_print("Unicast updated completed");
79 	}
80 }
81 
unicast_stop_complete_cb(int err,struct bt_conn * conn)82 static void unicast_stop_complete_cb(int err, struct bt_conn *conn)
83 {
84 	if (err == -ECANCELED) {
85 		bt_shell_print("Unicast stop was cancelled for conn %p", conn);
86 	} else if (err != 0) {
87 		bt_shell_error("Unicast stop failed for conn %p (%d)", conn, err);
88 	} else {
89 		bt_shell_print("Unicast stop completed");
90 
91 		if (default_unicast_group != NULL) {
92 			err = bt_bap_unicast_group_delete(default_unicast_group);
93 			if (err != 0) {
94 				bt_shell_error("Failed to delete unicast group %p: %d",
95 					       default_unicast_group, err);
96 			} else {
97 				default_unicast_group = NULL;
98 			}
99 		}
100 	}
101 }
102 
103 static struct bt_cap_initiator_cb cbs = {
104 	.unicast_discovery_complete = cap_discover_cb,
105 	.unicast_start_complete = cap_unicast_start_complete_cb,
106 	.unicast_update_complete = unicast_update_complete_cb,
107 	.unicast_stop_complete = unicast_stop_complete_cb,
108 };
109 
cmd_cap_initiator_discover(const struct shell * sh,size_t argc,char * argv[])110 static int cmd_cap_initiator_discover(const struct shell *sh, size_t argc,
111 				    char *argv[])
112 {
113 	static bool cbs_registered;
114 	int err;
115 
116 	if (default_conn == NULL) {
117 		shell_error(sh, "Not connected");
118 		return -ENOEXEC;
119 	}
120 
121 	if (!cbs_registered) {
122 		bt_cap_initiator_register_cb(&cbs);
123 		cbs_registered = true;
124 	}
125 
126 	err = bt_cap_initiator_unicast_discover(default_conn);
127 	if (err != 0) {
128 		shell_error(sh, "Fail: %d", err);
129 	}
130 
131 	return err;
132 }
133 
populate_connected_conns(struct bt_conn * conn,void * data)134 static void populate_connected_conns(struct bt_conn *conn, void *data)
135 {
136 	struct bt_conn **connected_conns = (struct bt_conn **)data;
137 
138 	for (int i = 0; i < CONFIG_BT_MAX_CONN; i++) {
139 		if (connected_conns[i] == NULL) {
140 			connected_conns[i] = conn;
141 			return;
142 		}
143 	}
144 }
145 
cmd_cap_initiator_unicast_start(const struct shell * sh,size_t argc,char * argv[])146 static int cmd_cap_initiator_unicast_start(const struct shell *sh, size_t argc,
147 					   char *argv[])
148 {
149 	struct bt_bap_unicast_group_stream_param
150 		group_stream_params[CAP_UNICAST_CLIENT_STREAM_COUNT] = {0};
151 	struct bt_bap_unicast_group_stream_pair_param
152 		pair_params[CAP_UNICAST_CLIENT_STREAM_COUNT] = {0};
153 	struct bt_cap_unicast_audio_start_stream_param
154 		stream_param[CAP_UNICAST_CLIENT_STREAM_COUNT] = {0};
155 	struct bt_conn *connected_conns[CONFIG_BT_MAX_CONN] = {0};
156 	struct bt_cap_unicast_audio_start_param start_param = {0};
157 	struct bt_bap_unicast_group_param group_param = {0};
158 	size_t source_cnt = 1U;
159 	ssize_t conn_cnt = 1U;
160 	size_t sink_cnt = 1U;
161 	size_t pair_cnt = 0U;
162 	int err = 0;
163 
164 	if (default_conn == NULL) {
165 		shell_error(sh, "Not connected");
166 		return -ENOEXEC;
167 	}
168 
169 	start_param.type = BT_CAP_SET_TYPE_AD_HOC;
170 
171 	for (size_t argn = 1; argn < argc; argn++) {
172 		const char *arg = argv[argn];
173 
174 		if (strcmp(arg, "csip") == 0) {
175 			start_param.type = BT_CAP_SET_TYPE_CSIP;
176 		} else if (strcmp(arg, "sinks") == 0) {
177 			if (++argn == argc) {
178 				shell_help(sh);
179 
180 				return SHELL_CMD_HELP_PRINTED;
181 			}
182 
183 			sink_cnt = shell_strtoul(argv[argn], 10, &err);
184 		} else if (strcmp(arg, "sources") == 0) {
185 			if (++argn == argc) {
186 				shell_help(sh);
187 
188 				return SHELL_CMD_HELP_PRINTED;
189 			}
190 
191 			source_cnt = shell_strtoul(argv[argn], 10, &err);
192 		} else if (strcmp(arg, "conns") == 0) {
193 			if (++argn == argc) {
194 				shell_help(sh);
195 
196 				return SHELL_CMD_HELP_PRINTED;
197 			}
198 
199 			if (strcmp(argv[argn], "all") == 0) {
200 				conn_cnt = CONFIG_BT_MAX_CONN;
201 			} else {
202 				conn_cnt = shell_strtoul(argv[argn], 10, &err);
203 
204 				/* Ensure that we do not iterate over more conns
205 				 * than the array supports
206 				 */
207 				conn_cnt = MIN(conn_cnt, ARRAY_SIZE(connected_conns));
208 			}
209 		} else {
210 			shell_help(sh);
211 
212 			return SHELL_CMD_HELP_PRINTED;
213 		}
214 
215 		if (err != 0) {
216 			shell_error(sh, "Failed to parse argument: %s: %s (%d)",
217 				    arg, argv[argn], err);
218 
219 			return err;
220 		}
221 	}
222 
223 	shell_print(sh, "Setting up %u sinks and %u sources on each (%u) conn", sink_cnt,
224 		    source_cnt, conn_cnt);
225 
226 	/* Populate the array of connected connections */
227 	(void)memset(connected_conns, 0, sizeof(connected_conns));
228 	bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns,
229 			(void *)connected_conns);
230 
231 	start_param.count = 0U;
232 	start_param.stream_params = stream_param;
233 	for (size_t i = 0; i < conn_cnt; i++) {
234 		struct bt_conn *conn = connected_conns[i];
235 		size_t conn_src_cnt = 0U;
236 		size_t conn_snk_cnt = 0U;
237 
238 		if (conn == NULL) {
239 			break;
240 		}
241 
242 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
243 		conn_snk_cnt = sink_cnt;
244 		for (size_t j = 0U; j < sink_cnt; j++) {
245 			struct bt_cap_stream *stream =
246 				&unicast_streams[start_param.count].stream;
247 			struct shell_stream *uni_stream =
248 				CONTAINER_OF(stream, struct shell_stream, stream);
249 			struct bt_bap_ep *snk_ep = snks[bt_conn_index(conn)][j];
250 
251 			if (snk_ep == NULL) {
252 				shell_info(sh, "Could only setup %zu/%zu sink endpoints",
253 					   j, sink_cnt);
254 				conn_snk_cnt = j;
255 				break;
256 			}
257 
258 			stream_param[start_param.count].member.member = conn;
259 			stream_param[start_param.count].stream = stream;
260 			stream_param[start_param.count].ep = snk_ep;
261 			copy_unicast_stream_preset(uni_stream, &default_sink_preset);
262 			stream_param[start_param.count].codec_cfg = &uni_stream->codec_cfg;
263 
264 			group_stream_params[start_param.count].stream =
265 				&stream_param[start_param.count].stream->bap_stream;
266 			group_stream_params[start_param.count].qos = &uni_stream->qos;
267 			pair_params[pair_cnt + j].tx_param =
268 				&group_stream_params[start_param.count];
269 
270 			start_param.count++;
271 		}
272 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
273 
274 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
275 		conn_src_cnt = source_cnt;
276 		for (size_t j = 0U; j < source_cnt; j++) {
277 			struct bt_cap_stream *stream =
278 				&unicast_streams[start_param.count].stream;
279 			struct shell_stream *uni_stream =
280 				CONTAINER_OF(stream, struct shell_stream, stream);
281 			struct bt_bap_ep *src_ep = srcs[bt_conn_index(conn)][j];
282 
283 			if (src_ep == NULL) {
284 				shell_info(sh, "Could only setup %zu/%zu source endpoints",
285 					   j, source_cnt);
286 				conn_src_cnt = j;
287 				break;
288 			}
289 
290 			stream_param[start_param.count].member.member = conn;
291 			stream_param[start_param.count].stream = stream;
292 			stream_param[start_param.count].ep = src_ep;
293 			copy_unicast_stream_preset(uni_stream, &default_source_preset);
294 			stream_param[start_param.count].codec_cfg = &uni_stream->codec_cfg;
295 			group_stream_params[start_param.count].stream =
296 				&stream_param[start_param.count].stream->bap_stream;
297 			group_stream_params[start_param.count].qos = &uni_stream->qos;
298 			pair_params[pair_cnt + j].rx_param =
299 				&group_stream_params[start_param.count];
300 
301 			start_param.count++;
302 		}
303 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
304 
305 		/* Increment pair count with the max of sink and source for this connection, as
306 		 * we cannot have pairs across connections
307 		 */
308 		pair_cnt += MAX(conn_snk_cnt, conn_src_cnt);
309 	}
310 
311 	if (pair_cnt == 0U) {
312 		shell_error(sh, "No streams to setup");
313 
314 		return -ENOEXEC;
315 	}
316 
317 	group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
318 	group_param.params_count = pair_cnt;
319 	group_param.params = pair_params;
320 
321 	if (default_unicast_group == NULL) {
322 		err = bt_bap_unicast_group_create(&group_param, &default_unicast_group);
323 		if (err != 0) {
324 			shell_print(sh, "Failed to create group: %d", err);
325 
326 			return -ENOEXEC;
327 		}
328 	}
329 
330 	shell_print(sh, "Starting %zu streams", start_param.count);
331 
332 	err = bt_cap_initiator_unicast_audio_start(&start_param);
333 	if (err != 0) {
334 		shell_print(sh, "Failed to start unicast audio: %d", err);
335 
336 		return -ENOEXEC;
337 	}
338 
339 	return 0;
340 }
341 
cmd_cap_initiator_unicast_list(const struct shell * sh,size_t argc,char * argv[])342 static int cmd_cap_initiator_unicast_list(const struct shell *sh, size_t argc,
343 					  char *argv[])
344 {
345 	for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
346 		if (unicast_streams[i].stream.bap_stream.conn == NULL) {
347 			break;
348 		}
349 
350 		shell_print(sh, "Stream #%zu: %p", i, &unicast_streams[i].stream);
351 	}
352 	return 0;
353 }
354 
cmd_cap_initiator_unicast_update(const struct shell * sh,size_t argc,char * argv[])355 static int cmd_cap_initiator_unicast_update(const struct shell *sh, size_t argc,
356 					    char *argv[])
357 {
358 	struct bt_cap_unicast_audio_update_stream_param
359 		stream_params[CAP_UNICAST_CLIENT_STREAM_COUNT] = {0};
360 	struct bt_cap_unicast_audio_update_param param = {0};
361 	int err = 0;
362 
363 	if (default_conn == NULL) {
364 		shell_error(sh, "Not connected");
365 		return -ENOEXEC;
366 	}
367 
368 	if (argc == 2 && strcmp(argv[1], "all") == 0) {
369 		for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
370 			struct bt_cap_stream *stream = &unicast_streams[i].stream;
371 			struct shell_stream *uni_stream =
372 				CONTAINER_OF(stream, struct shell_stream, stream);
373 			struct bt_bap_ep_info ep_info;
374 
375 			if (stream->bap_stream.conn == NULL) {
376 				break;
377 			}
378 
379 			err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info);
380 			if (err != 0) {
381 				shell_error(sh, "Failed to get endpoint info: %d", err);
382 
383 				return -ENOEXEC;
384 			}
385 
386 			stream_params[param.count].stream = stream;
387 
388 			if (ep_info.dir == BT_AUDIO_DIR_SINK) {
389 				copy_unicast_stream_preset(uni_stream, &default_sink_preset);
390 			} else {
391 				copy_unicast_stream_preset(uni_stream, &default_source_preset);
392 			}
393 
394 			stream_params[param.count].meta = uni_stream->codec_cfg.meta;
395 			stream_params[param.count].meta_len = uni_stream->codec_cfg.meta_len;
396 
397 			param.count++;
398 		}
399 
400 	} else {
401 		for (size_t i = 1U; i < argc; i++) {
402 			struct bt_cap_stream *stream = (void *)shell_strtoul(argv[i], 16, &err);
403 			struct shell_stream *uni_stream =
404 				CONTAINER_OF(stream, struct shell_stream, stream);
405 			struct bt_bap_ep_info ep_info;
406 
407 			if (err != 0) {
408 				shell_error(sh, "Failed to parse stream argument %s: %d",
409 					argv[i], err);
410 
411 				return err;
412 			}
413 
414 			if (!PART_OF_ARRAY(unicast_streams, stream)) {
415 				shell_error(sh, "Pointer %p is not a CAP stream pointer",
416 					stream);
417 
418 				return -ENOEXEC;
419 			}
420 
421 			err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info);
422 			if (err != 0) {
423 				shell_error(sh, "Failed to get endpoint info: %d", err);
424 
425 				return -ENOEXEC;
426 			}
427 
428 			stream_params[param.count].stream = stream;
429 
430 			if (ep_info.dir == BT_AUDIO_DIR_SINK) {
431 				copy_unicast_stream_preset(uni_stream, &default_sink_preset);
432 			} else {
433 				copy_unicast_stream_preset(uni_stream, &default_source_preset);
434 			}
435 
436 			stream_params[param.count].meta = uni_stream->codec_cfg.meta;
437 			stream_params[param.count].meta_len = uni_stream->codec_cfg.meta_len;
438 
439 			param.count++;
440 		}
441 	}
442 
443 	if (param.count == 0) {
444 		shell_error(sh, "No streams to update");
445 
446 		return -ENOEXEC;
447 	}
448 
449 	param.stream_params = stream_params;
450 	param.type = BT_CAP_SET_TYPE_AD_HOC;
451 
452 	shell_print(sh, "Updating %zu streams", param.count);
453 
454 	err = bt_cap_initiator_unicast_audio_update(&param);
455 	if (err != 0) {
456 		shell_print(sh, "Failed to update unicast audio: %d", err);
457 	}
458 
459 	return err;
460 }
461 
cmd_cap_initiator_unicast_stop(const struct shell * sh,size_t argc,char * argv[])462 static int cmd_cap_initiator_unicast_stop(const struct shell *sh, size_t argc,
463 					  char *argv[])
464 {
465 	struct bt_cap_stream *streams[CAP_UNICAST_CLIENT_STREAM_COUNT];
466 	struct bt_cap_unicast_audio_stop_param param = {0};
467 	int err = 0;
468 
469 	if (default_conn == NULL) {
470 		shell_error(sh, "Not connected");
471 		return -ENOEXEC;
472 	}
473 
474 	if (argc == 1) {
475 		for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
476 			struct bt_cap_stream *stream = &unicast_streams[i].stream;
477 			struct bt_bap_ep_info ep_info;
478 
479 			if (stream->bap_stream.conn == NULL) {
480 				break;
481 			}
482 
483 			err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info);
484 			if (err != 0) {
485 				shell_error(sh, "Failed to get endpoint info: %d", err);
486 
487 				return -ENOEXEC;
488 			}
489 
490 			streams[param.count] = stream;
491 			param.count++;
492 		}
493 
494 	} else {
495 		for (size_t i = 1U; i < argc; i++) {
496 			struct bt_cap_stream *stream = (void *)shell_strtoul(argv[i], 16, &err);
497 			struct bt_bap_ep_info ep_info;
498 
499 			if (err != 0) {
500 				shell_error(sh, "Failed to parse stream argument %s: %d", argv[i],
501 					    err);
502 
503 				return err;
504 			}
505 
506 			if (!PART_OF_ARRAY(unicast_streams, stream)) {
507 				shell_error(sh, "Pointer %p is not a CAP stream pointer", stream);
508 
509 				return -ENOEXEC;
510 			}
511 
512 			err = bt_bap_ep_get_info(stream->bap_stream.ep, &ep_info);
513 			if (err != 0) {
514 				shell_error(sh, "Failed to get endpoint info: %d", err);
515 
516 				return -ENOEXEC;
517 			}
518 
519 			streams[param.count] = stream;
520 			param.count++;
521 		}
522 	}
523 
524 	if (param.count == 0) {
525 		shell_error(sh, "No streams to update");
526 
527 		return -ENOEXEC;
528 	}
529 
530 	param.streams = streams;
531 	param.type = BT_CAP_SET_TYPE_AD_HOC;
532 	param.release = true;
533 
534 	err = bt_cap_initiator_unicast_audio_stop(&param);
535 	if (err != 0) {
536 		shell_print(sh, "Failed to update unicast audio: %d", err);
537 	}
538 
539 	return err;
540 }
541 
cmd_cap_initiator_unicast_cancel(const struct shell * sh,size_t argc,char * argv[])542 static int cmd_cap_initiator_unicast_cancel(const struct shell *sh, size_t argc, char *argv[])
543 {
544 	int err = 0;
545 
546 	err = bt_cap_initiator_unicast_audio_cancel();
547 	if (err != 0) {
548 		shell_print(sh, "Failed to cancel unicast audio procedure: %d", err);
549 		return -ENOEXEC;
550 	}
551 
552 	return 0;
553 }
554 
cap_ac_unicast_start(const struct bap_unicast_ac_param * param,struct bt_conn * connected_conns[],struct shell_stream * snk_uni_streams[],size_t snk_cnt,struct shell_stream * src_uni_streams[],size_t src_cnt)555 static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param,
556 				struct bt_conn *connected_conns[],
557 				struct shell_stream *snk_uni_streams[], size_t snk_cnt,
558 				struct shell_stream *src_uni_streams[], size_t src_cnt)
559 {
560 	struct bt_cap_unicast_audio_start_stream_param stream_params[BAP_UNICAST_AC_MAX_STREAM] = {
561 		0};
562 	struct bt_audio_codec_cfg *snk_codec_cfgs[BAP_UNICAST_AC_MAX_SNK] = {0};
563 	struct bt_audio_codec_cfg *src_codec_cfgs[BAP_UNICAST_AC_MAX_SRC] = {0};
564 	struct bt_cap_stream *snk_cap_streams[BAP_UNICAST_AC_MAX_SNK] = {0};
565 	struct bt_cap_stream *src_cap_streams[BAP_UNICAST_AC_MAX_SRC] = {0};
566 	struct bt_cap_unicast_audio_start_param start_param = {0};
567 	struct bt_bap_ep *snk_eps[BAP_UNICAST_AC_MAX_SNK] = {0};
568 	struct bt_bap_ep *src_eps[BAP_UNICAST_AC_MAX_SRC] = {0};
569 	size_t snk_stream_cnt = 0U;
570 	size_t src_stream_cnt = 0U;
571 	size_t stream_cnt = 0U;
572 	size_t snk_ep_cnt = 0U;
573 	size_t src_ep_cnt = 0U;
574 
575 	for (size_t i = 0U; i < param->conn_cnt; i++) {
576 #if UNICAST_SINK_SUPPORTED
577 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
578 			snk_eps[snk_ep_cnt] = snks[bt_conn_index(connected_conns[i])][j];
579 			if (snk_eps[snk_ep_cnt] == NULL) {
580 				bt_shell_error("No sink[%zu][%zu] endpoint available", i, j);
581 
582 				return -ENOEXEC;
583 			}
584 			snk_ep_cnt++;
585 		}
586 #endif /* UNICAST_SINK_SUPPORTED */
587 
588 #if UNICAST_SRC_SUPPORTED
589 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
590 			src_eps[src_ep_cnt] = srcs[bt_conn_index(connected_conns[i])][j];
591 			if (src_eps[src_ep_cnt] == NULL) {
592 				bt_shell_error("No source[%zu][%zu] endpoint available", i, j);
593 
594 				return -ENOEXEC;
595 			}
596 			src_ep_cnt++;
597 		}
598 #endif /* UNICAST_SRC_SUPPORTED  */
599 	}
600 
601 	if (snk_ep_cnt != snk_cnt) {
602 		bt_shell_error("Sink endpoint and stream count mismatch: %zu != %zu",
603 			       snk_ep_cnt, snk_cnt);
604 
605 		return -ENOEXEC;
606 	}
607 
608 	if (src_ep_cnt != src_cnt) {
609 		bt_shell_error("Source  endpoint and stream count mismatch: %zu != %zu",
610 			       src_ep_cnt, src_cnt);
611 
612 		return -ENOEXEC;
613 	}
614 
615 	/* Setup arrays of parameters based on the preset for easier access. This also copies the
616 	 * preset so that we can modify them (e.g. update the metadata)
617 	 */
618 	for (size_t i = 0U; i < snk_cnt; i++) {
619 		snk_cap_streams[i] = &snk_uni_streams[i]->stream;
620 		snk_codec_cfgs[i] = &snk_uni_streams[i]->codec_cfg;
621 	}
622 
623 	for (size_t i = 0U; i < src_cnt; i++) {
624 		src_cap_streams[i] = &src_uni_streams[i]->stream;
625 		src_codec_cfgs[i] = &src_uni_streams[i]->codec_cfg;
626 	}
627 
628 	/* CAP Start */
629 	for (size_t i = 0U; i < param->conn_cnt; i++) {
630 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
631 			struct bt_cap_unicast_audio_start_stream_param *stream_param =
632 				&stream_params[stream_cnt];
633 
634 			stream_param->member.member = connected_conns[i];
635 			stream_param->codec_cfg = snk_codec_cfgs[snk_stream_cnt];
636 			stream_param->ep = snk_eps[snk_stream_cnt];
637 			stream_param->stream = snk_cap_streams[snk_stream_cnt];
638 
639 			snk_stream_cnt++;
640 			stream_cnt++;
641 		}
642 
643 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
644 			struct bt_cap_unicast_audio_start_stream_param *stream_param =
645 				&stream_params[stream_cnt];
646 
647 			stream_param->member.member = connected_conns[i];
648 			stream_param->codec_cfg = src_codec_cfgs[src_stream_cnt];
649 			stream_param->ep = src_eps[src_stream_cnt];
650 			stream_param->stream = src_cap_streams[src_stream_cnt];
651 
652 			src_stream_cnt++;
653 			stream_cnt++;
654 		}
655 	}
656 
657 	start_param.stream_params = stream_params;
658 	start_param.count = stream_cnt;
659 	start_param.type = BT_CAP_SET_TYPE_AD_HOC;
660 
661 	return bt_cap_initiator_unicast_audio_start(&start_param);
662 }
663 
set_codec_config(const struct shell * sh,struct shell_stream * sh_stream,struct named_lc3_preset * preset,size_t conn_cnt,size_t ep_cnt,size_t chan_cnt,size_t conn_index,size_t ep_index)664 static int set_codec_config(const struct shell *sh, struct shell_stream *sh_stream,
665 			    struct named_lc3_preset *preset, size_t conn_cnt, size_t ep_cnt,
666 			    size_t chan_cnt, size_t conn_index, size_t ep_index)
667 {
668 	enum bt_audio_location new_chan_alloc;
669 	enum bt_audio_location chan_alloc;
670 	int err;
671 
672 	copy_unicast_stream_preset(sh_stream, preset);
673 
674 	if (chan_cnt == 1U) {
675 		/* - When we have a single channel on a single connection then we make it mono
676 		 * - When we have a single channel on a multiple connections then we make it left on
677 		 *   the first connection and right on the second connection
678 		 * - When we have multiple channels streams for a connection, we make them either
679 		 *   left or right, regardless of the connection count
680 		 */
681 		if (ep_cnt == 1) {
682 			if (conn_cnt == 1) {
683 				new_chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
684 			} else if (conn_cnt == 2) {
685 				if (conn_index == 0) {
686 					new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
687 				} else if (conn_index == 1) {
688 					new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
689 				} else {
690 					return 0;
691 				}
692 			} else {
693 				return 0;
694 			}
695 		} else if (ep_cnt == 2) {
696 			if (ep_index == 0) {
697 				new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
698 			} else if (ep_index == 1) {
699 				new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
700 			} else {
701 				return 0;
702 			}
703 		} else {
704 			return 0;
705 		}
706 	} else if (chan_cnt == 2U) {
707 		/* Some audio configuration requires multiple sink channels,
708 		 * so multiply the SDU based on the channel count
709 		 */
710 		sh_stream->qos.sdu *= chan_cnt;
711 
712 		/* If a stream has 2 channels, we make it stereo */
713 		new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
714 
715 	} else {
716 		return 0;
717 	}
718 
719 	err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc, false);
720 	if (err != 0) {
721 		if (err == -ENODATA) {
722 			chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
723 		}
724 	}
725 
726 	if (chan_alloc != new_chan_alloc) {
727 		shell_info(sh,
728 			   "[%zu][%zu]: Overwriting existing channel allocation 0x%08X with 0x%08X",
729 			   conn_index, ep_index, chan_alloc, new_chan_alloc);
730 
731 		err = bt_audio_codec_cfg_set_chan_allocation(&sh_stream->codec_cfg, new_chan_alloc);
732 		if (err < 0) {
733 			return err;
734 		}
735 	}
736 
737 	return 0;
738 }
739 
cap_ac_unicast(const struct shell * sh,const struct bap_unicast_ac_param * param)740 int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *param)
741 {
742 	/* Allocate params large enough for any params, but only use what is required */
743 	struct bt_conn *connected_conns[BAP_UNICAST_AC_MAX_CONN] = {0};
744 	struct shell_stream *snk_uni_streams[BAP_UNICAST_AC_MAX_SNK];
745 	struct shell_stream *src_uni_streams[BAP_UNICAST_AC_MAX_SRC];
746 	size_t conn_avail_cnt;
747 	size_t snk_cnt = 0;
748 	size_t src_cnt = 0;
749 	int err;
750 
751 	if (default_unicast_group != NULL) {
752 		shell_error(sh, "Unicast Group already exist, please delete first");
753 		return -ENOEXEC;
754 	}
755 
756 	if (param->conn_cnt > BAP_UNICAST_AC_MAX_CONN) {
757 		shell_error(sh, "Invalid conn_cnt: %zu", param->conn_cnt);
758 		return -ENOEXEC;
759 	}
760 
761 	for (size_t i = 0; i < param->conn_cnt; i++) {
762 		/* Verify conn values */
763 		if (param->snk_cnt[i] > BAP_UNICAST_AC_MAX_SNK) {
764 			shell_error(sh, "Invalid conn_snk_cnt[%zu]: %zu", i, param->snk_cnt[i]);
765 			return -ENOEXEC;
766 		}
767 
768 		if (param->src_cnt[i] > BAP_UNICAST_AC_MAX_SRC) {
769 			shell_error(sh, "Invalid conn_src_cnt[%zu]: %zu", i, param->src_cnt[i]);
770 			return -ENOEXEC;
771 		}
772 	}
773 
774 	/* Populate the array of connected connections */
775 	bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns, (void *)connected_conns);
776 	for (conn_avail_cnt = 0; conn_avail_cnt < ARRAY_SIZE(connected_conns); conn_avail_cnt++) {
777 		if (connected_conns[conn_avail_cnt] == NULL) {
778 			break;
779 		}
780 	}
781 
782 	if (conn_avail_cnt < param->conn_cnt) {
783 		shell_error(sh,
784 			    "Only %zu/%u connected devices, please connect additional devices for "
785 			    "this audio configuration",
786 			    conn_avail_cnt, param->conn_cnt);
787 		return -ENOEXEC;
788 	}
789 
790 	/* Set all endpoints from multiple connections in a single array, and verify that the known
791 	 * endpoints matches the audio configuration
792 	 */
793 	for (size_t i = 0U; i < param->conn_cnt; i++) {
794 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
795 			struct shell_stream *snk_uni_stream;
796 
797 			snk_uni_stream = snk_uni_streams[snk_cnt] = &unicast_streams[snk_cnt];
798 
799 			err = set_codec_config(sh, snk_uni_stream, &default_sink_preset,
800 					       param->conn_cnt, param->snk_cnt[i],
801 					       param->snk_chan_cnt, i, j);
802 			if (err != 0) {
803 				shell_error(sh, "Failed to set codec configuration: %d", err);
804 
805 				return -ENOEXEC;
806 			}
807 
808 			snk_cnt++;
809 		}
810 
811 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
812 			struct shell_stream *src_uni_stream;
813 
814 			src_uni_stream = snk_uni_streams[src_cnt] = &unicast_streams[src_cnt];
815 
816 			err = set_codec_config(sh, src_uni_stream, &default_source_preset,
817 					       param->conn_cnt, param->src_cnt[i],
818 					       param->src_chan_cnt, i, j);
819 			if (err != 0) {
820 				shell_error(sh, "Failed to set codec configuration: %d", err);
821 
822 				return -ENOEXEC;
823 			}
824 
825 			src_cnt++;
826 		}
827 	}
828 
829 	err = bap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams,
830 					  src_cnt);
831 	if (err != 0) {
832 		shell_error(sh, "Failed to create group: %d", err);
833 
834 		return -ENOEXEC;
835 	}
836 
837 	shell_print(sh, "Starting %zu streams for %s", snk_cnt + src_cnt, param->name);
838 	err = cap_ac_unicast_start(param, connected_conns, snk_uni_streams, snk_cnt,
839 				   src_uni_streams, src_cnt);
840 	if (err != 0) {
841 		shell_error(sh, "Failed to start unicast audio: %d", err);
842 
843 		err = bt_bap_unicast_group_delete(default_unicast_group);
844 		if (err != 0) {
845 			shell_error(sh, "Failed to delete group: %d", err);
846 		} else {
847 			default_unicast_group = NULL;
848 		}
849 
850 		return -ENOEXEC;
851 	}
852 
853 	return 0;
854 }
855 
856 #if UNICAST_SINK_SUPPORTED
cmd_cap_ac_1(const struct shell * sh,size_t argc,char ** argv)857 static int cmd_cap_ac_1(const struct shell *sh, size_t argc, char **argv)
858 {
859 	const struct bap_unicast_ac_param param = {
860 		.name = "AC_1",
861 		.conn_cnt = 1U,
862 		.snk_cnt = {1U},
863 		.src_cnt = {0U},
864 		.snk_chan_cnt = 1U,
865 		.src_chan_cnt = 0U,
866 	};
867 
868 	return cap_ac_unicast(sh, &param);
869 }
870 #endif /* UNICAST_SINK_SUPPORTED */
871 
872 #if UNICAST_SRC_SUPPORTED
cmd_cap_ac_2(const struct shell * sh,size_t argc,char ** argv)873 static int cmd_cap_ac_2(const struct shell *sh, size_t argc, char **argv)
874 {
875 	const struct bap_unicast_ac_param param = {
876 		.name = "AC_2",
877 		.conn_cnt = 1U,
878 		.snk_cnt = {0U},
879 		.src_cnt = {1U},
880 		.snk_chan_cnt = 0U,
881 		.src_chan_cnt = 1U,
882 	};
883 
884 	return cap_ac_unicast(sh, &param);
885 }
886 #endif /* UNICAST_SRC_SUPPORTED */
887 
888 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_3(const struct shell * sh,size_t argc,char ** argv)889 static int cmd_cap_ac_3(const struct shell *sh, size_t argc, char **argv)
890 {
891 	const struct bap_unicast_ac_param param = {
892 		.name = "AC_3",
893 		.conn_cnt = 1U,
894 		.snk_cnt = {1U},
895 		.src_cnt = {1U},
896 		.snk_chan_cnt = 1U,
897 		.src_chan_cnt = 1U,
898 	};
899 
900 	return cap_ac_unicast(sh, &param);
901 }
902 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
903 
904 #if UNICAST_SINK_SUPPORTED
cmd_cap_ac_4(const struct shell * sh,size_t argc,char ** argv)905 static int cmd_cap_ac_4(const struct shell *sh, size_t argc, char **argv)
906 {
907 	const struct bap_unicast_ac_param param = {
908 		.name = "AC_4",
909 		.conn_cnt = 1,
910 		.snk_cnt = {1U},
911 		.src_cnt = {0U},
912 		.snk_chan_cnt = 2U,
913 		.src_chan_cnt = 0U,
914 	};
915 
916 	return cap_ac_unicast(sh, &param);
917 }
918 #endif /* UNICAST_SINK_SUPPORTED */
919 
920 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_5(const struct shell * sh,size_t argc,char ** argv)921 static int cmd_cap_ac_5(const struct shell *sh, size_t argc, char **argv)
922 {
923 	const struct bap_unicast_ac_param param = {
924 		.name = "AC_5",
925 		.conn_cnt = 1U,
926 		.snk_cnt = {1U},
927 		.src_cnt = {1U},
928 		.snk_chan_cnt = 2U,
929 		.src_chan_cnt = 1U,
930 	};
931 
932 	return cap_ac_unicast(sh, &param);
933 }
934 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
935 
936 #if UNICAST_SINK_SUPPORTED
937 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
cmd_cap_ac_6_i(const struct shell * sh,size_t argc,char ** argv)938 static int cmd_cap_ac_6_i(const struct shell *sh, size_t argc, char **argv)
939 {
940 	const struct bap_unicast_ac_param param = {
941 		.name = "AC_6_I",
942 		.conn_cnt = 1U,
943 		.snk_cnt = {2U},
944 		.src_cnt = {0U},
945 		.snk_chan_cnt = 1U,
946 		.src_chan_cnt = 0U,
947 	};
948 
949 	return cap_ac_unicast(sh, &param);
950 }
951 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
952 
953 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_6_ii(const struct shell * sh,size_t argc,char ** argv)954 static int cmd_cap_ac_6_ii(const struct shell *sh, size_t argc, char **argv)
955 {
956 	const struct bap_unicast_ac_param param = {
957 		.name = "AC_6_II",
958 		.conn_cnt = 2U,
959 		.snk_cnt = {1U, 1U},
960 		.src_cnt = {0U, 0U},
961 		.snk_chan_cnt = 1U,
962 		.src_chan_cnt = 0U,
963 	};
964 
965 	return cap_ac_unicast(sh, &param);
966 }
967 #endif /* CONFIG_BT_MAX_CONN >= 2 */
968 #endif /* UNICAST_SINK_SUPPORTED */
969 
970 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_7_i(const struct shell * sh,size_t argc,char ** argv)971 static int cmd_cap_ac_7_i(const struct shell *sh, size_t argc, char **argv)
972 {
973 	const struct bap_unicast_ac_param param = {
974 		.name = "AC_7_I",
975 		.conn_cnt = 1U,
976 		.snk_cnt = {1U}, /* TODO: These should be separate CIS */
977 		.src_cnt = {1U}, /* TODO: These should be separate CIS */
978 		.snk_chan_cnt = 1U,
979 		.src_chan_cnt = 1U,
980 	};
981 
982 	return cap_ac_unicast(sh, &param);
983 }
984 
985 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_7_ii(const struct shell * sh,size_t argc,char ** argv)986 static int cmd_cap_ac_7_ii(const struct shell *sh, size_t argc, char **argv)
987 {
988 	const struct bap_unicast_ac_param param = {
989 		.name = "AC_7_II",
990 		.conn_cnt = 2U,
991 		.snk_cnt = {1U, 0U},
992 		.src_cnt = {0U, 1U},
993 		.snk_chan_cnt = 1U,
994 		.src_chan_cnt = 1U,
995 	};
996 
997 	return cap_ac_unicast(sh, &param);
998 }
999 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1000 
1001 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
cmd_cap_ac_8_i(const struct shell * sh,size_t argc,char ** argv)1002 static int cmd_cap_ac_8_i(const struct shell *sh, size_t argc, char **argv)
1003 {
1004 	const struct bap_unicast_ac_param param = {
1005 		.name = "AC_8_I",
1006 		.conn_cnt = 1U,
1007 		.snk_cnt = {2U},
1008 		.src_cnt = {1U},
1009 		.snk_chan_cnt = 1U,
1010 		.src_chan_cnt = 1U,
1011 	};
1012 
1013 	return cap_ac_unicast(sh, &param);
1014 }
1015 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1016 
1017 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_8_ii(const struct shell * sh,size_t argc,char ** argv)1018 static int cmd_cap_ac_8_ii(const struct shell *sh, size_t argc, char **argv)
1019 {
1020 	const struct bap_unicast_ac_param param = {
1021 		.name = "AC_8_II",
1022 		.conn_cnt = 2U,
1023 		.snk_cnt = {1U, 1U},
1024 		.src_cnt = {1U, 0U},
1025 		.snk_chan_cnt = 1U,
1026 		.src_chan_cnt = 1U,
1027 	};
1028 
1029 	return cap_ac_unicast(sh, &param);
1030 }
1031 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1032 
1033 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_9_i(const struct shell * sh,size_t argc,char ** argv)1034 static int cmd_cap_ac_9_i(const struct shell *sh, size_t argc, char **argv)
1035 {
1036 	const struct bap_unicast_ac_param param = {
1037 		.name = "AC_9_I",
1038 		.conn_cnt = 1U,
1039 		.snk_cnt = {0U},
1040 		.src_cnt = {2U},
1041 		.snk_chan_cnt = 0U,
1042 		.src_chan_cnt = 1U,
1043 	};
1044 
1045 	return cap_ac_unicast(sh, &param);
1046 }
1047 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1048 
1049 #if CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_9_ii(const struct shell * sh,size_t argc,char ** argv)1050 static int cmd_cap_ac_9_ii(const struct shell *sh, size_t argc, char **argv)
1051 {
1052 	const struct bap_unicast_ac_param param = {
1053 		.name = "AC_9_II",
1054 		.conn_cnt = 2U,
1055 		.snk_cnt = {0U, 0U},
1056 		.src_cnt = {1U, 1U},
1057 		.snk_chan_cnt = 0U,
1058 		.src_chan_cnt = 1U,
1059 	};
1060 
1061 	return cap_ac_unicast(sh, &param);
1062 }
1063 #endif /* CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1064 
1065 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_10(const struct shell * sh,size_t argc,char ** argv)1066 static int cmd_cap_ac_10(const struct shell *sh, size_t argc, char **argv)
1067 {
1068 	const struct bap_unicast_ac_param param = {
1069 		.name = "AC_10",
1070 		.conn_cnt = 1U,
1071 		.snk_cnt = {0U},
1072 		.src_cnt = {1U},
1073 		.snk_chan_cnt = 0U,
1074 		.src_chan_cnt = 2U,
1075 	};
1076 
1077 	return cap_ac_unicast(sh, &param);
1078 }
1079 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1080 
1081 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_11_i(const struct shell * sh,size_t argc,char ** argv)1082 static int cmd_cap_ac_11_i(const struct shell *sh, size_t argc, char **argv)
1083 {
1084 	const struct bap_unicast_ac_param param = {
1085 		.name = "AC_11_I",
1086 		.conn_cnt = 1U,
1087 		.snk_cnt = {2U},
1088 		.src_cnt = {2U},
1089 		.snk_chan_cnt = 1U,
1090 		.src_chan_cnt = 1U,
1091 	};
1092 
1093 	return cap_ac_unicast(sh, &param);
1094 }
1095 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 &&                                        \
1096 	* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1                                           \
1097 	*/
1098 
1099 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_11_ii(const struct shell * sh,size_t argc,char ** argv)1100 static int cmd_cap_ac_11_ii(const struct shell *sh, size_t argc, char **argv)
1101 {
1102 	const struct bap_unicast_ac_param param = {
1103 		.name = "AC_11_II",
1104 		.conn_cnt = 2U,
1105 		.snk_cnt = {1U, 1U},
1106 		.src_cnt = {1U, 1U},
1107 		.snk_chan_cnt = 1U,
1108 		.src_chan_cnt = 1U,
1109 	};
1110 
1111 	return cap_ac_unicast(sh, &param);
1112 }
1113 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1114 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1115 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1116 
1117 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
cmd_broadcast_start(const struct shell * sh,size_t argc,char * argv[])1118 static int cmd_broadcast_start(const struct shell *sh, size_t argc, char *argv[])
1119 {
1120 	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
1121 	int err;
1122 
1123 	if (adv == NULL) {
1124 		shell_info(sh, "Extended advertising set is NULL");
1125 
1126 		return -ENOEXEC;
1127 	}
1128 
1129 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1130 		shell_info(sh, "CAP Broadcast source not created");
1131 
1132 		return -ENOEXEC;
1133 	}
1134 
1135 	err = bt_cap_initiator_broadcast_audio_start(default_source.cap_source,
1136 						     adv_sets[selected_adv]);
1137 	if (err != 0) {
1138 		shell_error(sh, "Unable to start broadcast source: %d", err);
1139 
1140 		return -ENOEXEC;
1141 	}
1142 
1143 	return 0;
1144 }
1145 
cmd_broadcast_update(const struct shell * sh,size_t argc,char * argv[])1146 static int cmd_broadcast_update(const struct shell *sh, size_t argc, char *argv[])
1147 {
1148 	uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
1149 	size_t len;
1150 	int err;
1151 
1152 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1153 		shell_info(sh, "CAP Broadcast source not created");
1154 
1155 		return -ENOEXEC;
1156 	}
1157 
1158 	len = hex2bin(argv[1], strlen(argv[1]), meta, sizeof(meta));
1159 	if (len == 0) {
1160 		shell_print(sh, "Unable to parse metadata (len was %zu, max len is %d)",
1161 			    strlen(argv[1]) / 2U + strlen(argv[1]) % 2U,
1162 			    CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
1163 
1164 		return -ENOEXEC;
1165 	}
1166 
1167 	err = bt_cap_initiator_broadcast_audio_update(default_source.cap_source, meta, len);
1168 	if (err != 0) {
1169 		shell_error(sh, "Unable to update broadcast source: %d", err);
1170 
1171 		return -ENOEXEC;
1172 	}
1173 
1174 	shell_print(sh, "CAP Broadcast source updated with new metadata. Update the advertised "
1175 			"base via `bt per-adv-data`");
1176 
1177 	return 0;
1178 }
1179 
cmd_broadcast_stop(const struct shell * sh,size_t argc,char * argv[])1180 static int cmd_broadcast_stop(const struct shell *sh, size_t argc, char *argv[])
1181 {
1182 	int err;
1183 
1184 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1185 		shell_info(sh, "CAP Broadcast source not created");
1186 
1187 		return -ENOEXEC;
1188 	}
1189 
1190 	err = bt_cap_initiator_broadcast_audio_stop(default_source.cap_source);
1191 	if (err != 0) {
1192 		shell_error(sh, "Unable to stop broadcast source: %d", err);
1193 
1194 		return -ENOEXEC;
1195 	}
1196 
1197 	return 0;
1198 }
1199 
cmd_broadcast_delete(const struct shell * sh,size_t argc,char * argv[])1200 static int cmd_broadcast_delete(const struct shell *sh, size_t argc, char *argv[])
1201 {
1202 	int err;
1203 
1204 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1205 		shell_info(sh, "CAP Broadcast source not created");
1206 
1207 		return -ENOEXEC;
1208 	}
1209 
1210 	err = bt_cap_initiator_broadcast_audio_delete(default_source.cap_source);
1211 	if (err != 0) {
1212 		shell_error(sh, "Unable to stop broadcast source: %d", err);
1213 
1214 		return -ENOEXEC;
1215 	}
1216 
1217 	default_source.cap_source = NULL;
1218 	default_source.is_cap = false;
1219 
1220 	return 0;
1221 }
1222 
cap_ac_broadcast(const struct shell * sh,size_t argc,char ** argv,const struct bap_broadcast_ac_param * param)1223 int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv,
1224 		     const struct bap_broadcast_ac_param *param)
1225 {
1226 	/* TODO: Use CAP API when the CAP shell has broadcast support */
1227 	struct bt_cap_initiator_broadcast_stream_param stream_params[BAP_UNICAST_AC_MAX_SRC] = {0};
1228 	uint8_t stereo_data[] = {
1229 		BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1230 				    BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)};
1231 	uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1232 						    BT_AUDIO_LOCATION_FRONT_RIGHT)};
1233 	uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1234 						   BT_AUDIO_LOCATION_FRONT_LEFT)};
1235 	struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0};
1236 	struct bt_cap_initiator_broadcast_create_param create_param = {0};
1237 	struct bt_le_ext_adv *adv;
1238 	int err;
1239 
1240 	if (default_source.cap_source != NULL) {
1241 		shell_error(sh, "Broadcast Source already created, please delete first");
1242 		return -ENOEXEC;
1243 	}
1244 
1245 	adv = adv_sets[selected_adv];
1246 	if (adv == NULL) {
1247 		shell_error(sh, "Extended advertising set is NULL");
1248 		return -ENOEXEC;
1249 	}
1250 
1251 	copy_broadcast_source_preset(&default_source, &default_broadcast_source_preset);
1252 	default_source.qos.sdu *= param->chan_cnt;
1253 
1254 	for (size_t i = 0U; i < param->stream_cnt; i++) {
1255 		stream_params[i].stream = &broadcast_source_streams[i].stream;
1256 
1257 		if (param->stream_cnt == 1U) {
1258 			stream_params[i].data_len = ARRAY_SIZE(stereo_data);
1259 			stream_params[i].data = stereo_data;
1260 		} else if (i == 0U) {
1261 			stream_params[i].data_len = ARRAY_SIZE(left_data);
1262 			stream_params[i].data = left_data;
1263 		} else if (i == 1U) {
1264 			stream_params[i].data_len = ARRAY_SIZE(right_data);
1265 			stream_params[i].data = right_data;
1266 		}
1267 	}
1268 
1269 	subgroup_param.stream_count = param->stream_cnt;
1270 	subgroup_param.stream_params = stream_params;
1271 	subgroup_param.codec_cfg = &default_source.codec_cfg;
1272 	create_param.subgroup_count = 1U;
1273 	create_param.subgroup_params = &subgroup_param;
1274 	create_param.qos = &default_source.qos;
1275 
1276 	err = bt_cap_initiator_broadcast_audio_create(&create_param, &default_source.cap_source);
1277 	if (err != 0) {
1278 		shell_error(sh, "Failed to create broadcast source: %d", err);
1279 		return -ENOEXEC;
1280 	}
1281 
1282 	/* We don't start the broadcast source here, because in order to populate the BASE in the
1283 	 * periodic advertising data, the broadcast source needs to be created but not started.
1284 	 */
1285 	shell_print(sh,
1286 		    "CAP Broadcast source for %s created. "
1287 		    "Start via `cap_initiator broadcast_start`, "
1288 		    "and update / set the base via `bt per-adv data`",
1289 		    param->name);
1290 	default_source.is_cap = true;
1291 
1292 	return 0;
1293 }
1294 
cmd_cap_ac_12(const struct shell * sh,size_t argc,char ** argv)1295 static int cmd_cap_ac_12(const struct shell *sh, size_t argc, char **argv)
1296 {
1297 	const struct bap_broadcast_ac_param param = {
1298 		.name = "AC_12",
1299 		.stream_cnt = 1U,
1300 		.chan_cnt = 1U,
1301 	};
1302 
1303 	return cap_ac_broadcast(sh, argc, argv, &param);
1304 }
1305 
1306 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1
cmd_cap_ac_13(const struct shell * sh,size_t argc,char ** argv)1307 static int cmd_cap_ac_13(const struct shell *sh, size_t argc, char **argv)
1308 {
1309 	const struct bap_broadcast_ac_param param = {
1310 		.name = "AC_13",
1311 		.stream_cnt = 2U,
1312 		.chan_cnt = 1U,
1313 	};
1314 
1315 	return cap_ac_broadcast(sh, argc, argv, &param);
1316 }
1317 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */
1318 
cmd_cap_ac_14(const struct shell * sh,size_t argc,char ** argv)1319 static int cmd_cap_ac_14(const struct shell *sh, size_t argc, char **argv)
1320 {
1321 	const struct bap_broadcast_ac_param param = {
1322 		.name = "AC_14",
1323 		.stream_cnt = 2U,
1324 		.chan_cnt = 2U,
1325 	};
1326 
1327 	return cap_ac_broadcast(sh, argc, argv, &param);
1328 }
1329 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1330 
cmd_cap_initiator(const struct shell * sh,size_t argc,char ** argv)1331 static int cmd_cap_initiator(const struct shell *sh, size_t argc, char **argv)
1332 {
1333 	if (argc > 1) {
1334 		shell_error(sh, "%s unknown parameter: %s",
1335 			    argv[0], argv[1]);
1336 	} else {
1337 		shell_error(sh, "%s Missing subcommand", argv[0]);
1338 	}
1339 
1340 	return -ENOEXEC;
1341 }
1342 
1343 SHELL_STATIC_SUBCMD_SET_CREATE(
1344 	cap_initiator_cmds,
1345 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
1346 	SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_initiator_discover, 1, 0),
1347 	SHELL_CMD_ARG(unicast_start, NULL,
1348 		      "Unicast Start [csip] [sinks <cnt> (default 1)] "
1349 		      "[sources <cnt> (default 1)] "
1350 		      "[conns (<cnt> | all) (default 1)]",
1351 		      cmd_cap_initiator_unicast_start, 1, 7),
1352 	SHELL_CMD_ARG(unicast_list, NULL, "Unicast list streams", cmd_cap_initiator_unicast_list, 1,
1353 		      0),
1354 	SHELL_CMD_ARG(unicast_update, NULL, "Unicast Update <all | stream [stream [stream...]]>",
1355 		      cmd_cap_initiator_unicast_update, 2, CAP_UNICAST_CLIENT_STREAM_COUNT),
1356 	SHELL_CMD_ARG(unicast_stop, NULL,
1357 		      "Unicast stop streams [stream [stream [stream...]]] (all by default)",
1358 		      cmd_cap_initiator_unicast_stop, 1, CAP_UNICAST_CLIENT_STREAM_COUNT),
1359 	SHELL_CMD_ARG(unicast_cancel, NULL, "Unicast cancel current procedure",
1360 		      cmd_cap_initiator_unicast_cancel, 1, 0),
1361 #if UNICAST_SINK_SUPPORTED
1362 	SHELL_CMD_ARG(ac_1, NULL, "Unicast audio configuration 1", cmd_cap_ac_1, 1, 0),
1363 #endif /* UNICAST_SINK_SUPPORTED */
1364 #if UNICAST_SRC_SUPPORTED
1365 	SHELL_CMD_ARG(ac_2, NULL, "Unicast audio configuration 2", cmd_cap_ac_2, 1, 0),
1366 #endif /* UNICAST_SRC_SUPPORTED */
1367 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1368 	SHELL_CMD_ARG(ac_3, NULL, "Unicast audio configuration 3", cmd_cap_ac_3, 1, 0),
1369 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1370 #if UNICAST_SINK_SUPPORTED
1371 	SHELL_CMD_ARG(ac_4, NULL, "Unicast audio configuration 4", cmd_cap_ac_4, 1, 0),
1372 #endif /* UNICAST_SINK_SUPPORTED */
1373 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1374 	SHELL_CMD_ARG(ac_5, NULL, "Unicast audio configuration 5", cmd_cap_ac_5, 1, 0),
1375 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1376 #if UNICAST_SINK_SUPPORTED
1377 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
1378 	SHELL_CMD_ARG(ac_6_i, NULL, "Unicast audio configuration 6(i)", cmd_cap_ac_6_i, 1, 0),
1379 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1380 #if CONFIG_BT_MAX_CONN >= 2
1381 	SHELL_CMD_ARG(ac_6_ii, NULL, "Unicast audio configuration 6(ii)", cmd_cap_ac_6_ii, 1, 0),
1382 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1383 #endif /* UNICAST_SINK_SUPPORTED */
1384 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1385 	SHELL_CMD_ARG(ac_7_i, NULL, "Unicast audio configuration 7(i)", cmd_cap_ac_7_i, 1, 0),
1386 #if CONFIG_BT_MAX_CONN >= 2
1387 	SHELL_CMD_ARG(ac_7_ii, NULL, "Unicast audio configuration 7(ii)", cmd_cap_ac_7_ii, 1, 0),
1388 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1389 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
1390 	SHELL_CMD_ARG(ac_8_i, NULL, "Unicast audio configuration 8(i)", cmd_cap_ac_8_i, 1, 0),
1391 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1392 #if CONFIG_BT_MAX_CONN >= 2
1393 	SHELL_CMD_ARG(ac_8_ii, NULL, "Unicast audio configuration 8(ii)", cmd_cap_ac_8_ii, 1, 0),
1394 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1395 #if UNICAST_SRC_SUPPORTED
1396 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
1397 	SHELL_CMD_ARG(ac_9_i, NULL, "Unicast audio configuration 9(i)", cmd_cap_ac_9_i, 1, 0),
1398 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1399 #if CONFIG_BT_MAX_CONN >= 2
1400 	SHELL_CMD_ARG(ac_9_ii, NULL, "Unicast audio configuration 9(ii)", cmd_cap_ac_9_ii, 1, 0),
1401 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1402 	SHELL_CMD_ARG(ac_10, NULL, "Unicast audio configuration 10", cmd_cap_ac_10, 1, 0),
1403 #endif /* UNICAST_SRC_SUPPORTED */
1404 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
1405 	SHELL_CMD_ARG(ac_11_i, NULL, "Unicast audio configuration 11(i)", cmd_cap_ac_11_i, 1, 0),
1406 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 &&                                        \
1407 	* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1                                           \
1408 	*/
1409 #if CONFIG_BT_MAX_CONN >= 2
1410 	SHELL_CMD_ARG(ac_11_ii, NULL, "Unicast audio configuration 11(ii)", cmd_cap_ac_11_ii, 1, 0),
1411 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1412 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1413 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1414 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1415 	SHELL_CMD_ARG(broadcast_start, NULL, "", cmd_broadcast_start, 1, 0),
1416 	SHELL_CMD_ARG(broadcast_update, NULL, "<meta>", cmd_broadcast_update, 2, 0),
1417 	SHELL_CMD_ARG(broadcast_stop, NULL, "", cmd_broadcast_stop, 1, 0),
1418 	SHELL_CMD_ARG(broadcast_delete, NULL, "", cmd_broadcast_delete, 1, 0),
1419 	SHELL_CMD_ARG(ac_12, NULL, "Broadcast audio configuration 12", cmd_cap_ac_12, 1, 0),
1420 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1
1421 	SHELL_CMD_ARG(ac_13, NULL, "Broadcast audio configuration 13", cmd_cap_ac_13, 1, 0),
1422 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */
1423 	SHELL_CMD_ARG(ac_14, NULL, "Broadcast audio configuration 14", cmd_cap_ac_14, 1, 0),
1424 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1425 	SHELL_SUBCMD_SET_END);
1426 
1427 SHELL_CMD_ARG_REGISTER(cap_initiator, &cap_initiator_cmds,
1428 		       "Bluetooth CAP initiator shell commands",
1429 		       cmd_cap_initiator, 1, 1);
1430 
nonconnectable_ad_data_add(struct bt_data * data_array,const size_t data_array_size)1431 static size_t nonconnectable_ad_data_add(struct bt_data *data_array, const size_t data_array_size)
1432 {
1433 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1434 	if (default_source.cap_source != NULL && default_source.is_cap) {
1435 		static uint8_t ad_cap_broadcast_announcement[5] = {
1436 			BT_UUID_16_ENCODE(BT_UUID_BROADCAST_AUDIO_VAL),
1437 		};
1438 		uint32_t broadcast_id;
1439 		int err;
1440 
1441 		err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
1442 		if (err) {
1443 			bt_shell_error("Unable to generate broadcast ID: %d\n", err);
1444 
1445 			return 0;
1446 		}
1447 
1448 		sys_put_le24(broadcast_id, &ad_cap_broadcast_announcement[2]);
1449 		data_array[0].type = BT_DATA_SVC_DATA16;
1450 		data_array[0].data_len = ARRAY_SIZE(ad_cap_broadcast_announcement);
1451 		data_array[0].data = ad_cap_broadcast_announcement;
1452 
1453 		return 1;
1454 	}
1455 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1456 
1457 	return 0;
1458 }
1459 
cap_initiator_ad_data_add(struct bt_data * data_array,const size_t data_array_size,const bool discoverable,const bool connectable)1460 size_t cap_initiator_ad_data_add(struct bt_data *data_array, const size_t data_array_size,
1461 				 const bool discoverable, const bool connectable)
1462 {
1463 	if (!discoverable) {
1464 		return 0;
1465 	}
1466 
1467 	if (!connectable) {
1468 		return nonconnectable_ad_data_add(data_array, data_array_size);
1469 	}
1470 
1471 	return 0;
1472 }
1473 
cap_initiator_pa_data_add(struct bt_data * data_array,const size_t data_array_size)1474 size_t cap_initiator_pa_data_add(struct bt_data *data_array, const size_t data_array_size)
1475 {
1476 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1477 	if (default_source.cap_source != NULL && default_source.is_cap) {
1478 		/* Required size of the buffer depends on what has been
1479 		 * configured. We just use the maximum size possible.
1480 		 */
1481 		NET_BUF_SIMPLE_DEFINE_STATIC(base_buf, UINT8_MAX);
1482 		int err;
1483 
1484 		net_buf_simple_reset(&base_buf);
1485 
1486 		err = bt_cap_initiator_broadcast_get_base(default_source.cap_source, &base_buf);
1487 		if (err != 0) {
1488 			bt_shell_error("Unable to get BASE: %d\n", err);
1489 
1490 			return 0;
1491 		}
1492 
1493 		data_array[0].type = BT_DATA_SVC_DATA16;
1494 		data_array[0].data_len = base_buf.len;
1495 		data_array[0].data = base_buf.data;
1496 
1497 		return 1;
1498 	}
1499 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1500 
1501 	return 0;
1502 }
1503