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 "host/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 	param.release = true;
536 
537 	err = bt_cap_initiator_unicast_audio_stop(&param);
538 	if (err != 0) {
539 		shell_print(sh, "Failed to update unicast audio: %d", err);
540 	}
541 
542 	return err;
543 }
544 
cmd_cap_initiator_unicast_cancel(const struct shell * sh,size_t argc,char * argv[])545 static int cmd_cap_initiator_unicast_cancel(const struct shell *sh, size_t argc, char *argv[])
546 {
547 	int err = 0;
548 
549 	err = bt_cap_initiator_unicast_audio_cancel();
550 	if (err != 0) {
551 		shell_print(sh, "Failed to cancel unicast audio procedure: %d", err);
552 		return -ENOEXEC;
553 	}
554 
555 	return 0;
556 }
557 
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)558 static int cap_ac_unicast_start(const struct bap_unicast_ac_param *param,
559 				struct bt_conn *connected_conns[],
560 				struct shell_stream *snk_uni_streams[], size_t snk_cnt,
561 				struct shell_stream *src_uni_streams[], size_t src_cnt)
562 {
563 	struct bt_cap_unicast_audio_start_stream_param stream_params[BAP_UNICAST_AC_MAX_STREAM] = {
564 		0};
565 	struct bt_audio_codec_cfg *snk_codec_cfgs[BAP_UNICAST_AC_MAX_SNK] = {0};
566 	struct bt_audio_codec_cfg *src_codec_cfgs[BAP_UNICAST_AC_MAX_SRC] = {0};
567 	struct bt_cap_stream *snk_cap_streams[BAP_UNICAST_AC_MAX_SNK] = {0};
568 	struct bt_cap_stream *src_cap_streams[BAP_UNICAST_AC_MAX_SRC] = {0};
569 	struct bt_cap_unicast_audio_start_param start_param = {0};
570 	struct bt_bap_ep *snk_eps[BAP_UNICAST_AC_MAX_SNK] = {0};
571 	struct bt_bap_ep *src_eps[BAP_UNICAST_AC_MAX_SRC] = {0};
572 	size_t snk_stream_cnt = 0U;
573 	size_t src_stream_cnt = 0U;
574 	size_t stream_cnt = 0U;
575 	size_t snk_ep_cnt = 0U;
576 	size_t src_ep_cnt = 0U;
577 
578 	for (size_t i = 0U; i < param->conn_cnt; i++) {
579 #if UNICAST_SINK_SUPPORTED
580 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
581 			snk_eps[snk_ep_cnt] = snks[bt_conn_index(connected_conns[i])][j];
582 			if (snk_eps[snk_ep_cnt] == NULL) {
583 				shell_error(ctx_shell, "No sink[%zu][%zu] endpoint available", i,
584 					    j);
585 
586 				return -ENOEXEC;
587 			}
588 			snk_ep_cnt++;
589 		}
590 #endif /* UNICAST_SINK_SUPPORTED */
591 
592 #if UNICAST_SRC_SUPPORTED
593 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
594 			src_eps[src_ep_cnt] = srcs[bt_conn_index(connected_conns[i])][j];
595 			if (src_eps[src_ep_cnt] == NULL) {
596 				shell_error(ctx_shell, "No source[%zu][%zu] endpoint available", i,
597 					    j);
598 
599 				return -ENOEXEC;
600 			}
601 			src_ep_cnt++;
602 		}
603 #endif /* UNICAST_SRC_SUPPORTED  */
604 	}
605 
606 	if (snk_ep_cnt != snk_cnt) {
607 		shell_error(ctx_shell, "Sink endpoint and stream count mismatch: %zu != %zu",
608 			    snk_ep_cnt, snk_cnt);
609 
610 		return -ENOEXEC;
611 	}
612 
613 	if (src_ep_cnt != src_cnt) {
614 		shell_error(ctx_shell, "Source  endpoint and stream count mismatch: %zu != %zu",
615 			    src_ep_cnt, src_cnt);
616 
617 		return -ENOEXEC;
618 	}
619 
620 	/* Setup arrays of parameters based on the preset for easier access. This also copies the
621 	 * preset so that we can modify them (e.g. update the metadata)
622 	 */
623 	for (size_t i = 0U; i < snk_cnt; i++) {
624 		snk_cap_streams[i] = &snk_uni_streams[i]->stream;
625 		snk_codec_cfgs[i] = &snk_uni_streams[i]->codec_cfg;
626 	}
627 
628 	for (size_t i = 0U; i < src_cnt; i++) {
629 		src_cap_streams[i] = &src_uni_streams[i]->stream;
630 		src_codec_cfgs[i] = &src_uni_streams[i]->codec_cfg;
631 	}
632 
633 	/* CAP Start */
634 	for (size_t i = 0U; i < param->conn_cnt; i++) {
635 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
636 			struct bt_cap_unicast_audio_start_stream_param *stream_param =
637 				&stream_params[stream_cnt];
638 
639 			stream_param->member.member = connected_conns[i];
640 			stream_param->codec_cfg = snk_codec_cfgs[snk_stream_cnt];
641 			stream_param->ep = snk_eps[snk_stream_cnt];
642 			stream_param->stream = snk_cap_streams[snk_stream_cnt];
643 
644 			snk_stream_cnt++;
645 			stream_cnt++;
646 		}
647 
648 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
649 			struct bt_cap_unicast_audio_start_stream_param *stream_param =
650 				&stream_params[stream_cnt];
651 
652 			stream_param->member.member = connected_conns[i];
653 			stream_param->codec_cfg = src_codec_cfgs[src_stream_cnt];
654 			stream_param->ep = src_eps[src_stream_cnt];
655 			stream_param->stream = src_cap_streams[src_stream_cnt];
656 
657 			src_stream_cnt++;
658 			stream_cnt++;
659 		}
660 	}
661 
662 	start_param.stream_params = stream_params;
663 	start_param.count = stream_cnt;
664 	start_param.type = BT_CAP_SET_TYPE_AD_HOC;
665 
666 	return bt_cap_initiator_unicast_audio_start(&start_param);
667 }
668 
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)669 static int set_codec_config(const struct shell *sh, struct shell_stream *sh_stream,
670 			    struct named_lc3_preset *preset, size_t conn_cnt, size_t ep_cnt,
671 			    size_t chan_cnt, size_t conn_index, size_t ep_index)
672 {
673 	enum bt_audio_location new_chan_alloc;
674 	enum bt_audio_location chan_alloc;
675 	int err;
676 
677 	copy_unicast_stream_preset(sh_stream, preset);
678 
679 	if (chan_cnt == 1U) {
680 		/* - When we have a single channel on a single connection then we make it mono
681 		 * - When we have a single channel on a multiple connections then we make it left on
682 		 *   the first connection and right on the second connection
683 		 * - When we have multiple channels streams for a connection, we make them either
684 		 *   left or right, regardless of the connection count
685 		 */
686 		if (ep_cnt == 1) {
687 			if (conn_cnt == 1) {
688 				new_chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
689 			} else if (conn_cnt == 2) {
690 				if (conn_index == 0) {
691 					new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
692 				} else if (conn_index == 1) {
693 					new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
694 				} else {
695 					return 0;
696 				}
697 			} else {
698 				return 0;
699 			}
700 		} else if (ep_cnt == 2) {
701 			if (ep_index == 0) {
702 				new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
703 			} else if (ep_index == 1) {
704 				new_chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
705 			} else {
706 				return 0;
707 			}
708 		} else {
709 			return 0;
710 		}
711 	} else if (chan_cnt == 2U) {
712 		/* Some audio configuration requires multiple sink channels,
713 		 * so multiply the SDU based on the channel count
714 		 */
715 		sh_stream->qos.sdu *= chan_cnt;
716 
717 		/* If a stream has 2 channels, we make it stereo */
718 		new_chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT;
719 
720 	} else {
721 		return 0;
722 	}
723 
724 	err = bt_audio_codec_cfg_get_chan_allocation(&sh_stream->codec_cfg, &chan_alloc, false);
725 	if (err != 0) {
726 		if (err == -ENODATA) {
727 			chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
728 		}
729 	}
730 
731 	if (chan_alloc != new_chan_alloc) {
732 		shell_info(sh,
733 			   "[%zu][%zu]: Overwriting existing channel allocation 0x%08X with 0x%08X",
734 			   conn_index, ep_index, chan_alloc, new_chan_alloc);
735 
736 		err = bt_audio_codec_cfg_set_chan_allocation(&sh_stream->codec_cfg, new_chan_alloc);
737 		if (err < 0) {
738 			return err;
739 		}
740 	}
741 
742 	return 0;
743 }
744 
cap_ac_unicast(const struct shell * sh,const struct bap_unicast_ac_param * param)745 int cap_ac_unicast(const struct shell *sh, const struct bap_unicast_ac_param *param)
746 {
747 	/* Allocate params large enough for any params, but only use what is required */
748 	struct bt_conn *connected_conns[BAP_UNICAST_AC_MAX_CONN] = {0};
749 	struct shell_stream *snk_uni_streams[BAP_UNICAST_AC_MAX_SNK];
750 	struct shell_stream *src_uni_streams[BAP_UNICAST_AC_MAX_SRC];
751 	size_t conn_avail_cnt;
752 	size_t snk_cnt = 0;
753 	size_t src_cnt = 0;
754 	int err;
755 
756 	if (default_unicast_group != NULL) {
757 		shell_error(sh, "Unicast Group already exist, please delete first");
758 		return -ENOEXEC;
759 	}
760 
761 	if (param->conn_cnt > BAP_UNICAST_AC_MAX_CONN) {
762 		shell_error(sh, "Invalid conn_cnt: %zu", param->conn_cnt);
763 		return -ENOEXEC;
764 	}
765 
766 	for (size_t i = 0; i < param->conn_cnt; i++) {
767 		/* Verify conn values */
768 		if (param->snk_cnt[i] > BAP_UNICAST_AC_MAX_SNK) {
769 			shell_error(sh, "Invalid conn_snk_cnt[%zu]: %zu", i, param->snk_cnt[i]);
770 			return -ENOEXEC;
771 		}
772 
773 		if (param->src_cnt[i] > BAP_UNICAST_AC_MAX_SRC) {
774 			shell_error(sh, "Invalid conn_src_cnt[%zu]: %zu", i, param->src_cnt[i]);
775 			return -ENOEXEC;
776 		}
777 	}
778 
779 	/* Populate the array of connected connections */
780 	bt_conn_foreach(BT_CONN_TYPE_LE, populate_connected_conns, (void *)connected_conns);
781 	for (conn_avail_cnt = 0; conn_avail_cnt < ARRAY_SIZE(connected_conns); conn_avail_cnt++) {
782 		if (connected_conns[conn_avail_cnt] == NULL) {
783 			break;
784 		}
785 	}
786 
787 	if (conn_avail_cnt < param->conn_cnt) {
788 		shell_error(sh,
789 			    "Only %zu/%u connected devices, please connect additional devices for "
790 			    "this audio configuration",
791 			    conn_avail_cnt, param->conn_cnt);
792 		return -ENOEXEC;
793 	}
794 
795 	/* Set all endpoints from multiple connections in a single array, and verify that the known
796 	 * endpoints matches the audio configuration
797 	 */
798 	for (size_t i = 0U; i < param->conn_cnt; i++) {
799 		for (size_t j = 0U; j < param->snk_cnt[i]; j++) {
800 			struct shell_stream *snk_uni_stream;
801 
802 			snk_uni_stream = snk_uni_streams[snk_cnt] = &unicast_streams[snk_cnt];
803 
804 			err = set_codec_config(sh, snk_uni_stream, &default_sink_preset,
805 					       param->conn_cnt, param->snk_cnt[i],
806 					       param->snk_chan_cnt, i, j);
807 			if (err != 0) {
808 				shell_error(sh, "Failed to set codec configuration: %d", err);
809 
810 				return -ENOEXEC;
811 			}
812 
813 			snk_cnt++;
814 		}
815 
816 		for (size_t j = 0U; j < param->src_cnt[i]; j++) {
817 			struct shell_stream *src_uni_stream;
818 
819 			src_uni_stream = snk_uni_streams[src_cnt] = &unicast_streams[src_cnt];
820 
821 			err = set_codec_config(sh, src_uni_stream, &default_source_preset,
822 					       param->conn_cnt, param->src_cnt[i],
823 					       param->src_chan_cnt, i, j);
824 			if (err != 0) {
825 				shell_error(sh, "Failed to set codec configuration: %d", err);
826 
827 				return -ENOEXEC;
828 			}
829 
830 			src_cnt++;
831 		}
832 	}
833 
834 	if (!ctx_shell) {
835 		ctx_shell = sh;
836 	}
837 
838 	err = bap_ac_create_unicast_group(param, snk_uni_streams, snk_cnt, src_uni_streams,
839 					  src_cnt);
840 	if (err != 0) {
841 		shell_error(sh, "Failed to create group: %d", err);
842 
843 		return -ENOEXEC;
844 	}
845 
846 	shell_print(sh, "Starting %zu streams for %s", snk_cnt + src_cnt, param->name);
847 	err = cap_ac_unicast_start(param, connected_conns, snk_uni_streams, snk_cnt,
848 				   src_uni_streams, src_cnt);
849 	if (err != 0) {
850 		shell_error(sh, "Failed to start unicast audio: %d", err);
851 
852 		err = bt_bap_unicast_group_delete(default_unicast_group);
853 		if (err != 0) {
854 			shell_error(sh, "Failed to delete group: %d", err);
855 		} else {
856 			default_unicast_group = NULL;
857 		}
858 
859 		return -ENOEXEC;
860 	}
861 
862 	return 0;
863 }
864 
865 #if UNICAST_SINK_SUPPORTED
cmd_cap_ac_1(const struct shell * sh,size_t argc,char ** argv)866 static int cmd_cap_ac_1(const struct shell *sh, size_t argc, char **argv)
867 {
868 	const struct bap_unicast_ac_param param = {
869 		.name = "AC_1",
870 		.conn_cnt = 1U,
871 		.snk_cnt = {1U},
872 		.src_cnt = {0U},
873 		.snk_chan_cnt = 1U,
874 		.src_chan_cnt = 0U,
875 	};
876 
877 	return cap_ac_unicast(sh, &param);
878 }
879 #endif /* UNICAST_SINK_SUPPORTED */
880 
881 #if UNICAST_SRC_SUPPORTED
cmd_cap_ac_2(const struct shell * sh,size_t argc,char ** argv)882 static int cmd_cap_ac_2(const struct shell *sh, size_t argc, char **argv)
883 {
884 	const struct bap_unicast_ac_param param = {
885 		.name = "AC_2",
886 		.conn_cnt = 1U,
887 		.snk_cnt = {0U},
888 		.src_cnt = {1U},
889 		.snk_chan_cnt = 0U,
890 		.src_chan_cnt = 1U,
891 	};
892 
893 	return cap_ac_unicast(sh, &param);
894 }
895 #endif /* UNICAST_SRC_SUPPORTED */
896 
897 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_3(const struct shell * sh,size_t argc,char ** argv)898 static int cmd_cap_ac_3(const struct shell *sh, size_t argc, char **argv)
899 {
900 	const struct bap_unicast_ac_param param = {
901 		.name = "AC_3",
902 		.conn_cnt = 1U,
903 		.snk_cnt = {1U},
904 		.src_cnt = {1U},
905 		.snk_chan_cnt = 1U,
906 		.src_chan_cnt = 1U,
907 	};
908 
909 	return cap_ac_unicast(sh, &param);
910 }
911 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
912 
913 #if UNICAST_SINK_SUPPORTED
cmd_cap_ac_4(const struct shell * sh,size_t argc,char ** argv)914 static int cmd_cap_ac_4(const struct shell *sh, size_t argc, char **argv)
915 {
916 	const struct bap_unicast_ac_param param = {
917 		.name = "AC_4",
918 		.conn_cnt = 1,
919 		.snk_cnt = {1U},
920 		.src_cnt = {0U},
921 		.snk_chan_cnt = 2U,
922 		.src_chan_cnt = 0U,
923 	};
924 
925 	return cap_ac_unicast(sh, &param);
926 }
927 #endif /* UNICAST_SINK_SUPPORTED */
928 
929 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_5(const struct shell * sh,size_t argc,char ** argv)930 static int cmd_cap_ac_5(const struct shell *sh, size_t argc, char **argv)
931 {
932 	const struct bap_unicast_ac_param param = {
933 		.name = "AC_5",
934 		.conn_cnt = 1U,
935 		.snk_cnt = {1U},
936 		.src_cnt = {1U},
937 		.snk_chan_cnt = 2U,
938 		.src_chan_cnt = 1U,
939 	};
940 
941 	return cap_ac_unicast(sh, &param);
942 }
943 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
944 
945 #if UNICAST_SINK_SUPPORTED
946 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
cmd_cap_ac_6_i(const struct shell * sh,size_t argc,char ** argv)947 static int cmd_cap_ac_6_i(const struct shell *sh, size_t argc, char **argv)
948 {
949 	const struct bap_unicast_ac_param param = {
950 		.name = "AC_6_I",
951 		.conn_cnt = 1U,
952 		.snk_cnt = {2U},
953 		.src_cnt = {0U},
954 		.snk_chan_cnt = 1U,
955 		.src_chan_cnt = 0U,
956 	};
957 
958 	return cap_ac_unicast(sh, &param);
959 }
960 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
961 
962 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_6_ii(const struct shell * sh,size_t argc,char ** argv)963 static int cmd_cap_ac_6_ii(const struct shell *sh, size_t argc, char **argv)
964 {
965 	const struct bap_unicast_ac_param param = {
966 		.name = "AC_6_II",
967 		.conn_cnt = 2U,
968 		.snk_cnt = {1U, 1U},
969 		.src_cnt = {0U, 0U},
970 		.snk_chan_cnt = 1U,
971 		.src_chan_cnt = 0U,
972 	};
973 
974 	return cap_ac_unicast(sh, &param);
975 }
976 #endif /* CONFIG_BT_MAX_CONN >= 2 */
977 #endif /* UNICAST_SINK_SUPPORTED */
978 
979 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
cmd_cap_ac_7_i(const struct shell * sh,size_t argc,char ** argv)980 static int cmd_cap_ac_7_i(const struct shell *sh, size_t argc, char **argv)
981 {
982 	const struct bap_unicast_ac_param param = {
983 		.name = "AC_7_I",
984 		.conn_cnt = 1U,
985 		.snk_cnt = {1U}, /* TODO: These should be separate CIS */
986 		.src_cnt = {1U}, /* TODO: These should be separate CIS */
987 		.snk_chan_cnt = 1U,
988 		.src_chan_cnt = 1U,
989 	};
990 
991 	return cap_ac_unicast(sh, &param);
992 }
993 
994 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_7_ii(const struct shell * sh,size_t argc,char ** argv)995 static int cmd_cap_ac_7_ii(const struct shell *sh, size_t argc, char **argv)
996 {
997 	const struct bap_unicast_ac_param param = {
998 		.name = "AC_7_II",
999 		.conn_cnt = 2U,
1000 		.snk_cnt = {1U, 0U},
1001 		.src_cnt = {0U, 1U},
1002 		.snk_chan_cnt = 1U,
1003 		.src_chan_cnt = 1U,
1004 	};
1005 
1006 	return cap_ac_unicast(sh, &param);
1007 }
1008 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1009 
1010 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
cmd_cap_ac_8_i(const struct shell * sh,size_t argc,char ** argv)1011 static int cmd_cap_ac_8_i(const struct shell *sh, size_t argc, char **argv)
1012 {
1013 	const struct bap_unicast_ac_param param = {
1014 		.name = "AC_8_I",
1015 		.conn_cnt = 1U,
1016 		.snk_cnt = {2U},
1017 		.src_cnt = {1U},
1018 		.snk_chan_cnt = 1U,
1019 		.src_chan_cnt = 1U,
1020 	};
1021 
1022 	return cap_ac_unicast(sh, &param);
1023 }
1024 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1025 
1026 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_8_ii(const struct shell * sh,size_t argc,char ** argv)1027 static int cmd_cap_ac_8_ii(const struct shell *sh, size_t argc, char **argv)
1028 {
1029 	const struct bap_unicast_ac_param param = {
1030 		.name = "AC_8_II",
1031 		.conn_cnt = 2U,
1032 		.snk_cnt = {1U, 1U},
1033 		.src_cnt = {1U, 0U},
1034 		.snk_chan_cnt = 1U,
1035 		.src_chan_cnt = 1U,
1036 	};
1037 
1038 	return cap_ac_unicast(sh, &param);
1039 }
1040 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1041 
1042 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_9_i(const struct shell * sh,size_t argc,char ** argv)1043 static int cmd_cap_ac_9_i(const struct shell *sh, size_t argc, char **argv)
1044 {
1045 	const struct bap_unicast_ac_param param = {
1046 		.name = "AC_9_I",
1047 		.conn_cnt = 1U,
1048 		.snk_cnt = {0U},
1049 		.src_cnt = {2U},
1050 		.snk_chan_cnt = 0U,
1051 		.src_chan_cnt = 1U,
1052 	};
1053 
1054 	return cap_ac_unicast(sh, &param);
1055 }
1056 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1057 
1058 #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)1059 static int cmd_cap_ac_9_ii(const struct shell *sh, size_t argc, char **argv)
1060 {
1061 	const struct bap_unicast_ac_param param = {
1062 		.name = "AC_9_II",
1063 		.conn_cnt = 2U,
1064 		.snk_cnt = {0U, 0U},
1065 		.src_cnt = {1U, 1U},
1066 		.snk_chan_cnt = 0U,
1067 		.src_chan_cnt = 1U,
1068 	};
1069 
1070 	return cap_ac_unicast(sh, &param);
1071 }
1072 #endif /* CONFIG_BT_MAX_CONN >= 2 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1073 
1074 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
cmd_cap_ac_10(const struct shell * sh,size_t argc,char ** argv)1075 static int cmd_cap_ac_10(const struct shell *sh, size_t argc, char **argv)
1076 {
1077 	const struct bap_unicast_ac_param param = {
1078 		.name = "AC_10",
1079 		.conn_cnt = 1U,
1080 		.snk_cnt = {0U},
1081 		.src_cnt = {1U},
1082 		.snk_chan_cnt = 0U,
1083 		.src_chan_cnt = 2U,
1084 	};
1085 
1086 	return cap_ac_unicast(sh, &param);
1087 }
1088 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1089 
1090 #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)1091 static int cmd_cap_ac_11_i(const struct shell *sh, size_t argc, char **argv)
1092 {
1093 	const struct bap_unicast_ac_param param = {
1094 		.name = "AC_11_I",
1095 		.conn_cnt = 1U,
1096 		.snk_cnt = {2U},
1097 		.src_cnt = {2U},
1098 		.snk_chan_cnt = 1U,
1099 		.src_chan_cnt = 1U,
1100 	};
1101 
1102 	return cap_ac_unicast(sh, &param);
1103 }
1104 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 &&                                        \
1105 	* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1                                           \
1106 	*/
1107 
1108 #if CONFIG_BT_MAX_CONN >= 2
cmd_cap_ac_11_ii(const struct shell * sh,size_t argc,char ** argv)1109 static int cmd_cap_ac_11_ii(const struct shell *sh, size_t argc, char **argv)
1110 {
1111 	const struct bap_unicast_ac_param param = {
1112 		.name = "AC_11_II",
1113 		.conn_cnt = 2U,
1114 		.snk_cnt = {1U, 1U},
1115 		.src_cnt = {1U, 1U},
1116 		.snk_chan_cnt = 1U,
1117 		.src_chan_cnt = 1U,
1118 	};
1119 
1120 	return cap_ac_unicast(sh, &param);
1121 }
1122 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1123 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1124 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1125 
1126 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
cmd_broadcast_start(const struct shell * sh,size_t argc,char * argv[])1127 static int cmd_broadcast_start(const struct shell *sh, size_t argc, char *argv[])
1128 {
1129 	struct bt_le_ext_adv *adv = adv_sets[selected_adv];
1130 	int err;
1131 
1132 	if (adv == NULL) {
1133 		shell_info(sh, "Extended advertising set is NULL");
1134 
1135 		return -ENOEXEC;
1136 	}
1137 
1138 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1139 		shell_info(sh, "CAP Broadcast source not created");
1140 
1141 		return -ENOEXEC;
1142 	}
1143 
1144 	err = bt_cap_initiator_broadcast_audio_start(default_source.cap_source,
1145 						     adv_sets[selected_adv]);
1146 	if (err != 0) {
1147 		shell_error(sh, "Unable to start broadcast source: %d", err);
1148 
1149 		return -ENOEXEC;
1150 	}
1151 
1152 	return 0;
1153 }
1154 
cmd_broadcast_update(const struct shell * sh,size_t argc,char * argv[])1155 static int cmd_broadcast_update(const struct shell *sh, size_t argc, char *argv[])
1156 {
1157 	uint8_t meta[CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE];
1158 	size_t len;
1159 	int err;
1160 
1161 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1162 		shell_info(sh, "CAP Broadcast source not created");
1163 
1164 		return -ENOEXEC;
1165 	}
1166 
1167 	len = hex2bin(argv[1], strlen(argv[1]), meta, sizeof(meta));
1168 	if (len == 0) {
1169 		shell_print(sh, "Unable to parse metadata (len was %zu, max len is %d)",
1170 			    strlen(argv[1]) / 2U + strlen(argv[1]) % 2U,
1171 			    CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
1172 
1173 		return -ENOEXEC;
1174 	}
1175 
1176 	err = bt_cap_initiator_broadcast_audio_update(default_source.cap_source, meta, len);
1177 	if (err != 0) {
1178 		shell_error(sh, "Unable to update broadcast source: %d", err);
1179 
1180 		return -ENOEXEC;
1181 	}
1182 
1183 	shell_print(sh, "CAP Broadcast source updated with new metadata. Update the advertised "
1184 			"base via `bt per-adv-data`");
1185 
1186 	return 0;
1187 }
1188 
cmd_broadcast_stop(const struct shell * sh,size_t argc,char * argv[])1189 static int cmd_broadcast_stop(const struct shell *sh, size_t argc, char *argv[])
1190 {
1191 	int err;
1192 
1193 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1194 		shell_info(sh, "CAP Broadcast source not created");
1195 
1196 		return -ENOEXEC;
1197 	}
1198 
1199 	err = bt_cap_initiator_broadcast_audio_stop(default_source.cap_source);
1200 	if (err != 0) {
1201 		shell_error(sh, "Unable to stop broadcast source: %d", err);
1202 
1203 		return -ENOEXEC;
1204 	}
1205 
1206 	return 0;
1207 }
1208 
cmd_broadcast_delete(const struct shell * sh,size_t argc,char * argv[])1209 static int cmd_broadcast_delete(const struct shell *sh, size_t argc, char *argv[])
1210 {
1211 	int err;
1212 
1213 	if (default_source.cap_source == NULL || !default_source.is_cap) {
1214 		shell_info(sh, "CAP Broadcast source not created");
1215 
1216 		return -ENOEXEC;
1217 	}
1218 
1219 	err = bt_cap_initiator_broadcast_audio_delete(default_source.cap_source);
1220 	if (err != 0) {
1221 		shell_error(sh, "Unable to stop broadcast source: %d", err);
1222 
1223 		return -ENOEXEC;
1224 	}
1225 
1226 	default_source.cap_source = NULL;
1227 	default_source.is_cap = false;
1228 
1229 	return 0;
1230 }
1231 
cap_ac_broadcast(const struct shell * sh,size_t argc,char ** argv,const struct bap_broadcast_ac_param * param)1232 int cap_ac_broadcast(const struct shell *sh, size_t argc, char **argv,
1233 			    const struct bap_broadcast_ac_param *param)
1234 {
1235 	/* TODO: Use CAP API when the CAP shell has broadcast support */
1236 	struct bt_cap_initiator_broadcast_stream_param stream_params[BAP_UNICAST_AC_MAX_SRC] = {0};
1237 	uint8_t stereo_data[] = {
1238 		BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1239 				    BT_AUDIO_LOCATION_FRONT_RIGHT | BT_AUDIO_LOCATION_FRONT_LEFT)};
1240 	uint8_t right_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1241 						    BT_AUDIO_LOCATION_FRONT_RIGHT)};
1242 	uint8_t left_data[] = {BT_AUDIO_CODEC_DATA(BT_AUDIO_CODEC_CFG_CHAN_ALLOC,
1243 						   BT_AUDIO_LOCATION_FRONT_LEFT)};
1244 	struct bt_cap_initiator_broadcast_subgroup_param subgroup_param = {0};
1245 	struct bt_cap_initiator_broadcast_create_param create_param = {0};
1246 	struct bt_le_ext_adv *adv;
1247 	int err;
1248 
1249 	if (default_source.cap_source != NULL) {
1250 		shell_error(sh, "Broadcast Source already created, please delete first");
1251 		return -ENOEXEC;
1252 	}
1253 
1254 	adv = adv_sets[selected_adv];
1255 	if (adv == NULL) {
1256 		shell_error(sh, "Extended advertising set is NULL");
1257 		return -ENOEXEC;
1258 	}
1259 
1260 	copy_broadcast_source_preset(&default_source, &default_broadcast_source_preset);
1261 	default_source.qos.sdu *= param->chan_cnt;
1262 
1263 	for (size_t i = 0U; i < param->stream_cnt; i++) {
1264 		stream_params[i].stream = &broadcast_source_streams[i].stream;
1265 
1266 		if (param->stream_cnt == 1U) {
1267 			stream_params[i].data_len = ARRAY_SIZE(stereo_data);
1268 			stream_params[i].data = stereo_data;
1269 		} else if (i == 0U) {
1270 			stream_params[i].data_len = ARRAY_SIZE(left_data);
1271 			stream_params[i].data = left_data;
1272 		} else if (i == 1U) {
1273 			stream_params[i].data_len = ARRAY_SIZE(right_data);
1274 			stream_params[i].data = right_data;
1275 		}
1276 	}
1277 
1278 	subgroup_param.stream_count = param->stream_cnt;
1279 	subgroup_param.stream_params = stream_params;
1280 	subgroup_param.codec_cfg = &default_source.codec_cfg;
1281 	create_param.subgroup_count = 1U;
1282 	create_param.subgroup_params = &subgroup_param;
1283 	create_param.qos = &default_source.qos;
1284 
1285 	err = bt_cap_initiator_broadcast_audio_create(&create_param, &default_source.cap_source);
1286 	if (err != 0) {
1287 		shell_error(sh, "Failed to create broadcast source: %d", err);
1288 		return -ENOEXEC;
1289 	}
1290 
1291 	/* We don't start the broadcast source here, because in order to populate the BASE in the
1292 	 * periodic advertising data, the broadcast source needs to be created but not started.
1293 	 */
1294 	shell_print(sh,
1295 		    "CAP Broadcast source for %s created. "
1296 		    "Start via `cap_initiator broadcast_start`, "
1297 		    "and update / set the base via `bt per-adv data`",
1298 		    param->name);
1299 	default_source.is_cap = true;
1300 
1301 	return 0;
1302 }
1303 
cmd_cap_ac_12(const struct shell * sh,size_t argc,char ** argv)1304 static int cmd_cap_ac_12(const struct shell *sh, size_t argc, char **argv)
1305 {
1306 	const struct bap_broadcast_ac_param param = {
1307 		.name = "AC_12",
1308 		.stream_cnt = 1U,
1309 		.chan_cnt = 1U,
1310 	};
1311 
1312 	return cap_ac_broadcast(sh, argc, argv, &param);
1313 }
1314 
1315 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1
cmd_cap_ac_13(const struct shell * sh,size_t argc,char ** argv)1316 static int cmd_cap_ac_13(const struct shell *sh, size_t argc, char **argv)
1317 {
1318 	const struct bap_broadcast_ac_param param = {
1319 		.name = "AC_13",
1320 		.stream_cnt = 2U,
1321 		.chan_cnt = 1U,
1322 	};
1323 
1324 	return cap_ac_broadcast(sh, argc, argv, &param);
1325 }
1326 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */
1327 
cmd_cap_ac_14(const struct shell * sh,size_t argc,char ** argv)1328 static int cmd_cap_ac_14(const struct shell *sh, size_t argc, char **argv)
1329 {
1330 	const struct bap_broadcast_ac_param param = {
1331 		.name = "AC_14",
1332 		.stream_cnt = 2U,
1333 		.chan_cnt = 2U,
1334 	};
1335 
1336 	return cap_ac_broadcast(sh, argc, argv, &param);
1337 }
1338 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1339 
cmd_cap_initiator(const struct shell * sh,size_t argc,char ** argv)1340 static int cmd_cap_initiator(const struct shell *sh, size_t argc, char **argv)
1341 {
1342 	if (argc > 1) {
1343 		shell_error(sh, "%s unknown parameter: %s",
1344 			    argv[0], argv[1]);
1345 	} else {
1346 		shell_error(sh, "%s Missing subcommand", argv[0]);
1347 	}
1348 
1349 	return -ENOEXEC;
1350 }
1351 
1352 SHELL_STATIC_SUBCMD_SET_CREATE(
1353 	cap_initiator_cmds,
1354 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
1355 	SHELL_CMD_ARG(discover, NULL, "Discover CAS", cmd_cap_initiator_discover, 1, 0),
1356 	SHELL_CMD_ARG(unicast_start, NULL,
1357 		      "Unicast Start [csip] [sinks <cnt> (default 1)] "
1358 		      "[sources <cnt> (default 1)] "
1359 		      "[conns (<cnt> | all) (default 1)]",
1360 		      cmd_cap_initiator_unicast_start, 1, 7),
1361 	SHELL_CMD_ARG(unicast_list, NULL, "Unicast list streams", cmd_cap_initiator_unicast_list, 1,
1362 		      0),
1363 	SHELL_CMD_ARG(unicast_update, NULL, "Unicast Update <all | stream [stream [stream...]]>",
1364 		      cmd_cap_initiator_unicast_update, 2, CAP_UNICAST_CLIENT_STREAM_COUNT),
1365 	SHELL_CMD_ARG(unicast_stop, NULL,
1366 		      "Unicast stop streams [stream [stream [stream...]]] (all by default)",
1367 		      cmd_cap_initiator_unicast_stop, 1, CAP_UNICAST_CLIENT_STREAM_COUNT),
1368 	SHELL_CMD_ARG(unicast_cancel, NULL, "Unicast cancel current procedure",
1369 		      cmd_cap_initiator_unicast_cancel, 1, 0),
1370 #if UNICAST_SINK_SUPPORTED
1371 	SHELL_CMD_ARG(ac_1, NULL, "Unicast audio configuration 1", cmd_cap_ac_1, 1, 0),
1372 #endif /* UNICAST_SINK_SUPPORTED */
1373 #if UNICAST_SRC_SUPPORTED
1374 	SHELL_CMD_ARG(ac_2, NULL, "Unicast audio configuration 2", cmd_cap_ac_2, 1, 0),
1375 #endif /* UNICAST_SRC_SUPPORTED */
1376 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1377 	SHELL_CMD_ARG(ac_3, NULL, "Unicast audio configuration 3", cmd_cap_ac_3, 1, 0),
1378 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1379 #if UNICAST_SINK_SUPPORTED
1380 	SHELL_CMD_ARG(ac_4, NULL, "Unicast audio configuration 4", cmd_cap_ac_4, 1, 0),
1381 #endif /* UNICAST_SINK_SUPPORTED */
1382 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1383 	SHELL_CMD_ARG(ac_5, NULL, "Unicast audio configuration 5", cmd_cap_ac_5, 1, 0),
1384 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1385 #if UNICAST_SINK_SUPPORTED
1386 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
1387 	SHELL_CMD_ARG(ac_6_i, NULL, "Unicast audio configuration 6(i)", cmd_cap_ac_6_i, 1, 0),
1388 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1389 #if CONFIG_BT_MAX_CONN >= 2
1390 	SHELL_CMD_ARG(ac_6_ii, NULL, "Unicast audio configuration 6(ii)", cmd_cap_ac_6_ii, 1, 0),
1391 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1392 #endif /* UNICAST_SINK_SUPPORTED */
1393 #if UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED
1394 	SHELL_CMD_ARG(ac_7_i, NULL, "Unicast audio configuration 7(i)", cmd_cap_ac_7_i, 1, 0),
1395 #if CONFIG_BT_MAX_CONN >= 2
1396 	SHELL_CMD_ARG(ac_7_ii, NULL, "Unicast audio configuration 7(ii)", cmd_cap_ac_7_ii, 1, 0),
1397 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1398 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1
1399 	SHELL_CMD_ARG(ac_8_i, NULL, "Unicast audio configuration 8(i)", cmd_cap_ac_8_i, 1, 0),
1400 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 */
1401 #if CONFIG_BT_MAX_CONN >= 2
1402 	SHELL_CMD_ARG(ac_8_ii, NULL, "Unicast audio configuration 8(ii)", cmd_cap_ac_8_ii, 1, 0),
1403 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1404 #if UNICAST_SRC_SUPPORTED
1405 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
1406 	SHELL_CMD_ARG(ac_9_i, NULL, "Unicast audio configuration 9(i)", cmd_cap_ac_9_i, 1, 0),
1407 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1 */
1408 #if CONFIG_BT_MAX_CONN >= 2
1409 	SHELL_CMD_ARG(ac_9_ii, NULL, "Unicast audio configuration 9(ii)", cmd_cap_ac_9_ii, 1, 0),
1410 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1411 	SHELL_CMD_ARG(ac_10, NULL, "Unicast audio configuration 10", cmd_cap_ac_10, 1, 0),
1412 #endif /* UNICAST_SRC_SUPPORTED */
1413 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 && CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1
1414 	SHELL_CMD_ARG(ac_11_i, NULL, "Unicast audio configuration 11(i)", cmd_cap_ac_11_i, 1, 0),
1415 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 1 &&                                        \
1416 	* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 1                                           \
1417 	*/
1418 #if CONFIG_BT_MAX_CONN >= 2
1419 	SHELL_CMD_ARG(ac_11_ii, NULL, "Unicast audio configuration 11(ii)", cmd_cap_ac_11_ii, 1, 0),
1420 #endif /* CONFIG_BT_MAX_CONN >= 2 */
1421 #endif /* UNICAST_SINK_SUPPORTED && UNICAST_SRC_SUPPORTED */
1422 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1423 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1424 	SHELL_CMD_ARG(broadcast_start, NULL, "", cmd_broadcast_start, 1, 0),
1425 	SHELL_CMD_ARG(broadcast_update, NULL, "<meta>", cmd_broadcast_update, 2, 0),
1426 	SHELL_CMD_ARG(broadcast_stop, NULL, "", cmd_broadcast_stop, 1, 0),
1427 	SHELL_CMD_ARG(broadcast_delete, NULL, "", cmd_broadcast_delete, 1, 0),
1428 	SHELL_CMD_ARG(ac_12, NULL, "Broadcast audio configuration 12", cmd_cap_ac_12, 1, 0),
1429 #if CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1
1430 	SHELL_CMD_ARG(ac_13, NULL, "Broadcast audio configuration 13", cmd_cap_ac_13, 1, 0),
1431 #endif /* CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT > 1 */
1432 	SHELL_CMD_ARG(ac_14, NULL, "Broadcast audio configuration 14", cmd_cap_ac_14, 1, 0),
1433 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1434 	SHELL_SUBCMD_SET_END);
1435 
1436 SHELL_CMD_ARG_REGISTER(cap_initiator, &cap_initiator_cmds,
1437 		       "Bluetooth CAP initiator shell commands",
1438 		       cmd_cap_initiator, 1, 1);
1439 
nonconnectable_ad_data_add(struct bt_data * data_array,const size_t data_array_size)1440 static ssize_t nonconnectable_ad_data_add(struct bt_data *data_array, const size_t data_array_size)
1441 {
1442 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1443 	if (default_source.cap_source != NULL && default_source.is_cap) {
1444 		static uint8_t ad_cap_broadcast_announcement[5] = {
1445 			BT_UUID_16_ENCODE(BT_UUID_BROADCAST_AUDIO_VAL),
1446 		};
1447 		uint32_t broadcast_id;
1448 		int err;
1449 
1450 		err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
1451 		if (err) {
1452 			printk("Unable to generate broadcast ID: %d\n", err);
1453 
1454 			return -1;
1455 		}
1456 
1457 		sys_put_le24(broadcast_id, &ad_cap_broadcast_announcement[2]);
1458 		data_array[0].type = BT_DATA_SVC_DATA16;
1459 		data_array[0].data_len = ARRAY_SIZE(ad_cap_broadcast_announcement);
1460 		data_array[0].data = ad_cap_broadcast_announcement;
1461 
1462 		return 1;
1463 	}
1464 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1465 
1466 	return 0;
1467 }
1468 
cap_initiator_ad_data_add(struct bt_data * data_array,const size_t data_array_size,const bool discoverable,const bool connectable)1469 ssize_t cap_initiator_ad_data_add(struct bt_data *data_array, const size_t data_array_size,
1470 				  const bool discoverable, const bool connectable)
1471 {
1472 	if (!discoverable) {
1473 		return 0;
1474 	}
1475 
1476 	if (!connectable) {
1477 		return nonconnectable_ad_data_add(data_array, data_array_size);
1478 	}
1479 
1480 	return 0;
1481 }
1482 
cap_initiator_pa_data_add(struct bt_data * data_array,const size_t data_array_size)1483 ssize_t cap_initiator_pa_data_add(struct bt_data *data_array, const size_t data_array_size)
1484 {
1485 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
1486 	if (default_source.cap_source != NULL && default_source.is_cap) {
1487 		/* Required size of the buffer depends on what has been
1488 		 * configured. We just use the maximum size possible.
1489 		 */
1490 		NET_BUF_SIMPLE_DEFINE_STATIC(base_buf, UINT8_MAX);
1491 		int err;
1492 
1493 		net_buf_simple_reset(&base_buf);
1494 
1495 		err = bt_cap_initiator_broadcast_get_base(default_source.cap_source, &base_buf);
1496 		if (err != 0) {
1497 			printk("Unable to get BASE: %d\n", err);
1498 
1499 			return -1;
1500 		}
1501 
1502 		data_array[0].type = BT_DATA_SVC_DATA16;
1503 		data_array[0].data_len = base_buf.len;
1504 		data_array[0].data = base_buf.data;
1505 
1506 		return 1;
1507 	}
1508 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
1509 
1510 	return 0;
1511 }
1512