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