1 /** @file
2 * @brief Bluetooth Basic Audio Profile shell
3 *
4 */
5
6 /*
7 * Copyright (c) 2020 Intel Corporation
8 * Copyright (c) 2022-2023 Nordic Semiconductor ASA
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <errno.h>
14 #include <stdbool.h>
15 #include <stddef.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <sys/types.h>
19
20 #include <zephyr/autoconf.h>
21 #include <zephyr/bluetooth/audio/audio.h>
22 #include <zephyr/bluetooth/audio/bap.h>
23 #include <zephyr/bluetooth/audio/bap_lc3_preset.h>
24 #include <zephyr/bluetooth/audio/cap.h>
25 #include <zephyr/bluetooth/audio/gmap.h>
26 #include <zephyr/bluetooth/audio/lc3.h>
27 #include <zephyr/bluetooth/audio/pacs.h>
28 #include <zephyr/bluetooth/addr.h>
29 #include <zephyr/bluetooth/bluetooth.h>
30 #include <zephyr/bluetooth/conn.h>
31 #include <zephyr/bluetooth/gap.h>
32 #include <zephyr/bluetooth/gatt.h>
33 #include <zephyr/bluetooth/hci_types.h>
34 #include <zephyr/bluetooth/iso.h>
35 #include <zephyr/bluetooth/uuid.h>
36 #include <zephyr/kernel.h>
37 #include <zephyr/kernel/thread_stack.h>
38 #include <zephyr/net/buf.h>
39 #include <zephyr/shell/shell.h>
40 #include <zephyr/shell/shell_string_conv.h>
41 #include <zephyr/sys/__assert.h>
42 #include <zephyr/sys/atomic.h>
43 #include <zephyr/sys/printk.h>
44 #include <zephyr/sys/byteorder.h>
45 #include <zephyr/sys/time_units.h>
46 #include <zephyr/sys/util.h>
47 #include <zephyr/sys/util_macro.h>
48 #include <zephyr/sys_clock.h>
49
50 #include "shell/bt.h"
51 #include "audio.h"
52
53 /* Determines if we can initiate streaming */
54 #define IS_BAP_INITIATOR \
55 (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) || IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT))
56
57 #define GENERATE_SINE_SUPPORTED (IS_ENABLED(CONFIG_LIBLC3) && !IS_ENABLED(CONFIG_USB_DEVICE_AUDIO))
58
59 #if defined(CONFIG_BT_BAP_UNICAST)
60
61 struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN *
62 MAX(UNICAST_SERVER_STREAM_COUNT, UNICAST_CLIENT_STREAM_COUNT)];
63
64 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
65 struct bt_bap_unicast_group *default_unicast_group;
66 static struct bt_bap_unicast_client_cb unicast_client_cbs;
67 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
68 struct bt_bap_ep *snks[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT];
69 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
70 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
71 struct bt_bap_ep *srcs[CONFIG_BT_MAX_CONN][CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT];
72 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
73 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
74 #endif /* CONFIG_BT_BAP_UNICAST */
75
76 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
77 struct shell_stream broadcast_source_streams[CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT];
78 struct broadcast_source default_source;
79 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
80 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
81 static struct shell_stream broadcast_sink_streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
82 static struct broadcast_sink default_broadcast_sink;
83 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
84
85 #if defined(CONFIG_BT_BAP_UNICAST) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
86 static struct bt_bap_stream *default_stream;
87 #endif /* CONFIG_BT_BAP_UNICAST || CONFIG_BT_BAP_BROADCAST_SOURCE */
88
89 #if IS_BAP_INITIATOR
90 /* Default to 16_2_1 */
91 struct named_lc3_preset default_sink_preset = {"16_2_1",
92 BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)};
93 struct named_lc3_preset default_source_preset = {
94 "16_2_1", BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)};
95 struct named_lc3_preset default_broadcast_source_preset = {
96 "16_2_1", BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT)};
97 #endif /* IS_BAP_INITIATOR */
98
99 static const struct named_lc3_preset lc3_unicast_presets[] = {
100 {"8_1_1", BT_BAP_LC3_UNICAST_PRESET_8_1_1(LOCATION, CONTEXT)},
101 {"8_2_1", BT_BAP_LC3_UNICAST_PRESET_8_2_1(LOCATION, CONTEXT)},
102 {"16_1_1", BT_BAP_LC3_UNICAST_PRESET_16_1_1(LOCATION, CONTEXT)},
103 {"16_2_1", BT_BAP_LC3_UNICAST_PRESET_16_2_1(LOCATION, CONTEXT)},
104 {"24_1_1", BT_BAP_LC3_UNICAST_PRESET_24_1_1(LOCATION, CONTEXT)},
105 {"24_2_1", BT_BAP_LC3_UNICAST_PRESET_24_2_1(LOCATION, CONTEXT)},
106 {"32_1_1", BT_BAP_LC3_UNICAST_PRESET_32_1_1(LOCATION, CONTEXT)},
107 {"32_2_1", BT_BAP_LC3_UNICAST_PRESET_32_2_1(LOCATION, CONTEXT)},
108 {"441_1_1", BT_BAP_LC3_UNICAST_PRESET_441_1_1(LOCATION, CONTEXT)},
109 {"441_2_1", BT_BAP_LC3_UNICAST_PRESET_441_2_1(LOCATION, CONTEXT)},
110 {"48_1_1", BT_BAP_LC3_UNICAST_PRESET_48_1_1(LOCATION, CONTEXT)},
111 {"48_2_1", BT_BAP_LC3_UNICAST_PRESET_48_2_1(LOCATION, CONTEXT)},
112 {"48_3_1", BT_BAP_LC3_UNICAST_PRESET_48_3_1(LOCATION, CONTEXT)},
113 {"48_4_1", BT_BAP_LC3_UNICAST_PRESET_48_4_1(LOCATION, CONTEXT)},
114 {"48_5_1", BT_BAP_LC3_UNICAST_PRESET_48_5_1(LOCATION, CONTEXT)},
115 {"48_6_1", BT_BAP_LC3_UNICAST_PRESET_48_6_1(LOCATION, CONTEXT)},
116 /* High-reliability presets */
117 {"8_1_2", BT_BAP_LC3_UNICAST_PRESET_8_1_2(LOCATION, CONTEXT)},
118 {"8_2_2", BT_BAP_LC3_UNICAST_PRESET_8_2_2(LOCATION, CONTEXT)},
119 {"16_1_2", BT_BAP_LC3_UNICAST_PRESET_16_1_2(LOCATION, CONTEXT)},
120 {"16_2_2", BT_BAP_LC3_UNICAST_PRESET_16_2_2(LOCATION, CONTEXT)},
121 {"24_1_2", BT_BAP_LC3_UNICAST_PRESET_24_1_2(LOCATION, CONTEXT)},
122 {"24_2_2", BT_BAP_LC3_UNICAST_PRESET_24_2_2(LOCATION, CONTEXT)},
123 {"32_1_2", BT_BAP_LC3_UNICAST_PRESET_32_1_2(LOCATION, CONTEXT)},
124 {"32_2_2", BT_BAP_LC3_UNICAST_PRESET_32_2_2(LOCATION, CONTEXT)},
125 {"441_1_2", BT_BAP_LC3_UNICAST_PRESET_441_1_2(LOCATION, CONTEXT)},
126 {"441_2_2", BT_BAP_LC3_UNICAST_PRESET_441_2_2(LOCATION, CONTEXT)},
127 {"48_1_2", BT_BAP_LC3_UNICAST_PRESET_48_1_2(LOCATION, CONTEXT)},
128 {"48_2_2", BT_BAP_LC3_UNICAST_PRESET_48_2_2(LOCATION, CONTEXT)},
129 {"48_3_2", BT_BAP_LC3_UNICAST_PRESET_48_3_2(LOCATION, CONTEXT)},
130 {"48_4_2", BT_BAP_LC3_UNICAST_PRESET_48_4_2(LOCATION, CONTEXT)},
131 {"48_5_2", BT_BAP_LC3_UNICAST_PRESET_48_5_2(LOCATION, CONTEXT)},
132 {"48_6_2", BT_BAP_LC3_UNICAST_PRESET_48_6_2(LOCATION, CONTEXT)},
133 };
134
135 static const struct named_lc3_preset lc3_broadcast_presets[] = {
136 {"8_1_1", BT_BAP_LC3_BROADCAST_PRESET_8_1_1(LOCATION, CONTEXT)},
137 {"8_2_1", BT_BAP_LC3_BROADCAST_PRESET_8_2_1(LOCATION, CONTEXT)},
138 {"16_1_1", BT_BAP_LC3_BROADCAST_PRESET_16_1_1(LOCATION, CONTEXT)},
139 {"16_2_1", BT_BAP_LC3_BROADCAST_PRESET_16_2_1(LOCATION, CONTEXT)},
140 {"24_1_1", BT_BAP_LC3_BROADCAST_PRESET_24_1_1(LOCATION, CONTEXT)},
141 {"24_2_1", BT_BAP_LC3_BROADCAST_PRESET_24_2_1(LOCATION, CONTEXT)},
142 {"32_1_1", BT_BAP_LC3_BROADCAST_PRESET_32_1_1(LOCATION, CONTEXT)},
143 {"32_2_1", BT_BAP_LC3_BROADCAST_PRESET_32_2_1(LOCATION, CONTEXT)},
144 {"441_1_1", BT_BAP_LC3_BROADCAST_PRESET_441_1_1(LOCATION, CONTEXT)},
145 {"441_2_1", BT_BAP_LC3_BROADCAST_PRESET_441_2_1(LOCATION, CONTEXT)},
146 {"48_1_1", BT_BAP_LC3_BROADCAST_PRESET_48_1_1(LOCATION, CONTEXT)},
147 {"48_2_1", BT_BAP_LC3_BROADCAST_PRESET_48_2_1(LOCATION, CONTEXT)},
148 {"48_3_1", BT_BAP_LC3_BROADCAST_PRESET_48_3_1(LOCATION, CONTEXT)},
149 {"48_4_1", BT_BAP_LC3_BROADCAST_PRESET_48_4_1(LOCATION, CONTEXT)},
150 {"48_5_1", BT_BAP_LC3_BROADCAST_PRESET_48_5_1(LOCATION, CONTEXT)},
151 {"48_6_1", BT_BAP_LC3_BROADCAST_PRESET_48_6_1(LOCATION, CONTEXT)},
152 /* High-reliability presets */
153 {"8_1_2", BT_BAP_LC3_BROADCAST_PRESET_8_1_2(LOCATION, CONTEXT)},
154 {"8_2_2", BT_BAP_LC3_BROADCAST_PRESET_8_2_2(LOCATION, CONTEXT)},
155 {"16_1_2", BT_BAP_LC3_BROADCAST_PRESET_16_1_2(LOCATION, CONTEXT)},
156 {"16_2_2", BT_BAP_LC3_BROADCAST_PRESET_16_2_2(LOCATION, CONTEXT)},
157 {"24_1_2", BT_BAP_LC3_BROADCAST_PRESET_24_1_2(LOCATION, CONTEXT)},
158 {"24_2_2", BT_BAP_LC3_BROADCAST_PRESET_24_2_2(LOCATION, CONTEXT)},
159 {"32_1_2", BT_BAP_LC3_BROADCAST_PRESET_32_1_2(LOCATION, CONTEXT)},
160 {"32_2_2", BT_BAP_LC3_BROADCAST_PRESET_32_2_2(LOCATION, CONTEXT)},
161 {"441_1_2", BT_BAP_LC3_BROADCAST_PRESET_441_1_2(LOCATION, CONTEXT)},
162 {"441_2_2", BT_BAP_LC3_BROADCAST_PRESET_441_2_2(LOCATION, CONTEXT)},
163 {"48_1_2", BT_BAP_LC3_BROADCAST_PRESET_48_1_2(LOCATION, CONTEXT)},
164 {"48_2_2", BT_BAP_LC3_BROADCAST_PRESET_48_2_2(LOCATION, CONTEXT)},
165 {"48_3_2", BT_BAP_LC3_BROADCAST_PRESET_48_3_2(LOCATION, CONTEXT)},
166 {"48_4_2", BT_BAP_LC3_BROADCAST_PRESET_48_4_2(LOCATION, CONTEXT)},
167 {"48_5_2", BT_BAP_LC3_BROADCAST_PRESET_48_5_2(LOCATION, CONTEXT)},
168 {"48_6_2", BT_BAP_LC3_BROADCAST_PRESET_48_6_2(LOCATION, CONTEXT)},
169 };
170
171 static bool initialized;
172 static unsigned long bap_stats_interval = 1000U;
173
shell_stream_from_bap_stream(struct bt_bap_stream * bap_stream)174 struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *bap_stream)
175 {
176 struct bt_cap_stream *cap_stream =
177 CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
178 struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream);
179
180 return sh_stream;
181 }
182
bap_stream_from_shell_stream(struct shell_stream * sh_stream)183 struct bt_bap_stream *bap_stream_from_shell_stream(struct shell_stream *sh_stream)
184 {
185 return &sh_stream->stream.bap_stream;
186 }
187
bap_get_stats_interval(void)188 unsigned long bap_get_stats_interval(void)
189 {
190 return bap_stats_interval;
191 }
192
bap_foreach_stream(void (* func)(struct shell_stream * sh_stream,void * data),void * data)193 void bap_foreach_stream(void (*func)(struct shell_stream *sh_stream, void *data), void *data)
194 {
195 #if defined(CONFIG_BT_BAP_UNICAST)
196 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
197 func(&unicast_streams[i], data);
198 }
199 #endif /* CONFIG_BT_BAP_UNICAST */
200
201 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
202 for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) {
203 func(&broadcast_source_streams[i], data);
204 }
205 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
206
207 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
208 for (size_t i = 0U; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
209 func(&broadcast_sink_streams[i], data);
210 }
211 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
212 }
213
214 #if defined(CONFIG_LIBLC3)
215 #include <lc3.h>
216
get_lc3_chan_alloc_from_index(const struct shell_stream * sh_stream,uint8_t index,enum bt_audio_location * chan_alloc)217 static int get_lc3_chan_alloc_from_index(const struct shell_stream *sh_stream, uint8_t index,
218 enum bt_audio_location *chan_alloc)
219 {
220 const bool has_left = (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0;
221 const bool has_right =
222 (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0;
223 const bool is_mono = sh_stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO;
224 const bool is_left = index == 0 && has_left;
225 const bool is_right = has_right && (index == 0U || (index == 1U && has_left));
226
227 /* LC3 is always Left before Right, so we can use the index and the stream channel
228 * allocation to determine if index 0 is left or right.
229 */
230 if (is_left) {
231 *chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
232 } else if (is_right) {
233 *chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
234 } else if (is_mono) {
235 *chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
236 } else {
237 /* Not suitable for USB */
238 return -EINVAL;
239 }
240
241 return 0;
242 }
243 #endif /* CONFIG_LIBLC3 */
244
245 #if defined(CONFIG_BT_AUDIO_TX)
246 static size_t tx_streaming_cnt;
247
bap_get_tx_streaming_cnt(void)248 size_t bap_get_tx_streaming_cnt(void)
249 {
250 return tx_streaming_cnt;
251 }
252
get_next_seq_num(struct bt_bap_stream * bap_stream)253 uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream)
254 {
255 struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
256 const uint32_t interval_us = bap_stream->qos->interval;
257 int64_t uptime_ticks;
258 int64_t delta_ticks;
259 uint64_t delta_us;
260 uint16_t seq_num;
261
262 if (!sh_stream->is_tx) {
263 return 0;
264 }
265
266 /* Note: This does not handle wrapping of ticks when they go above 2^(62-1) */
267 uptime_ticks = k_uptime_ticks();
268 delta_ticks = uptime_ticks - sh_stream->tx.connected_at_ticks;
269
270 delta_us = k_ticks_to_us_near64((uint64_t)delta_ticks);
271 /* Calculate the sequence number by dividing the stream uptime by the SDU interval */
272 seq_num = (uint16_t)(delta_us / interval_us);
273
274 return seq_num;
275 }
276 #endif /* CONFIG_BT_AUDIO_TX */
277
278 #if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX)
279 /* For the first call-back we push multiple audio frames to the buffer to use the
280 * controller ISO buffer to handle jitter.
281 */
282 #define PRIME_COUNT 2U
283 #define SINE_TX_POOL_SIZE (BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU))
284 NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, SINE_TX_POOL_SIZE,
285 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
286
287 #include "math.h"
288
289 #define AUDIO_VOLUME (INT16_MAX - 3000) /* codec does clipping above INT16_MAX - 3000 */
290 #define AUDIO_TONE_FREQUENCY_HZ 400
291
292 static int16_t lc3_tx_buf[LC3_MAX_NUM_SAMPLES_MONO];
293
init_lc3_encoder(struct shell_stream * sh_stream)294 static int init_lc3_encoder(struct shell_stream *sh_stream)
295 {
296 if (sh_stream == NULL) {
297 shell_error(ctx_shell, "NULL stream to init LC3");
298 return -EINVAL;
299 }
300
301 if (!sh_stream->is_tx) {
302 shell_error(ctx_shell, "Invalid stream to init LC3 encoder");
303 return -EINVAL;
304 }
305
306 if (sh_stream->tx.lc3_encoder != NULL) {
307 shell_error(ctx_shell, "Already initialized");
308 return -EALREADY;
309 }
310
311 if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) {
312 shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)",
313 sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us);
314
315 return -EINVAL;
316 }
317
318 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
319 const size_t frame_size = bap_usb_get_frame_size(sh_stream);
320
321 if (frame_size > sizeof(lc3_tx_buf)) {
322 shell_error(ctx_shell, "Cannot put %u octets in lc3_tx_buf of size %zu",
323 frame_size, sizeof(lc3_tx_buf));
324
325 return -EINVAL;
326 }
327 }
328
329 shell_print(ctx_shell,
330 "Initializing LC3 encoder for BAP stream %p with %u us duration and %u Hz "
331 "frequency",
332 bap_stream_from_shell_stream(sh_stream), sh_stream->lc3_frame_duration_us,
333 sh_stream->lc3_freq_hz);
334
335 sh_stream->tx.lc3_encoder =
336 lc3_setup_encoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz,
337 IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE : 0,
338 &sh_stream->tx.lc3_encoder_mem);
339 if (sh_stream->tx.lc3_encoder == NULL) {
340 shell_error(ctx_shell, "Failed to setup LC3 encoder - wrong parameters?\n");
341 return -EINVAL;
342 }
343
344 return 0;
345 }
346
347 /**
348 * Use the math lib to generate a sine-wave using 16 bit samples into a buffer.
349 *
350 * @param buf Destination buffer
351 * @param length_us Length of the buffer in microseconds
352 * @param frequency_hz frequency in Hz
353 * @param sample_rate_hz sample-rate in Hz.
354 */
fill_lc3_tx_buf_sin(int16_t * buf,int length_us,int frequency_hz,int sample_rate_hz)355 static void fill_lc3_tx_buf_sin(int16_t *buf, int length_us, int frequency_hz, int sample_rate_hz)
356 {
357 const uint32_t sine_period_samples = sample_rate_hz / frequency_hz;
358 const size_t num_samples = (length_us * sample_rate_hz) / USEC_PER_SEC;
359 const float step = 2 * 3.1415 / sine_period_samples;
360
361 for (size_t i = 0; i < num_samples; i++) {
362 const float sample = sinf(i * step);
363
364 buf[i] = (int16_t)(AUDIO_VOLUME * sample);
365 }
366 }
367
encode_frame(struct shell_stream * sh_stream,uint8_t index,size_t frame_cnt,struct net_buf * out_buf)368 static bool encode_frame(struct shell_stream *sh_stream, uint8_t index, size_t frame_cnt,
369 struct net_buf *out_buf)
370 {
371 const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu;
372 const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame;
373 int lc3_ret;
374
375 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
376 enum bt_audio_location chan_alloc;
377 int err;
378
379 err = get_lc3_chan_alloc_from_index(sh_stream, index, &chan_alloc);
380 if (err != 0) {
381 /* Not suitable for USB */
382 false;
383 }
384
385 /* TODO: Move the following to a function in bap_usb.c*/
386 bap_usb_get_frame(sh_stream, chan_alloc, lc3_tx_buf);
387 } else {
388 /* Generate sine wave */
389 fill_lc3_tx_buf_sin(lc3_tx_buf, sh_stream->lc3_frame_duration_us,
390 AUDIO_TONE_FREQUENCY_HZ, sh_stream->lc3_freq_hz);
391 }
392
393 if ((sh_stream->tx.encoded_cnt % bap_stats_interval) == 0) {
394 shell_print(ctx_shell, "[%zu]: Encoding frame of size %u (%u/%u)",
395 sh_stream->tx.encoded_cnt, octets_per_frame, frame_cnt + 1,
396 total_frames);
397 }
398
399 lc3_ret = lc3_encode(sh_stream->tx.lc3_encoder, LC3_PCM_FORMAT_S16, lc3_tx_buf, 1,
400 octets_per_frame, net_buf_tail(out_buf));
401 if (lc3_ret == -1) {
402 shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", lc3_ret);
403
404 return false;
405 }
406
407 out_buf->len += octets_per_frame;
408
409 return true;
410 }
411
encode_frame_block(struct shell_stream * sh_stream,size_t frame_cnt,struct net_buf * out_buf)412 static size_t encode_frame_block(struct shell_stream *sh_stream, size_t frame_cnt,
413 struct net_buf *out_buf)
414 {
415 const uint8_t chan_cnt = sh_stream->lc3_chan_cnt;
416 size_t encoded_frames = 0U;
417
418 for (uint8_t i = 0U; i < chan_cnt; i++) {
419 /* We provide the total number of decoded frames to `decode_frame` for logging
420 * purposes
421 */
422 if (encode_frame(sh_stream, i, frame_cnt, out_buf)) {
423 encoded_frames++;
424 }
425 }
426
427 return encoded_frames;
428 }
429
do_lc3_encode(struct shell_stream * sh_stream,struct net_buf * out_buf)430 static void do_lc3_encode(struct shell_stream *sh_stream, struct net_buf *out_buf)
431 {
432 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) && !bap_usb_can_get_full_sdu(sh_stream)) {
433 /* No op - Will just send empty SDU */
434 } else {
435 size_t frame_cnt = 0U;
436
437 for (uint8_t i = 0U; i < sh_stream->lc3_frame_blocks_per_sdu; i++) {
438 frame_cnt += encode_frame_block(sh_stream, frame_cnt, out_buf);
439
440 sh_stream->tx.encoded_cnt++;
441 }
442 }
443 }
444
lc3_audio_send_data(struct shell_stream * sh_stream)445 static void lc3_audio_send_data(struct shell_stream *sh_stream)
446 {
447 struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream);
448 const uint16_t tx_sdu_len = sh_stream->lc3_frame_blocks_per_sdu * sh_stream->lc3_chan_cnt *
449 sh_stream->lc3_octets_per_frame;
450 struct net_buf *buf;
451 int err;
452
453 if (!sh_stream->is_tx || !sh_stream->tx.active) {
454 /* TX has been aborted */
455 return;
456 }
457
458 if (sh_stream->tx.lc3_encoder == NULL) {
459 shell_error(ctx_shell, "LC3 encoder not setup, cannot encode data");
460 return;
461 }
462
463 if (bap_stream == NULL || bap_stream->qos == NULL) {
464 shell_error(ctx_shell, "invalid stream, aborting");
465 return;
466 }
467
468 if (tx_sdu_len == 0U || tx_sdu_len > SINE_TX_POOL_SIZE) {
469 shell_error(ctx_shell,
470 "Cannot send %u length SDU (from frame blocks per sdu %u, channel "
471 "count %u and %u octets per frame) for pool size %d",
472 tx_sdu_len, sh_stream->lc3_frame_blocks_per_sdu,
473 sh_stream->lc3_chan_cnt, sh_stream->lc3_octets_per_frame,
474 SINE_TX_POOL_SIZE);
475 return;
476 }
477
478 if (atomic_get(&sh_stream->tx.lc3_enqueue_cnt) == 0U) {
479 /* no op */
480 return;
481 }
482
483 buf = net_buf_alloc(&sine_tx_pool, K_FOREVER);
484 net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
485
486 do_lc3_encode(sh_stream, buf);
487
488 err = bt_bap_stream_send(bap_stream, buf, sh_stream->tx.seq_num);
489 if (err < 0) {
490 shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err);
491 net_buf_unref(buf);
492
493 return;
494 }
495
496 if ((sh_stream->tx.lc3_sdu_cnt % bap_stats_interval) == 0U) {
497 shell_info(ctx_shell, "[%zu]: stream %p : TX LC3: %zu (seq_num %u)",
498 sh_stream->tx.lc3_sdu_cnt, bap_stream, tx_sdu_len,
499 sh_stream->tx.seq_num);
500 }
501
502 sh_stream->tx.lc3_sdu_cnt++;
503 sh_stream->tx.seq_num++;
504 atomic_dec(&sh_stream->tx.lc3_enqueue_cnt);
505 }
506
lc3_sent_cb(struct bt_bap_stream * bap_stream)507 static void lc3_sent_cb(struct bt_bap_stream *bap_stream)
508 {
509 struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
510
511 if (!sh_stream->is_tx) {
512 return;
513 }
514
515 atomic_inc(&sh_stream->tx.lc3_enqueue_cnt);
516 }
517
encode_and_send_cb(struct shell_stream * sh_stream,void * user_data)518 static void encode_and_send_cb(struct shell_stream *sh_stream, void *user_data)
519 {
520 if (sh_stream->is_tx) {
521 lc3_audio_send_data(sh_stream);
522 }
523 }
524
lc3_encoder_thread_func(void * arg1,void * arg2,void * arg3)525 static void lc3_encoder_thread_func(void *arg1, void *arg2, void *arg3)
526 {
527 /* This will attempt to send on all TX streams.
528 * If there are no buffers available or the stream already have PRIME_COUNT outstanding SDUs
529 * the stream will not send anything.
530 *
531 * If USB is enabled it will attempt to read from buffered USB audio data.
532 * If there is no data available it will send empty SDUs
533 */
534 while (true) {
535 bap_foreach_stream(encode_and_send_cb, NULL);
536 k_sleep(K_MSEC(1));
537 }
538 }
539 #endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */
540
bap_get_named_preset(bool is_unicast,enum bt_audio_dir dir,const char * preset_arg)541 const struct named_lc3_preset *bap_get_named_preset(bool is_unicast, enum bt_audio_dir dir,
542 const char *preset_arg)
543 {
544 if (is_unicast) {
545 for (size_t i = 0U; i < ARRAY_SIZE(lc3_unicast_presets); i++) {
546 if (!strcmp(preset_arg, lc3_unicast_presets[i].name)) {
547 return &lc3_unicast_presets[i];
548 }
549 }
550 } else {
551 for (size_t i = 0U; i < ARRAY_SIZE(lc3_broadcast_presets); i++) {
552 if (!strcmp(preset_arg, lc3_broadcast_presets[i].name)) {
553 return &lc3_broadcast_presets[i];
554 }
555 }
556 }
557
558 if (IS_ENABLED(CONFIG_BT_GMAP)) {
559 return gmap_get_named_preset(is_unicast, dir, preset_arg);
560 }
561
562 return NULL;
563 }
564
565 #if defined(CONFIG_BT_PACS)
566 static const struct bt_audio_codec_cap lc3_codec_cap = BT_AUDIO_CODEC_CAP_LC3(
567 BT_AUDIO_CODEC_CAP_FREQ_ANY, BT_AUDIO_CODEC_CAP_DURATION_ANY,
568 BT_AUDIO_CODEC_CAP_CHAN_COUNT_SUPPORT(1, 2), 30, 240, MAX_CODEC_FRAMES_PER_SDU, CONTEXT);
569
570 #if defined(CONFIG_BT_PAC_SNK)
571 static struct bt_pacs_cap cap_sink = {
572 .codec_cap = &lc3_codec_cap,
573 };
574 #endif /* CONFIG_BT_PAC_SNK */
575
576 #if defined(CONFIG_BT_PAC_SRC)
577 static struct bt_pacs_cap cap_source = {
578 .codec_cap = &lc3_codec_cap,
579 };
580 #endif /* CONFIG_BT_PAC_SRC */
581 #endif /* CONFIG_BT_PACS */
582
583 #if defined(CONFIG_BT_BAP_UNICAST)
set_unicast_stream(struct bt_bap_stream * stream)584 static void set_unicast_stream(struct bt_bap_stream *stream)
585 {
586 default_stream = stream;
587
588 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
589 if (stream == bap_stream_from_shell_stream(&unicast_streams[i])) {
590 shell_print(ctx_shell, "Default stream: %u", i + 1);
591 }
592 }
593 }
594
cmd_select_unicast(const struct shell * sh,size_t argc,char * argv[])595 static int cmd_select_unicast(const struct shell *sh, size_t argc, char *argv[])
596 {
597 struct bt_bap_stream *stream;
598 unsigned long index;
599 int err = 0;
600
601 index = shell_strtoul(argv[1], 0, &err);
602 if (err != 0) {
603 shell_error(sh, "Could not parse index: %d", err);
604
605 return -ENOEXEC;
606 }
607
608 if (index > ARRAY_SIZE(unicast_streams)) {
609 shell_error(sh, "Invalid index: %lu", index);
610
611 return -ENOEXEC;
612 }
613
614 stream = bap_stream_from_shell_stream(&unicast_streams[index]);
615
616 set_unicast_stream(stream);
617
618 return 0;
619 }
620
621 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
622 static const struct bt_audio_codec_qos_pref qos_pref =
623 BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0u, 60u, 10000u, 60000u, 10000u, 60000u);
624
stream_alloc(void)625 static struct bt_bap_stream *stream_alloc(void)
626 {
627 for (size_t i = 0; i < ARRAY_SIZE(unicast_streams); i++) {
628 struct bt_bap_stream *stream = bap_stream_from_shell_stream(&unicast_streams[i]);
629
630 if (!stream->conn) {
631 return stream;
632 }
633 }
634
635 return NULL;
636 }
637
lc3_config(struct bt_conn * conn,const struct bt_bap_ep * ep,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_stream ** stream,struct bt_audio_codec_qos_pref * const pref,struct bt_bap_ascs_rsp * rsp)638 static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
639 const struct bt_audio_codec_cfg *codec_cfg, struct bt_bap_stream **stream,
640 struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
641 {
642 shell_print(ctx_shell, "ASE Codec Config: conn %p ep %p dir %u", conn, ep, dir);
643
644 print_codec_cfg(ctx_shell, 0, codec_cfg);
645
646 *stream = stream_alloc();
647 if (*stream == NULL) {
648 shell_print(ctx_shell, "No unicast_streams available");
649
650 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
651
652 return -ENOMEM;
653 }
654
655 shell_print(ctx_shell, "ASE Codec Config stream %p", *stream);
656
657 set_unicast_stream(*stream);
658
659 *pref = qos_pref;
660
661 return 0;
662 }
663
lc3_reconfig(struct bt_bap_stream * stream,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_audio_codec_qos_pref * const pref,struct bt_bap_ascs_rsp * rsp)664 static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
665 const struct bt_audio_codec_cfg *codec_cfg,
666 struct bt_audio_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
667 {
668 shell_print(ctx_shell, "ASE Codec Reconfig: stream %p", stream);
669
670 print_codec_cfg(ctx_shell, 0, codec_cfg);
671
672 if (default_stream == NULL) {
673 set_unicast_stream(stream);
674 }
675
676 *pref = qos_pref;
677
678 return 0;
679 }
680
lc3_qos(struct bt_bap_stream * stream,const struct bt_audio_codec_qos * qos,struct bt_bap_ascs_rsp * rsp)681 static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos *qos,
682 struct bt_bap_ascs_rsp *rsp)
683 {
684 shell_print(ctx_shell, "QoS: stream %p %p", stream, qos);
685
686 print_qos(ctx_shell, qos);
687
688 return 0;
689 }
690
lc3_enable(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)691 static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
692 struct bt_bap_ascs_rsp *rsp)
693 {
694 shell_print(ctx_shell, "Enable: stream %p meta_len %zu", stream,
695 meta_len);
696
697 return 0;
698 }
699
lc3_start(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)700 static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
701 {
702 shell_print(ctx_shell, "Start: stream %p", stream);
703
704 return 0;
705 }
706
707
meta_data_func_cb(struct bt_data * data,void * user_data)708 static bool meta_data_func_cb(struct bt_data *data, void *user_data)
709 {
710 struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
711
712 if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
713 printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
714 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
715 return false;
716 }
717
718 return true;
719 }
720
lc3_metadata(struct bt_bap_stream * stream,const uint8_t meta[],size_t meta_len,struct bt_bap_ascs_rsp * rsp)721 static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
722 struct bt_bap_ascs_rsp *rsp)
723 {
724 shell_print(ctx_shell, "Metadata: stream %p meta_len %zu", stream,
725 meta_len);
726
727 return bt_audio_data_parse(meta, meta_len, meta_data_func_cb, rsp);
728 }
729
lc3_disable(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)730 static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
731 {
732 shell_print(ctx_shell, "Disable: stream %p", stream);
733
734 return 0;
735 }
736
lc3_stop(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)737 static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
738 {
739 shell_print(ctx_shell, "Stop: stream %p", stream);
740
741 return 0;
742 }
743
lc3_release(struct bt_bap_stream * stream,struct bt_bap_ascs_rsp * rsp)744 static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
745 {
746 shell_print(ctx_shell, "Release: stream %p", stream);
747
748 if (stream == default_stream) {
749 default_stream = NULL;
750 }
751
752 return 0;
753 }
754
755 static const struct bt_bap_unicast_server_cb unicast_server_cb = {
756 .config = lc3_config,
757 .reconfig = lc3_reconfig,
758 .qos = lc3_qos,
759 .enable = lc3_enable,
760 .start = lc3_start,
761 .metadata = lc3_metadata,
762 .disable = lc3_disable,
763 .stop = lc3_stop,
764 .release = lc3_release,
765 };
766 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
767
strmeta(const char * name)768 static uint16_t strmeta(const char *name)
769 {
770 if (strcmp(name, "Unspecified") == 0) {
771 return BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED;
772 } else if (strcmp(name, "Conversational") == 0) {
773 return BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL;
774 } else if (strcmp(name, "Media") == 0) {
775 return BT_AUDIO_CONTEXT_TYPE_MEDIA;
776 } else if (strcmp(name, "Game") == 0) {
777 return BT_AUDIO_CONTEXT_TYPE_GAME;
778 } else if (strcmp(name, "Instructional") == 0) {
779 return BT_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL;
780 } else if (strcmp(name, "VoiceAssistants") == 0) {
781 return BT_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS;
782 } else if (strcmp(name, "Live") == 0) {
783 return BT_AUDIO_CONTEXT_TYPE_LIVE;
784 } else if (strcmp(name, "SoundEffects") == 0) {
785 return BT_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS;
786 } else if (strcmp(name, "Notifications") == 0) {
787 return BT_AUDIO_CONTEXT_TYPE_NOTIFICATIONS;
788 } else if (strcmp(name, "Ringtone") == 0) {
789 return BT_AUDIO_CONTEXT_TYPE_RINGTONE;
790 } else if (strcmp(name, "Alerts") == 0) {
791 return BT_AUDIO_CONTEXT_TYPE_ALERTS;
792 } else if (strcmp(name, "EmergencyAlarm") == 0) {
793 return BT_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM;
794 }
795
796 return 0u;
797 }
798
set_metadata(struct bt_audio_codec_cfg * codec_cfg,const char * meta_str)799 static int set_metadata(struct bt_audio_codec_cfg *codec_cfg, const char *meta_str)
800 {
801 uint16_t context;
802
803 context = strmeta(meta_str);
804 if (context == 0) {
805 return -ENOEXEC;
806 }
807
808 /* TODO: Check the type and only overwrite the streaming context */
809 sys_put_le16(context, codec_cfg->meta);
810
811 return 0;
812 }
813
814 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
bap_ac_create_unicast_group(const struct bap_unicast_ac_param * param,struct shell_stream * snk_uni_streams[],size_t snk_cnt,struct shell_stream * src_uni_streams[],size_t src_cnt)815 int bap_ac_create_unicast_group(const struct bap_unicast_ac_param *param,
816 struct shell_stream *snk_uni_streams[], size_t snk_cnt,
817 struct shell_stream *src_uni_streams[], size_t src_cnt)
818 {
819 struct bt_bap_unicast_group_stream_param snk_group_stream_params[BAP_UNICAST_AC_MAX_SNK] = {
820 0};
821 struct bt_bap_unicast_group_stream_param src_group_stream_params[BAP_UNICAST_AC_MAX_SRC] = {
822 0};
823 struct bt_bap_unicast_group_stream_pair_param pair_params[BAP_UNICAST_AC_MAX_PAIR] = {0};
824 struct bt_bap_unicast_group_param group_param = {0};
825 struct bt_audio_codec_qos *snk_qos[BAP_UNICAST_AC_MAX_SNK];
826 struct bt_audio_codec_qos *src_qos[BAP_UNICAST_AC_MAX_SRC];
827 size_t snk_stream_cnt = 0U;
828 size_t src_stream_cnt = 0U;
829 size_t pair_cnt = 0U;
830
831 for (size_t i = 0U; i < snk_cnt; i++) {
832 snk_qos[i] = &snk_uni_streams[i]->qos;
833 }
834
835 for (size_t i = 0U; i < src_cnt; i++) {
836 src_qos[i] = &src_uni_streams[i]->qos;
837 }
838
839 /* Create Group
840 *
841 * First setup the individual stream parameters and then match them in pairs by connection
842 * and direction
843 */
844 for (size_t i = 0U; i < snk_cnt; i++) {
845 snk_group_stream_params[i].qos = snk_qos[i];
846 snk_group_stream_params[i].stream =
847 bap_stream_from_shell_stream(snk_uni_streams[i]);
848 }
849 for (size_t i = 0U; i < src_cnt; i++) {
850 src_group_stream_params[i].qos = src_qos[i];
851 src_group_stream_params[i].stream =
852 bap_stream_from_shell_stream(src_uni_streams[i]);
853 }
854
855 for (size_t i = 0U; i < param->conn_cnt; i++) {
856 for (size_t j = 0; j < MAX(param->snk_cnt[i], param->src_cnt[i]); j++) {
857 if (param->snk_cnt[i] > j) {
858 pair_params[pair_cnt].tx_param =
859 &snk_group_stream_params[snk_stream_cnt++];
860 } else {
861 pair_params[pair_cnt].tx_param = NULL;
862 }
863
864 if (param->src_cnt[i] > j) {
865 pair_params[pair_cnt].rx_param =
866 &src_group_stream_params[src_stream_cnt++];
867 } else {
868 pair_params[pair_cnt].rx_param = NULL;
869 }
870
871 pair_cnt++;
872 }
873 }
874
875 group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
876 group_param.params = pair_params;
877 group_param.params_count = pair_cnt;
878
879 return bt_bap_unicast_group_create(&group_param, &default_unicast_group);
880 }
881
stream_dir(const struct bt_bap_stream * stream)882 static uint8_t stream_dir(const struct bt_bap_stream *stream)
883 {
884 if (stream->conn) {
885 uint8_t conn_index = bt_conn_index(stream->conn);
886
887 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
888 for (size_t i = 0; i < ARRAY_SIZE(snks[conn_index]); i++) {
889 const struct bt_bap_ep *snk_ep = snks[conn_index][i];
890
891 if (snk_ep != NULL && stream->ep == snk_ep) {
892 return BT_AUDIO_DIR_SINK;
893 }
894 }
895 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
896
897 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
898 for (size_t i = 0; i < ARRAY_SIZE(srcs[conn_index]); i++) {
899 const struct bt_bap_ep *src_ep = srcs[conn_index][i];
900
901 if (src_ep != NULL && stream->ep == src_ep) {
902 return BT_AUDIO_DIR_SOURCE;
903 }
904 }
905 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
906 }
907
908 __ASSERT(false, "Invalid stream");
909 return 0;
910 }
911
print_remote_codec_cap(const struct bt_conn * conn,const struct bt_audio_codec_cap * codec_cap,enum bt_audio_dir dir)912 static void print_remote_codec_cap(const struct bt_conn *conn,
913 const struct bt_audio_codec_cap *codec_cap,
914 enum bt_audio_dir dir)
915 {
916 shell_print(ctx_shell, "conn %p: codec_cap %p dir 0x%02x", conn, codec_cap,
917 dir);
918
919 print_codec_cap(ctx_shell, 0, codec_cap);
920 }
921
922 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
add_sink(const struct bt_conn * conn,struct bt_bap_ep * ep)923 static void add_sink(const struct bt_conn *conn, struct bt_bap_ep *ep)
924 {
925 const uint8_t conn_index = bt_conn_index(conn);
926
927 for (size_t i = 0U; i < ARRAY_SIZE(snks[conn_index]); i++) {
928 if (snks[conn_index][i] == NULL) {
929 shell_print(ctx_shell, "Conn: %p, Sink #%zu: ep %p", conn, i, ep);
930
931 snks[conn_index][i] = ep;
932 return;
933 }
934 }
935
936 shell_error(ctx_shell, "Could not add more sink endpoints");
937 }
938 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
939
940 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
add_source(const struct bt_conn * conn,struct bt_bap_ep * ep)941 static void add_source(const struct bt_conn *conn, struct bt_bap_ep *ep)
942 {
943 const uint8_t conn_index = bt_conn_index(conn);
944
945 for (size_t i = 0U; i < ARRAY_SIZE(srcs[conn_index]); i++) {
946 if (srcs[conn_index][i] == NULL) {
947 shell_print(ctx_shell, "Conn: %p, Source #%zu: ep %p", conn, i, ep);
948
949 srcs[conn_index][i] = ep;
950 return;
951 }
952 }
953
954 shell_error(ctx_shell, "Could not add more sink endpoints");
955 }
956 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
957
pac_record_cb(struct bt_conn * conn,enum bt_audio_dir dir,const struct bt_audio_codec_cap * codec_cap)958 static void pac_record_cb(struct bt_conn *conn, enum bt_audio_dir dir,
959 const struct bt_audio_codec_cap *codec_cap)
960 {
961 print_remote_codec_cap(conn, codec_cap, dir);
962 }
963
endpoint_cb(struct bt_conn * conn,enum bt_audio_dir dir,struct bt_bap_ep * ep)964 static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_bap_ep *ep)
965 {
966 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
967 if (dir == BT_AUDIO_DIR_SINK) {
968 add_sink(conn, ep);
969 }
970 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
971
972 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
973 if (dir == BT_AUDIO_DIR_SOURCE) {
974 add_source(conn, ep);
975 }
976 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0*/
977 }
978
discover_cb(struct bt_conn * conn,int err,enum bt_audio_dir dir)979 static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir)
980 {
981 shell_print(ctx_shell, "Discover complete: err %d", err);
982 }
983
discover_all(struct bt_conn * conn,int err,enum bt_audio_dir dir)984 static void discover_all(struct bt_conn *conn, int err, enum bt_audio_dir dir)
985 {
986 /* Sinks discovery complete, now discover sources */
987 if (dir == BT_AUDIO_DIR_SINK) {
988 dir = BT_AUDIO_DIR_SOURCE;
989 unicast_client_cbs.discover = discover_cb;
990
991 err = bt_bap_unicast_client_discover(default_conn, dir);
992 if (err) {
993 shell_error(ctx_shell, "bt_bap_unicast_client_discover err %d", err);
994 }
995 }
996 }
997
unicast_client_location_cb(struct bt_conn * conn,enum bt_audio_dir dir,enum bt_audio_location loc)998 static void unicast_client_location_cb(struct bt_conn *conn,
999 enum bt_audio_dir dir,
1000 enum bt_audio_location loc)
1001 {
1002 shell_print(ctx_shell, "dir %u loc %X\n", dir, loc);
1003 }
1004
available_contexts_cb(struct bt_conn * conn,enum bt_audio_context snk_ctx,enum bt_audio_context src_ctx)1005 static void available_contexts_cb(struct bt_conn *conn,
1006 enum bt_audio_context snk_ctx,
1007 enum bt_audio_context src_ctx)
1008 {
1009 shell_print(ctx_shell, "snk ctx %u src ctx %u\n", snk_ctx, src_ctx);
1010 }
1011
config_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1012 static void config_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1013 enum bt_bap_ascs_reason reason)
1014 {
1015 shell_print(ctx_shell, "stream %p config operation rsp_code %u reason %u",
1016 stream, rsp_code, reason);
1017
1018 if (default_stream == NULL) {
1019 default_stream = stream;
1020 }
1021 }
1022
qos_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1023 static void qos_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1024 enum bt_bap_ascs_reason reason)
1025 {
1026 shell_print(ctx_shell, "stream %p qos operation rsp_code %u reason %u",
1027 stream, rsp_code, reason);
1028 }
1029
enable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1030 static void enable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1031 enum bt_bap_ascs_reason reason)
1032 {
1033 shell_print(ctx_shell, "stream %p enable operation rsp_code %u reason %u",
1034 stream, rsp_code, reason);
1035 }
1036
start_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1037 static void start_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1038 enum bt_bap_ascs_reason reason)
1039 {
1040 shell_print(ctx_shell, "stream %p start operation rsp_code %u reason %u",
1041 stream, rsp_code, reason);
1042 }
1043
stop_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1044 static void stop_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1045 enum bt_bap_ascs_reason reason)
1046 {
1047 shell_print(ctx_shell, "stream %p stop operation rsp_code %u reason %u",
1048 stream, rsp_code, reason);
1049 }
1050
disable_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1051 static void disable_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1052 enum bt_bap_ascs_reason reason)
1053 {
1054 shell_print(ctx_shell, "stream %p disable operation rsp_code %u reason %u",
1055 stream, rsp_code, reason);
1056 }
1057
metadata_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1058 static void metadata_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1059 enum bt_bap_ascs_reason reason)
1060 {
1061 shell_print(ctx_shell, "stream %p metadata operation rsp_code %u reason %u",
1062 stream, rsp_code, reason);
1063 }
1064
release_cb(struct bt_bap_stream * stream,enum bt_bap_ascs_rsp_code rsp_code,enum bt_bap_ascs_reason reason)1065 static void release_cb(struct bt_bap_stream *stream, enum bt_bap_ascs_rsp_code rsp_code,
1066 enum bt_bap_ascs_reason reason)
1067 {
1068 shell_print(ctx_shell, "stream %p release operation rsp_code %u reason %u",
1069 stream, rsp_code, reason);
1070 }
1071
1072 static struct bt_bap_unicast_client_cb unicast_client_cbs = {
1073 .location = unicast_client_location_cb,
1074 .available_contexts = available_contexts_cb,
1075 .config = config_cb,
1076 .qos = qos_cb,
1077 .enable = enable_cb,
1078 .start = start_cb,
1079 .stop = stop_cb,
1080 .disable = disable_cb,
1081 .metadata = metadata_cb,
1082 .release = release_cb,
1083 .pac_record = pac_record_cb,
1084 .endpoint = endpoint_cb,
1085 };
1086
cmd_discover(const struct shell * sh,size_t argc,char * argv[])1087 static int cmd_discover(const struct shell *sh, size_t argc, char *argv[])
1088 {
1089 static bool cbs_registered;
1090 enum bt_audio_dir dir;
1091 uint8_t conn_index;
1092 int err;
1093
1094 if (!default_conn) {
1095 shell_error(sh, "Not connected");
1096 return -ENOEXEC;
1097 }
1098
1099 if (!initialized) {
1100 shell_error(sh, "Not initialized");
1101 return -ENOEXEC;
1102 }
1103
1104 if (!cbs_registered) {
1105 err = bt_bap_unicast_client_register_cb(&unicast_client_cbs);
1106
1107 if (err != 0) {
1108 shell_error(sh, "Failed to register unicast client callbacks: %d", err);
1109 return err;
1110 }
1111
1112 cbs_registered = true;
1113 }
1114
1115 unicast_client_cbs.discover = discover_all;
1116 dir = BT_AUDIO_DIR_SINK;
1117
1118 if (argc > 1) {
1119 if (!strcmp(argv[1], "sink")) {
1120 unicast_client_cbs.discover = discover_cb;
1121 } else if (!strcmp(argv[1], "source")) {
1122 unicast_client_cbs.discover = discover_cb;
1123 dir = BT_AUDIO_DIR_SOURCE;
1124 } else {
1125 shell_error(sh, "Unsupported dir: %s", argv[1]);
1126 return -ENOEXEC;
1127 }
1128 }
1129
1130 err = bt_bap_unicast_client_discover(default_conn, dir);
1131 if (err != 0) {
1132 return -ENOEXEC;
1133 }
1134
1135 conn_index = bt_conn_index(default_conn);
1136 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
1137 memset(srcs[conn_index], 0, sizeof(srcs[conn_index]));
1138 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
1139
1140 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
1141 memset(snks[conn_index], 0, sizeof(snks[conn_index]));
1142 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
1143
1144 return 0;
1145 }
1146
cmd_config(const struct shell * sh,size_t argc,char * argv[])1147 static int cmd_config(const struct shell *sh, size_t argc, char *argv[])
1148 {
1149 enum bt_audio_location location = BT_AUDIO_LOCATION_MONO_AUDIO;
1150 const struct named_lc3_preset *named_preset;
1151 struct shell_stream *uni_stream;
1152 struct bt_bap_stream *bap_stream;
1153 struct bt_bap_ep *ep = NULL;
1154 enum bt_audio_dir dir;
1155 unsigned long index;
1156 uint8_t conn_index;
1157 int err = 0;
1158
1159 if (!default_conn) {
1160 shell_error(sh, "Not connected");
1161 return -ENOEXEC;
1162 }
1163 conn_index = bt_conn_index(default_conn);
1164
1165 if (default_stream == NULL) {
1166 bap_stream = bap_stream_from_shell_stream(&unicast_streams[0]);
1167 } else {
1168 bap_stream = default_stream;
1169 }
1170
1171 index = shell_strtoul(argv[2], 0, &err);
1172 if (err != 0) {
1173 shell_error(sh, "Could not parse index: %d", err);
1174
1175 return -ENOEXEC;
1176 }
1177
1178 if (index > ARRAY_SIZE(unicast_streams)) {
1179 shell_error(sh, "Invalid index: %lu", index);
1180
1181 return -ENOEXEC;
1182 }
1183
1184 if (false) {
1185
1186 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
1187 } else if (!strcmp(argv[1], "sink")) {
1188 dir = BT_AUDIO_DIR_SINK;
1189 ep = snks[conn_index][index];
1190
1191 named_preset = &default_sink_preset;
1192 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
1193
1194 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
1195 } else if (!strcmp(argv[1], "source")) {
1196 dir = BT_AUDIO_DIR_SOURCE;
1197 ep = srcs[conn_index][index];
1198
1199 named_preset = &default_source_preset;
1200 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
1201 } else {
1202 shell_error(sh, "Unsupported dir: %s", argv[1]);
1203 return -ENOEXEC;
1204 }
1205
1206 if (!ep) {
1207 shell_error(sh, "Unable to find endpoint");
1208 return -ENOEXEC;
1209 }
1210
1211 for (size_t i = 3U; i < argc; i++) {
1212 const char *arg = argv[i];
1213
1214 /* argc needs to be larger than `i` to parse the argument value */
1215 if (argc <= i) {
1216 shell_help(sh);
1217
1218 return SHELL_CMD_HELP_PRINTED;
1219 }
1220
1221 if (strcmp(arg, "loc") == 0) {
1222 unsigned long loc_bits;
1223
1224 arg = argv[++i];
1225 loc_bits = shell_strtoul(arg, 0, &err);
1226 if (err != 0) {
1227 shell_error(sh, "Could not parse loc_bits: %d", err);
1228
1229 return -ENOEXEC;
1230 }
1231
1232 if (loc_bits > BT_AUDIO_LOCATION_ANY) {
1233 shell_error(sh, "Invalid loc_bits: %lu", loc_bits);
1234
1235 return -ENOEXEC;
1236 }
1237
1238 location = (enum bt_audio_location)loc_bits;
1239 } else if (strcmp(arg, "preset") == 0) {
1240 if (argc > i) {
1241 arg = argv[++i];
1242
1243 named_preset = bap_get_named_preset(true, dir, arg);
1244 if (named_preset == NULL) {
1245 shell_error(sh, "Unable to parse named_preset %s", arg);
1246 return -ENOEXEC;
1247 }
1248 } else {
1249 shell_help(sh);
1250
1251 return SHELL_CMD_HELP_PRINTED;
1252 }
1253 } else {
1254 shell_help(sh);
1255
1256 return SHELL_CMD_HELP_PRINTED;
1257 }
1258 }
1259
1260 uni_stream = shell_stream_from_bap_stream(bap_stream);
1261 copy_unicast_stream_preset(uni_stream, named_preset);
1262
1263 /* If location has been modified, we update the location in the codec configuration */
1264 struct bt_audio_codec_cfg *codec_cfg = &uni_stream->codec_cfg;
1265
1266 for (size_t i = 0U; i < codec_cfg->data_len;) {
1267 const uint8_t len = codec_cfg->data[i++];
1268 uint8_t *value;
1269 uint8_t data_len;
1270 uint8_t type;
1271
1272 if (len == 0 || len > codec_cfg->data_len - i) {
1273 /* Invalid len field */
1274 return false;
1275 }
1276
1277 type = codec_cfg->data[i++];
1278 value = &codec_cfg->data[i];
1279
1280 if (type == BT_AUDIO_CODEC_CFG_CHAN_ALLOC) {
1281 const uint32_t loc_32 = location;
1282
1283 sys_put_le32(loc_32, value);
1284
1285 shell_print(sh, "Setting location to 0x%08X", location);
1286 break;
1287 }
1288
1289 data_len = len - sizeof(type);
1290
1291 /* Since we are incrementing i by the value_len, we don't need to increment
1292 * it further in the `for` statement
1293 */
1294 i += data_len;
1295 }
1296
1297 if (bap_stream->ep == ep) {
1298 err = bt_bap_stream_reconfig(bap_stream, &uni_stream->codec_cfg);
1299 if (err != 0) {
1300 shell_error(sh, "Unable reconfig stream: %d", err);
1301 return -ENOEXEC;
1302 }
1303 } else {
1304 err = bt_bap_stream_config(default_conn, bap_stream, ep,
1305 &uni_stream->codec_cfg);
1306 if (err != 0) {
1307 shell_error(sh, "Unable to config stream: %d", err);
1308 return err;
1309 }
1310 }
1311
1312 shell_print(sh, "ASE config: preset %s", named_preset->name);
1313
1314 return 0;
1315 }
1316
cmd_stream_qos(const struct shell * sh,size_t argc,char * argv[])1317 static int cmd_stream_qos(const struct shell *sh, size_t argc, char *argv[])
1318 {
1319 struct bt_audio_codec_qos *qos;
1320 unsigned long interval;
1321 int err = 0;
1322
1323 if (default_stream == NULL) {
1324 shell_print(sh, "No stream selected");
1325 return -ENOEXEC;
1326 }
1327
1328 qos = default_stream->qos;
1329
1330 if (qos == NULL) {
1331 shell_print(sh, "Stream not configured");
1332 return -ENOEXEC;
1333 }
1334
1335 interval = shell_strtoul(argv[1], 0, &err);
1336 if (err != 0) {
1337 return -ENOEXEC;
1338 }
1339
1340 if (!IN_RANGE(interval, BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX)) {
1341 return -ENOEXEC;
1342 }
1343
1344 qos->interval = interval;
1345
1346 if (argc > 2) {
1347 unsigned long framing;
1348
1349 framing = shell_strtoul(argv[2], 0, &err);
1350 if (err != 0) {
1351 return -ENOEXEC;
1352 }
1353
1354 if (framing != BT_ISO_FRAMING_UNFRAMED && framing != BT_ISO_FRAMING_FRAMED) {
1355 return -ENOEXEC;
1356 }
1357
1358 qos->framing = framing;
1359 }
1360
1361 if (argc > 3) {
1362 unsigned long latency;
1363
1364 latency = shell_strtoul(argv[3], 0, &err);
1365 if (err != 0) {
1366 return -ENOEXEC;
1367 }
1368
1369 if (!IN_RANGE(latency, BT_ISO_LATENCY_MIN, BT_ISO_LATENCY_MAX)) {
1370 return -ENOEXEC;
1371 }
1372
1373 qos->latency = latency;
1374 }
1375
1376 if (argc > 4) {
1377 unsigned long pd;
1378
1379 pd = shell_strtoul(argv[4], 0, &err);
1380 if (err != 0) {
1381 return -ENOEXEC;
1382 }
1383
1384 if (pd > BT_AUDIO_PD_MAX) {
1385 return -ENOEXEC;
1386 }
1387
1388 qos->pd = pd;
1389 }
1390
1391 if (argc > 5) {
1392 unsigned long sdu;
1393
1394 sdu = shell_strtoul(argv[5], 0, &err);
1395 if (err != 0) {
1396 return -ENOEXEC;
1397 }
1398
1399 if (sdu > BT_ISO_MAX_SDU) {
1400 return -ENOEXEC;
1401 }
1402
1403 qos->sdu = sdu;
1404 }
1405
1406 if (argc > 6) {
1407 unsigned long phy;
1408
1409 phy = shell_strtoul(argv[6], 0, &err);
1410 if (err != 0) {
1411 return -ENOEXEC;
1412 }
1413
1414 if (phy != BT_GAP_LE_PHY_1M && phy != BT_GAP_LE_PHY_2M &&
1415 phy != BT_GAP_LE_PHY_CODED) {
1416 return -ENOEXEC;
1417 }
1418
1419 qos->phy = phy;
1420 }
1421
1422 if (argc > 7) {
1423 unsigned long rtn;
1424
1425 rtn = shell_strtoul(argv[7], 0, &err);
1426 if (err != 0) {
1427 return -ENOEXEC;
1428 }
1429
1430 if (rtn > BT_ISO_CONNECTED_RTN_MAX) {
1431 return -ENOEXEC;
1432 }
1433
1434 qos->rtn = rtn;
1435 }
1436
1437 return 0;
1438 }
1439
create_unicast_group(const struct shell * sh)1440 static int create_unicast_group(const struct shell *sh)
1441 {
1442 struct bt_bap_unicast_group_stream_pair_param pair_param[ARRAY_SIZE(unicast_streams)];
1443 struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(unicast_streams)];
1444 struct bt_bap_unicast_group_param group_param;
1445 size_t source_cnt = 0;
1446 size_t sink_cnt = 0;
1447 size_t cnt = 0;
1448 int err;
1449
1450 memset(pair_param, 0, sizeof(pair_param));
1451 memset(stream_params, 0, sizeof(stream_params));
1452 memset(&group_param, 0, sizeof(group_param));
1453
1454 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
1455 struct bt_bap_stream *stream = bap_stream_from_shell_stream(&unicast_streams[i]);
1456 struct shell_stream *uni_stream = &unicast_streams[i];
1457
1458 if (stream->ep != NULL) {
1459 struct bt_bap_unicast_group_stream_param *stream_param;
1460
1461 stream_param = &stream_params[cnt];
1462
1463 stream_param->stream = stream;
1464 if (stream_dir(stream) == BT_AUDIO_DIR_SINK) {
1465 stream_param->qos = &uni_stream->qos;
1466 pair_param[sink_cnt++].tx_param = stream_param;
1467 } else {
1468 stream_param->qos = &uni_stream->qos;
1469 pair_param[source_cnt++].rx_param = stream_param;
1470 }
1471
1472 cnt++;
1473 }
1474 }
1475
1476 if (cnt == 0U) {
1477 shell_error(sh, "Stream cnt is 0");
1478
1479 return -ENOEXEC;
1480 }
1481
1482 group_param.packing = BT_ISO_PACKING_SEQUENTIAL;
1483 group_param.params = pair_param;
1484 group_param.params_count = MAX(source_cnt, sink_cnt);
1485
1486 err = bt_bap_unicast_group_create(&group_param,
1487 &default_unicast_group);
1488 if (err != 0) {
1489 shell_error(sh,
1490 "Unable to create default unicast group: %d",
1491 err);
1492
1493 return -ENOEXEC;
1494 }
1495
1496 return 0;
1497 }
1498
cmd_qos(const struct shell * sh,size_t argc,char * argv[])1499 static int cmd_qos(const struct shell *sh, size_t argc, char *argv[])
1500 {
1501 int err;
1502
1503 if (default_stream == NULL) {
1504 shell_print(sh, "No stream selected");
1505 return -ENOEXEC;
1506 }
1507
1508 if (default_conn == NULL) {
1509 shell_error(sh, "Not connected");
1510 return -ENOEXEC;
1511 }
1512
1513 if (default_unicast_group == NULL) {
1514 err = create_unicast_group(sh);
1515 if (err != 0) {
1516 return err;
1517 }
1518 }
1519
1520 err = bt_bap_stream_qos(default_conn, default_unicast_group);
1521 if (err) {
1522 shell_error(sh, "Unable to setup QoS: %d", err);
1523 return -ENOEXEC;
1524 }
1525
1526 return 0;
1527 }
1528
cmd_enable(const struct shell * sh,size_t argc,char * argv[])1529 static int cmd_enable(const struct shell *sh, size_t argc, char *argv[])
1530 {
1531 struct bt_audio_codec_cfg *codec_cfg;
1532 int err;
1533
1534 if (default_stream == NULL) {
1535 shell_error(sh, "No stream selected");
1536 return -ENOEXEC;
1537 }
1538
1539 codec_cfg = default_stream->codec_cfg;
1540
1541 if (argc > 1) {
1542 err = set_metadata(codec_cfg, argv[1]);
1543 if (err != 0) {
1544 shell_error(sh, "Unable to handle metadata update: %d", err);
1545 return err;
1546 }
1547 }
1548
1549 err = bt_bap_stream_enable(default_stream, codec_cfg->meta, codec_cfg->meta_len);
1550 if (err) {
1551 shell_error(sh, "Unable to enable Channel");
1552 return -ENOEXEC;
1553 }
1554
1555 return 0;
1556 }
1557
cmd_stop(const struct shell * sh,size_t argc,char * argv[])1558 static int cmd_stop(const struct shell *sh, size_t argc, char *argv[])
1559 {
1560 int err;
1561
1562 if (default_stream == NULL) {
1563 shell_error(sh, "No stream selected");
1564 return -ENOEXEC;
1565 }
1566
1567 err = bt_bap_stream_stop(default_stream);
1568 if (err) {
1569 shell_error(sh, "Unable to stop Channel");
1570 return -ENOEXEC;
1571 }
1572
1573 return 0;
1574 }
1575
cmd_connect(const struct shell * sh,size_t argc,char * argv[])1576 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
1577 {
1578 int err;
1579
1580 if (default_stream == NULL) {
1581 shell_error(sh, "No stream selected");
1582 return -ENOEXEC;
1583 }
1584
1585 err = bt_bap_stream_connect(default_stream);
1586 if (err) {
1587 shell_error(sh, "Unable to connect stream");
1588 return -ENOEXEC;
1589 }
1590
1591 return 0;
1592 }
1593 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1594
cmd_metadata(const struct shell * sh,size_t argc,char * argv[])1595 static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[])
1596 {
1597 struct bt_audio_codec_cfg *codec_cfg;
1598 int err;
1599
1600 if (default_stream == NULL) {
1601 shell_error(sh, "No stream selected");
1602 return -ENOEXEC;
1603 }
1604
1605 codec_cfg = default_stream->codec_cfg;
1606
1607 if (argc > 1) {
1608 err = set_metadata(codec_cfg, argv[1]);
1609 if (err != 0) {
1610 shell_error(sh, "Unable to handle metadata update: %d", err);
1611 return err;
1612 }
1613 }
1614
1615 err = bt_bap_stream_metadata(default_stream, codec_cfg->meta, codec_cfg->meta_len);
1616 if (err) {
1617 shell_error(sh, "Unable to set Channel metadata");
1618 return -ENOEXEC;
1619 }
1620
1621 return 0;
1622 }
1623
cmd_start(const struct shell * sh,size_t argc,char * argv[])1624 static int cmd_start(const struct shell *sh, size_t argc, char *argv[])
1625 {
1626 int err;
1627
1628 if (default_stream == NULL) {
1629 shell_error(sh, "No stream selected");
1630 return -ENOEXEC;
1631 }
1632
1633 err = bt_bap_stream_start(default_stream);
1634 if (err) {
1635 shell_error(sh, "Unable to start Channel");
1636 return -ENOEXEC;
1637 }
1638
1639 return 0;
1640 }
1641
cmd_disable(const struct shell * sh,size_t argc,char * argv[])1642 static int cmd_disable(const struct shell *sh, size_t argc, char *argv[])
1643 {
1644 int err;
1645
1646 if (default_stream == NULL) {
1647 shell_error(sh, "No stream selected");
1648 return -ENOEXEC;
1649 }
1650
1651 err = bt_bap_stream_disable(default_stream);
1652 if (err) {
1653 shell_error(sh, "Unable to disable Channel");
1654 return -ENOEXEC;
1655 }
1656
1657 return 0;
1658 }
1659
1660 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
conn_list_eps(struct bt_conn * conn,void * data)1661 static void conn_list_eps(struct bt_conn *conn, void *data)
1662 {
1663 const struct shell *sh = (const struct shell *)data;
1664 uint8_t conn_index = bt_conn_index(conn);
1665
1666 shell_print(sh, "Conn: %p", conn);
1667 shell_print(sh, " Sinks:");
1668
1669 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
1670 for (size_t i = 0U; i < ARRAY_SIZE(snks[conn_index]); i++) {
1671 const struct bt_bap_ep *ep = snks[conn_index][i];
1672
1673 if (ep != NULL) {
1674 struct bt_bap_ep_info ep_info;
1675 int err;
1676
1677 err = bt_bap_ep_get_info(ep, &ep_info);
1678 if (err == 0) {
1679 shell_print(sh, " #%u: ep %p (state: %d)", i, ep, ep_info.state);
1680 }
1681 }
1682 }
1683 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
1684
1685 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
1686 shell_print(sh, " Sources:");
1687
1688 for (size_t i = 0U; i < ARRAY_SIZE(srcs[conn_index]); i++) {
1689 const struct bt_bap_ep *ep = srcs[conn_index][i];
1690
1691 if (ep != NULL) {
1692 struct bt_bap_ep_info ep_info;
1693 int err;
1694
1695 err = bt_bap_ep_get_info(ep, &ep_info);
1696 if (err == 0) {
1697 shell_print(sh, " #%u: ep %p (state: %d)", i, ep, ep_info.state);
1698 }
1699 }
1700 }
1701 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
1702 }
1703 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1704
1705 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
cmd_list(const struct shell * sh,size_t argc,char * argv[])1706 static int cmd_list(const struct shell *sh, size_t argc, char *argv[])
1707 {
1708 shell_print(sh, "Configured Channels:");
1709
1710 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
1711 struct bt_bap_stream *stream = &unicast_streams[i].stream.bap_stream;
1712
1713 if (stream != NULL && stream->conn != NULL) {
1714 shell_print(sh, " %s#%u: stream %p dir 0x%02x group %p",
1715 stream == default_stream ? "*" : " ", i, stream,
1716 stream_dir(stream), stream->group);
1717 }
1718 }
1719
1720 bt_conn_foreach(BT_CONN_TYPE_LE, conn_list_eps, (void *)sh);
1721
1722 return 0;
1723 }
1724 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1725
cmd_release(const struct shell * sh,size_t argc,char * argv[])1726 static int cmd_release(const struct shell *sh, size_t argc, char *argv[])
1727 {
1728 int err;
1729
1730 if (default_stream == NULL) {
1731 shell_print(sh, "No stream selected");
1732 return -ENOEXEC;
1733 }
1734
1735 err = bt_bap_stream_release(default_stream);
1736 if (err) {
1737 shell_error(sh, "Unable to release Channel");
1738 return -ENOEXEC;
1739 }
1740
1741 return 0;
1742 }
1743 #endif /* CONFIG_BT_BAP_UNICAST */
1744
1745 #if IS_BAP_INITIATOR
parse_config_data_args(const struct shell * sh,size_t argn,size_t argc,char * argv[],struct bt_audio_codec_cfg * codec_cfg)1746 static ssize_t parse_config_data_args(const struct shell *sh, size_t argn, size_t argc,
1747 char *argv[], struct bt_audio_codec_cfg *codec_cfg)
1748 {
1749 for (; argn < argc; argn++) {
1750 const char *arg = argv[argn];
1751 unsigned long val;
1752 int err = 0;
1753
1754 if (strcmp(arg, "freq") == 0) {
1755 if (++argn == argc) {
1756 shell_help(sh);
1757
1758 return -1;
1759 }
1760
1761 arg = argv[argn];
1762
1763 val = shell_strtoul(arg, 0, &err);
1764 if (err != 0) {
1765 shell_error(sh, "Failed to parse freq from %s: %d", arg, err);
1766
1767 return -1;
1768 }
1769
1770 if (val > UINT8_MAX) {
1771 shell_error(sh, "Invalid freq value: %lu", val);
1772
1773 return -1;
1774 }
1775
1776 err = bt_audio_codec_cfg_set_freq(codec_cfg,
1777 (enum bt_audio_codec_cfg_freq)val);
1778 if (err < 0) {
1779 shell_error(sh, "Failed to set freq with value %lu: %d", val, err);
1780
1781 return -1;
1782 }
1783 } else if (strcmp(arg, "dur") == 0) {
1784 if (++argn == argc) {
1785 shell_help(sh);
1786
1787 return -1;
1788 }
1789
1790 arg = argv[argn];
1791
1792 val = shell_strtoul(arg, 0, &err);
1793 if (err != 0) {
1794 shell_error(sh, "Failed to parse dur from %s: %d", arg, err);
1795
1796 return -1;
1797 }
1798
1799 if (val > UINT8_MAX) {
1800 shell_error(sh, "Invalid dur value: %lu", val);
1801
1802 return -1;
1803 }
1804
1805 err = bt_audio_codec_cfg_set_frame_dur(
1806 codec_cfg, (enum bt_audio_codec_cfg_frame_dur)val);
1807 if (err < 0) {
1808 shell_error(sh, "Failed to set dur with value %lu: %d", val, err);
1809
1810 return -1;
1811 }
1812 } else if (strcmp(arg, "chan_alloc") == 0) {
1813 if (++argn == argc) {
1814 shell_help(sh);
1815
1816 return -1;
1817 }
1818
1819 arg = argv[argn];
1820
1821 val = shell_strtoul(arg, 0, &err);
1822 if (err != 0) {
1823 shell_error(sh, "Failed to parse chan alloc from %s: %d", arg, err);
1824
1825 return -1;
1826 }
1827
1828 if (val > UINT32_MAX) {
1829 shell_error(sh, "Invalid chan alloc value: %lu", val);
1830
1831 return -1;
1832 }
1833
1834 err = bt_audio_codec_cfg_set_chan_allocation(codec_cfg,
1835 (enum bt_audio_location)val);
1836 if (err < 0) {
1837 shell_error(sh, "Failed to set chan alloc with value %lu: %d", val,
1838 err);
1839
1840 return -1;
1841 }
1842 } else if (strcmp(arg, "frame_len") == 0) {
1843 if (++argn == argc) {
1844 shell_help(sh);
1845
1846 return -1;
1847 }
1848
1849 arg = argv[argn];
1850
1851 val = shell_strtoul(arg, 0, &err);
1852 if (err != 0) {
1853 shell_error(sh, "Failed to frame len from %s: %d", arg, err);
1854
1855 return -1;
1856 }
1857
1858 if (val > UINT16_MAX) {
1859 shell_error(sh, "Invalid frame len value: %lu", val);
1860
1861 return -1;
1862 }
1863
1864 err = bt_audio_codec_cfg_set_octets_per_frame(codec_cfg, (uint16_t)val);
1865 if (err < 0) {
1866 shell_error(sh, "Failed to set frame len with value %lu: %d", val,
1867 err);
1868
1869 return -1;
1870 }
1871 } else if (strcmp(arg, "frame_blks") == 0) {
1872 if (++argn == argc) {
1873 shell_help(sh);
1874
1875 return -1;
1876 }
1877
1878 arg = argv[argn];
1879
1880 val = shell_strtoul(arg, 0, &err);
1881 if (err != 0) {
1882 shell_error(sh, "Failed to parse frame blks from %s: %d", arg, err);
1883
1884 return -1;
1885 }
1886
1887 if (val > UINT8_MAX) {
1888 shell_error(sh, "Invalid frame blks value: %lu", val);
1889
1890 return -1;
1891 }
1892
1893 err = bt_audio_codec_cfg_set_frame_blocks_per_sdu(codec_cfg, (uint8_t)val);
1894 if (err < 0) {
1895 shell_error(sh, "Failed to set frame blks with value %lu: %d", val,
1896 err);
1897
1898 return -1;
1899 }
1900 } else { /* we are no longer parsing codec config values */
1901 /* Decrement to return taken argument */
1902 argn--;
1903 break;
1904 }
1905 }
1906
1907 return argn;
1908 }
1909
parse_config_meta_args(const struct shell * sh,size_t argn,size_t argc,char * argv[],struct bt_audio_codec_cfg * codec_cfg)1910 static ssize_t parse_config_meta_args(const struct shell *sh, size_t argn, size_t argc,
1911 char *argv[], struct bt_audio_codec_cfg *codec_cfg)
1912 {
1913 for (; argn < argc; argn++) {
1914 const char *arg = argv[argn];
1915 unsigned long val;
1916 int err = 0;
1917
1918 if (strcmp(arg, "pref_ctx") == 0) {
1919 if (++argn == argc) {
1920 shell_help(sh);
1921
1922 return -1;
1923 }
1924
1925 arg = argv[argn];
1926
1927 val = shell_strtoul(arg, 0, &err);
1928 if (err != 0) {
1929 shell_error(sh, "Failed to parse pref ctx from %s: %d", arg, err);
1930
1931 return -1;
1932 }
1933
1934 if (val > UINT16_MAX) {
1935 shell_error(sh, "Invalid pref ctx value: %lu", val);
1936
1937 return -1;
1938 }
1939
1940 err = bt_audio_codec_cfg_meta_set_pref_context(codec_cfg,
1941 (enum bt_audio_context)val);
1942 if (err < 0) {
1943 shell_error(sh, "Failed to set pref ctx with value %lu: %d", val,
1944 err);
1945
1946 return -1;
1947 }
1948 } else if (strcmp(arg, "stream_ctx") == 0) {
1949 if (++argn == argc) {
1950 shell_help(sh);
1951
1952 return -1;
1953 }
1954
1955 arg = argv[argn];
1956
1957 val = shell_strtoul(arg, 0, &err);
1958 if (err != 0) {
1959 shell_error(sh, "Failed to parse stream ctx from %s: %d", arg, err);
1960
1961 return -1;
1962 }
1963
1964 if (val > UINT16_MAX) {
1965 shell_error(sh, "Invalid stream ctx value: %lu", val);
1966
1967 return -1;
1968 }
1969
1970 err = bt_audio_codec_cfg_meta_set_stream_context(
1971 codec_cfg, (enum bt_audio_context)val);
1972 if (err < 0) {
1973 shell_error(sh, "Failed to set stream ctx with value %lu: %d", val,
1974 err);
1975
1976 return -1;
1977 }
1978 } else if (strcmp(arg, "program_info") == 0) {
1979 if (++argn == argc) {
1980 shell_help(sh);
1981
1982 return -1;
1983 }
1984
1985 arg = argv[argn];
1986
1987 err = bt_audio_codec_cfg_meta_set_program_info(codec_cfg, arg, strlen(arg));
1988 if (err != 0) {
1989 shell_error(sh, "Failed to set program info with value %s: %d", arg,
1990 err);
1991
1992 return -1;
1993 }
1994 } else if (strcmp(arg, "lang") == 0) {
1995 if (++argn == argc) {
1996 shell_help(sh);
1997
1998 return -1;
1999 }
2000
2001 arg = argv[argn];
2002
2003 if (strlen(arg) != BT_AUDIO_LANG_SIZE) {
2004 shell_error(sh, "Failed to parse lang from %s", arg);
2005
2006 return -1;
2007 }
2008
2009 err = bt_audio_codec_cfg_meta_set_lang(codec_cfg, arg);
2010 if (err < 0) {
2011 shell_error(sh, "Failed to set lang with value %s: %d", arg, err);
2012
2013 return -1;
2014 }
2015 } else if (strcmp(arg, "ccid_list") == 0) {
2016 uint8_t ccid_list[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2017 size_t ccid_list_len;
2018
2019 if (++argn == argc) {
2020 shell_help(sh);
2021
2022 return -1;
2023 }
2024
2025 arg = argv[argn];
2026
2027 ccid_list_len = hex2bin(arg, strlen(arg), ccid_list, sizeof(ccid_list));
2028 if (ccid_list_len == 0) {
2029 shell_error(sh, "Failed to parse ccid list from %s", arg);
2030
2031 return -1;
2032 }
2033
2034 err = bt_audio_codec_cfg_meta_set_ccid_list(codec_cfg, ccid_list,
2035 ccid_list_len);
2036 if (err < 0) {
2037 shell_error(sh, "Failed to set ccid list with value %s: %d", arg,
2038 err);
2039
2040 return -1;
2041 }
2042 } else if (strcmp(arg, "parental_rating") == 0) {
2043 if (++argn == argc) {
2044 shell_help(sh);
2045
2046 return -1;
2047 }
2048
2049 arg = argv[argn];
2050
2051 val = shell_strtoul(arg, 0, &err);
2052 if (err != 0) {
2053 shell_error(sh, "Failed to parse parental rating from %s: %d", arg,
2054 err);
2055
2056 return -1;
2057 }
2058
2059 if (val > UINT8_MAX) {
2060 shell_error(sh, "Invalid parental rating value: %lu", val);
2061
2062 return -1;
2063 }
2064
2065 err = bt_audio_codec_cfg_meta_set_parental_rating(
2066 codec_cfg, (enum bt_audio_parental_rating)val);
2067 if (err < 0) {
2068 shell_error(sh, "Failed to set parental rating with value %lu: %d",
2069 val, err);
2070
2071 return -1;
2072 }
2073 } else if (strcmp(arg, "program_info_uri") == 0) {
2074 if (++argn == argc) {
2075 shell_help(sh);
2076
2077 return -1;
2078 }
2079
2080 arg = argv[argn];
2081
2082 err = bt_audio_codec_cfg_meta_set_program_info_uri(codec_cfg, arg,
2083 strlen(arg));
2084 if (err < 0) {
2085 shell_error(sh, "Failed to set program info URI with value %s: %d",
2086 arg, err);
2087
2088 return -1;
2089 }
2090 } else if (strcmp(arg, "audio_active_state") == 0) {
2091 if (++argn == argc) {
2092 shell_help(sh);
2093
2094 return -1;
2095 }
2096
2097 arg = argv[argn];
2098
2099 val = shell_strtoul(arg, 0, &err);
2100 if (err != 0) {
2101 shell_error(sh, "Failed to parse audio active state from %s: %d",
2102 arg, err);
2103
2104 return -1;
2105 }
2106
2107 if (val > UINT8_MAX) {
2108 shell_error(sh, "Invalid audio active state value: %lu", val);
2109
2110 return -1;
2111 }
2112
2113 err = bt_audio_codec_cfg_meta_set_audio_active_state(
2114 codec_cfg, (enum bt_audio_active_state)val);
2115 if (err < 0) {
2116 shell_error(sh,
2117 "Failed to set audio active state with value %lu: %d",
2118 val, err);
2119
2120 return -1;
2121 }
2122 } else if (strcmp(arg, "bcast_flag") == 0) {
2123 err = bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(
2124 codec_cfg);
2125 if (err < 0) {
2126 shell_error(sh, "Failed to set audio active state: %d", err);
2127
2128 return -1;
2129 }
2130 } else if (strcmp(arg, "extended") == 0) {
2131 uint8_t extended[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2132 size_t extended_len;
2133
2134 if (++argn == argc) {
2135 shell_help(sh);
2136
2137 return -1;
2138 }
2139
2140 arg = argv[argn];
2141
2142 extended_len = hex2bin(arg, strlen(arg), extended, sizeof(extended));
2143 if (extended_len == 0) {
2144 shell_error(sh, "Failed to parse extended meta from %s", arg);
2145
2146 return -1;
2147 }
2148
2149 err = bt_audio_codec_cfg_meta_set_extended(codec_cfg, extended,
2150 extended_len);
2151 if (err < 0) {
2152 shell_error(sh, "Failed to set extended meta with value %s: %d",
2153 arg, err);
2154
2155 return -1;
2156 }
2157 } else if (strcmp(arg, "vendor") == 0) {
2158 uint8_t vendor[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2159 size_t vendor_len;
2160
2161 if (++argn == argc) {
2162 shell_help(sh);
2163
2164 return -1;
2165 }
2166
2167 arg = argv[argn];
2168
2169 vendor_len = hex2bin(arg, strlen(arg), vendor, sizeof(vendor));
2170 if (vendor_len == 0) {
2171 shell_error(sh, "Failed to parse vendor meta from %s", arg);
2172
2173 return -1;
2174 }
2175
2176 err = bt_audio_codec_cfg_meta_set_vendor(codec_cfg, vendor, vendor_len);
2177 if (err < 0) {
2178 shell_error(sh, "Failed to set vendor meta with value %s: %d", arg,
2179 err);
2180
2181 return -1;
2182 }
2183 } else { /* we are no longer parsing codec config meta values */
2184 /* Decrement to return taken argument */
2185 argn--;
2186 break;
2187 }
2188 }
2189
2190 return argn;
2191 }
2192
cmd_preset(const struct shell * sh,size_t argc,char * argv[])2193 static int cmd_preset(const struct shell *sh, size_t argc, char *argv[])
2194 {
2195 const struct named_lc3_preset *named_preset;
2196 enum bt_audio_dir dir;
2197 bool unicast = true;
2198
2199 if (!strcmp(argv[1], "sink")) {
2200 dir = BT_AUDIO_DIR_SINK;
2201 named_preset = &default_sink_preset;
2202 } else if (!strcmp(argv[1], "source")) {
2203 dir = BT_AUDIO_DIR_SOURCE;
2204 named_preset = &default_source_preset;
2205 } else if (!strcmp(argv[1], "broadcast")) {
2206 unicast = false;
2207 dir = BT_AUDIO_DIR_SOURCE;
2208
2209 named_preset = &default_broadcast_source_preset;
2210 } else {
2211 shell_error(sh, "Unsupported dir: %s", argv[1]);
2212 return -ENOEXEC;
2213 }
2214
2215 if (argc > 2) {
2216 struct bt_audio_codec_cfg *codec_cfg;
2217
2218 named_preset = bap_get_named_preset(unicast, dir, argv[2]);
2219 if (named_preset == NULL) {
2220 shell_error(sh, "Unable to parse named_preset %s", argv[2]);
2221 return -ENOEXEC;
2222 }
2223
2224 if (!strcmp(argv[1], "sink")) {
2225 named_preset = memcpy(&default_sink_preset, named_preset,
2226 sizeof(default_sink_preset));
2227 codec_cfg = &default_sink_preset.preset.codec_cfg;
2228 } else if (!strcmp(argv[1], "source")) {
2229 named_preset = memcpy(&default_source_preset, named_preset,
2230 sizeof(default_sink_preset));
2231 codec_cfg = &default_source_preset.preset.codec_cfg;
2232 } else if (!strcmp(argv[1], "broadcast")) {
2233 named_preset = memcpy(&default_broadcast_source_preset, named_preset,
2234 sizeof(default_sink_preset));
2235 codec_cfg = &default_broadcast_source_preset.preset.codec_cfg;
2236 } else {
2237 shell_error(sh, "Invalid dir: %s", argv[1]);
2238
2239 return -ENOEXEC;
2240 }
2241
2242 if (argc > 3) {
2243 struct bt_audio_codec_cfg codec_cfg_backup;
2244
2245 memcpy(&codec_cfg_backup, codec_cfg, sizeof(codec_cfg_backup));
2246
2247 for (size_t argn = 3; argn < argc; argn++) {
2248 const char *arg = argv[argn];
2249
2250 if (strcmp(arg, "config") == 0) {
2251 ssize_t ret;
2252
2253 if (++argn == argc) {
2254 shell_help(sh);
2255
2256 memcpy(codec_cfg, &codec_cfg_backup,
2257 sizeof(codec_cfg_backup));
2258
2259 return SHELL_CMD_HELP_PRINTED;
2260 }
2261
2262 ret = parse_config_data_args(sh, argn, argc, argv,
2263 codec_cfg);
2264 if (ret < 0) {
2265 memcpy(codec_cfg, &codec_cfg_backup,
2266 sizeof(codec_cfg_backup));
2267
2268 return -ENOEXEC;
2269 }
2270
2271 argn = ret;
2272 } else if (strcmp(arg, "meta") == 0) {
2273 ssize_t ret;
2274
2275 if (++argn == argc) {
2276 shell_help(sh);
2277
2278 memcpy(codec_cfg, &codec_cfg_backup,
2279 sizeof(codec_cfg_backup));
2280
2281 return SHELL_CMD_HELP_PRINTED;
2282 }
2283
2284 ret = parse_config_meta_args(sh, argn, argc, argv,
2285 codec_cfg);
2286 if (ret < 0) {
2287 memcpy(codec_cfg, &codec_cfg_backup,
2288 sizeof(codec_cfg_backup));
2289
2290 return -ENOEXEC;
2291 }
2292
2293 argn = ret;
2294 } else {
2295 shell_error(sh, "Invalid argument: %s", arg);
2296 shell_help(sh);
2297
2298 return -ENOEXEC;
2299 }
2300 }
2301 }
2302 }
2303
2304 shell_print(sh, "%s", named_preset->name);
2305
2306 print_codec_cfg(ctx_shell, 0, &named_preset->preset.codec_cfg);
2307 print_qos(ctx_shell, &named_preset->preset.qos);
2308
2309 return 0;
2310 }
2311 #endif /* IS_BAP_INITIATOR */
2312
2313 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
2314 #define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1)
2315 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
2316 #define PA_SYNC_SKIP 5
2317
2318 static struct broadcast_sink_auto_scan {
2319 struct broadcast_sink *broadcast_sink;
2320 uint32_t broadcast_id;
2321 struct bt_le_per_adv_sync **out_sync;
2322 } auto_scan = {
2323 .broadcast_id = INVALID_BROADCAST_ID,
2324 };
2325
clear_auto_scan(void)2326 static void clear_auto_scan(void)
2327 {
2328 if (auto_scan.broadcast_id != INVALID_BROADCAST_ID) {
2329 memset(&auto_scan, 0, sizeof(auto_scan));
2330 auto_scan.broadcast_id = INVALID_BROADCAST_ID;
2331 }
2332 }
2333
interval_to_sync_timeout(uint16_t interval)2334 static uint16_t interval_to_sync_timeout(uint16_t interval)
2335 {
2336 uint32_t interval_ms;
2337 uint32_t timeout;
2338
2339 /* Add retries and convert to unit in 10's of ms */
2340 interval_ms = BT_GAP_PER_ADV_INTERVAL_TO_MS(interval);
2341 timeout = (interval_ms * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO) / 10;
2342
2343 /* Enforce restraints */
2344 timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
2345
2346 return (uint16_t)timeout;
2347 }
2348
scan_check_and_sync_broadcast(struct bt_data * data,void * user_data)2349 static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data)
2350 {
2351 const struct bt_le_scan_recv_info *info = user_data;
2352 char le_addr[BT_ADDR_LE_STR_LEN];
2353 struct bt_uuid_16 adv_uuid;
2354 uint32_t broadcast_id;
2355
2356 if (data->type != BT_DATA_SVC_DATA16) {
2357 return true;
2358 }
2359
2360 if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) {
2361 return true;
2362 }
2363
2364 if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) {
2365 return true;
2366 }
2367
2368 if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO)) {
2369 return true;
2370 }
2371
2372 broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16);
2373
2374 bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
2375
2376 shell_print(ctx_shell,
2377 "Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X (looking for "
2378 "0x%06X)",
2379 broadcast_id, le_addr, info->sid, auto_scan.broadcast_id);
2380
2381 if (auto_scan.broadcast_id == broadcast_id && auto_scan.broadcast_sink != NULL &&
2382 auto_scan.broadcast_sink->pa_sync == NULL) {
2383 struct bt_le_per_adv_sync_param create_params = {0};
2384 int err;
2385
2386 err = bt_le_scan_stop();
2387 if (err != 0) {
2388 shell_error(ctx_shell, "Could not stop scan: %d", err);
2389 }
2390
2391 bt_addr_le_copy(&create_params.addr, info->addr);
2392 create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
2393 create_params.sid = info->sid;
2394 create_params.skip = PA_SYNC_SKIP;
2395 create_params.timeout = interval_to_sync_timeout(info->interval);
2396
2397 shell_print(ctx_shell, "Attempting to PA sync to the broadcaster");
2398 err = bt_le_per_adv_sync_create(&create_params, auto_scan.out_sync);
2399 if (err != 0) {
2400 shell_error(ctx_shell, "Could not create Broadcast PA sync: %d", err);
2401 } else {
2402 auto_scan.broadcast_sink->pa_sync = *auto_scan.out_sync;
2403 }
2404 }
2405
2406 /* Stop parsing */
2407 return false;
2408 }
2409
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)2410 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
2411 {
2412 if (passes_scan_filter(info, ad)) {
2413 bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)info);
2414 }
2415 }
2416
base_recv(struct bt_bap_broadcast_sink * sink,const struct bt_bap_base * base,size_t base_size)2417 static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base,
2418 size_t base_size)
2419 {
2420 /* Don't print duplicates */
2421 if (base_size != default_broadcast_sink.base_size ||
2422 memcmp(base, &default_broadcast_sink.received_base, base_size) != 0) {
2423 shell_print(ctx_shell, "Received BASE from sink %p:", sink);
2424 (void)memcpy(&default_broadcast_sink.received_base, base, base_size);
2425 default_broadcast_sink.base_size = base_size;
2426
2427 print_base(base);
2428 }
2429 }
2430
syncable(struct bt_bap_broadcast_sink * sink,const struct bt_iso_biginfo * biginfo)2431 static void syncable(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo)
2432 {
2433 if (default_broadcast_sink.bap_sink == sink) {
2434 if (default_broadcast_sink.syncable) {
2435 return;
2436 }
2437
2438 shell_print(ctx_shell, "Sink %p is ready to sync %s encryption", sink,
2439 biginfo->encryption ? "with" : "without");
2440 default_broadcast_sink.syncable = true;
2441 }
2442 }
2443
bap_pa_sync_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)2444 static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
2445 struct bt_le_per_adv_sync_synced_info *info)
2446 {
2447 if (auto_scan.broadcast_sink != NULL && auto_scan.out_sync != NULL &&
2448 sync == *auto_scan.out_sync) {
2449 shell_print(ctx_shell, "PA synced to broadcast with broadcast ID 0x%06x",
2450 auto_scan.broadcast_id);
2451
2452 if (auto_scan.broadcast_sink->bap_sink == NULL) {
2453 shell_print(ctx_shell, "Attempting to create the sink");
2454 int err;
2455
2456 err = bt_bap_broadcast_sink_create(sync, auto_scan.broadcast_id,
2457 &auto_scan.broadcast_sink->bap_sink);
2458 if (err != 0) {
2459 shell_error(ctx_shell, "Could not create broadcast sink: %d", err);
2460 }
2461 } else {
2462 shell_print(ctx_shell, "Sink is already created");
2463 }
2464 }
2465
2466 clear_auto_scan();
2467 }
2468
bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)2469 static void bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync,
2470 const struct bt_le_per_adv_sync_term_info *info)
2471 {
2472 if (default_broadcast_sink.pa_sync == sync) {
2473 default_broadcast_sink.syncable = false;
2474 (void)memset(&default_broadcast_sink.received_base, 0,
2475 sizeof(default_broadcast_sink.received_base));
2476 }
2477
2478 clear_auto_scan();
2479 }
2480
broadcast_scan_timeout_cb(void)2481 static void broadcast_scan_timeout_cb(void)
2482 {
2483 shell_print(ctx_shell, "Scan timeout");
2484
2485 clear_auto_scan();
2486 }
2487
2488 static struct bt_bap_broadcast_sink_cb sink_cbs = {
2489 .base_recv = base_recv,
2490 .syncable = syncable,
2491 };
2492
2493 static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = {
2494 .synced = bap_pa_sync_synced_cb,
2495 .term = bap_pa_sync_terminated_cb,
2496 };
2497
2498 static struct bt_le_scan_cb bap_scan_cb = {
2499 .timeout = broadcast_scan_timeout_cb,
2500 .recv = broadcast_scan_recv,
2501 };
2502 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
2503
2504 #if defined(CONFIG_BT_AUDIO_RX)
2505 static size_t rx_streaming_cnt;
2506
bap_get_rx_streaming_cnt(void)2507 size_t bap_get_rx_streaming_cnt(void)
2508 {
2509 return rx_streaming_cnt;
2510 }
2511
2512 #if defined(CONFIG_LIBLC3)
2513 struct lc3_data {
2514 void *fifo_reserved; /* 1st word reserved for use by FIFO */
2515 struct net_buf *buf;
2516 struct shell_stream *sh_stream;
2517 uint32_t ts;
2518 bool do_plc;
2519 };
2520
2521 K_MEM_SLAB_DEFINE(lc3_data_slab, sizeof(struct lc3_data), CONFIG_BT_ISO_RX_BUF_COUNT,
2522 __alignof__(struct lc3_data));
2523
2524 static int16_t lc3_rx_buf[LC3_MAX_NUM_SAMPLES_MONO];
2525 static K_FIFO_DEFINE(lc3_in_fifo);
2526
2527 /* We only want to send USB to left/right from a single stream. If we have 2 left streams, the
2528 * outgoing audio is going to be terrible.
2529 * Since a stream can contain stereo data, both of these may be the same stream.
2530 */
2531 static struct shell_stream *usb_left_stream;
2532 static struct shell_stream *usb_right_stream;
2533
init_lc3_decoder(struct shell_stream * sh_stream)2534 static int init_lc3_decoder(struct shell_stream *sh_stream)
2535 {
2536 if (sh_stream == NULL) {
2537 shell_error(ctx_shell, "NULL stream to init LC3 decoder");
2538 return -EINVAL;
2539 }
2540
2541 if (!sh_stream->is_rx) {
2542 shell_error(ctx_shell, "Invalid stream to init LC3 decoder");
2543 return -EINVAL;
2544 }
2545
2546 if (sh_stream->rx.lc3_decoder != NULL) {
2547 shell_error(ctx_shell, "Already initialized");
2548 return -EALREADY;
2549 }
2550
2551 if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) {
2552 shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)",
2553 sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us);
2554
2555 return -EINVAL;
2556 }
2557
2558 shell_print(ctx_shell,
2559 "Initializing the LC3 decoder with %u us duration and %u Hz frequency",
2560 sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz);
2561 /* Create the decoder instance. This shall complete before stream_started() is called. */
2562 sh_stream->rx.lc3_decoder =
2563 lc3_setup_decoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz,
2564 IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE : 0,
2565 &sh_stream->rx.lc3_decoder_mem);
2566 if (sh_stream->rx.lc3_decoder == NULL) {
2567 shell_error(ctx_shell, "Failed to setup LC3 decoder - wrong parameters?\n");
2568 return -EINVAL;
2569 }
2570
2571 return 0;
2572 }
2573
decode_frame(struct lc3_data * data,size_t frame_cnt)2574 static bool decode_frame(struct lc3_data *data, size_t frame_cnt)
2575 {
2576 const struct shell_stream *sh_stream = data->sh_stream;
2577 const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu;
2578 const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame;
2579 struct net_buf *buf = data->buf;
2580 void *iso_data;
2581 int err;
2582
2583 if (data->do_plc) {
2584 iso_data = NULL; /* perform PLC */
2585
2586 if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) {
2587 shell_print(ctx_shell, "[%zu]: Performing PLC", sh_stream->rx.decoded_cnt);
2588 }
2589
2590 data->do_plc = false; /* clear flag */
2591 } else {
2592 iso_data = net_buf_pull_mem(data->buf, octets_per_frame);
2593
2594 if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) {
2595 shell_print(ctx_shell, "[%zu]: Decoding frame of size %u (%u/%u)",
2596 sh_stream->rx.decoded_cnt, octets_per_frame, frame_cnt + 1,
2597 total_frames);
2598 }
2599 }
2600
2601 err = lc3_decode(sh_stream->rx.lc3_decoder, iso_data, octets_per_frame, LC3_PCM_FORMAT_S16,
2602 lc3_rx_buf, 1);
2603 if (err < 0) {
2604 shell_error(ctx_shell, "Failed to decode LC3 data (%u/%u - %u/%u)", frame_cnt + 1,
2605 total_frames, octets_per_frame * frame_cnt, buf->len);
2606 return false;
2607 }
2608
2609 return true;
2610 }
2611
decode_frame_block(struct lc3_data * data,size_t frame_cnt)2612 static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt)
2613 {
2614 const struct shell_stream *sh_stream = data->sh_stream;
2615 const uint8_t chan_cnt = sh_stream->lc3_chan_cnt;
2616 size_t decoded_frames = 0U;
2617
2618 for (uint8_t i = 0U; i < chan_cnt; i++) {
2619 /* We provide the total number of decoded frames to `decode_frame` for logging
2620 * purposes
2621 */
2622 if (decode_frame(data, frame_cnt + decoded_frames)) {
2623 decoded_frames++;
2624
2625 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2626 enum bt_audio_location chan_alloc;
2627 int err;
2628
2629 err = get_lc3_chan_alloc_from_index(sh_stream, i, &chan_alloc);
2630 if (err != 0) {
2631 /* Not suitable for USB */
2632 continue;
2633 }
2634
2635 /* We only want to left or right from one stream to USB */
2636 if ((chan_alloc == BT_AUDIO_LOCATION_FRONT_LEFT &&
2637 sh_stream != usb_left_stream) ||
2638 (chan_alloc == BT_AUDIO_LOCATION_FRONT_RIGHT &&
2639 sh_stream != usb_right_stream)) {
2640 continue;
2641 }
2642
2643 err = bap_usb_add_frame_to_usb(chan_alloc, lc3_rx_buf,
2644 sizeof(lc3_rx_buf), data->ts);
2645 if (err == -EINVAL) {
2646 continue;
2647 }
2648 }
2649 } else {
2650 /* If decoding failed, we clear the data to USB as it would contain
2651 * invalid data
2652 */
2653 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2654 bap_usb_clear_frames_to_usb();
2655 }
2656
2657 break;
2658 }
2659 }
2660
2661 return decoded_frames;
2662 }
2663
do_lc3_decode(struct lc3_data * data)2664 static void do_lc3_decode(struct lc3_data *data)
2665 {
2666 struct shell_stream *sh_stream = data->sh_stream;
2667
2668 if (sh_stream->is_rx && sh_stream->rx.lc3_decoder != NULL) {
2669 const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu;
2670 size_t frame_cnt;
2671
2672 frame_cnt = 0;
2673 for (uint8_t i = 0U; i < frame_blocks_per_sdu; i++) {
2674 const size_t decoded_frames = decode_frame_block(data, frame_cnt);
2675
2676 if (decoded_frames == 0) {
2677 break;
2678 }
2679
2680 frame_cnt += decoded_frames;
2681 }
2682
2683 sh_stream->rx.decoded_cnt++;
2684 }
2685
2686 net_buf_unref(data->buf);
2687 }
2688
lc3_decoder_thread_func(void * arg1,void * arg2,void * arg3)2689 static void lc3_decoder_thread_func(void *arg1, void *arg2, void *arg3)
2690 {
2691 while (true) {
2692 struct lc3_data *data = k_fifo_get(&lc3_in_fifo, K_FOREVER);
2693 struct shell_stream *sh_stream = data->sh_stream;
2694
2695 if (sh_stream->is_rx && sh_stream->rx.lc3_decoder == NULL) {
2696 shell_warn(ctx_shell, "Decoder is NULL, discarding data from FIFO");
2697 k_mem_slab_free(&lc3_data_slab, (void *)data);
2698 continue; /* Wait for new data */
2699 }
2700
2701 do_lc3_decode(data);
2702
2703 k_mem_slab_free(&lc3_data_slab, (void *)data);
2704 }
2705 }
2706
2707 #endif /* CONFIG_LIBLC3*/
2708
audio_recv(struct bt_bap_stream * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)2709 static void audio_recv(struct bt_bap_stream *stream,
2710 const struct bt_iso_recv_info *info,
2711 struct net_buf *buf)
2712 {
2713 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
2714
2715 if (!sh_stream->is_rx) {
2716 return;
2717 }
2718
2719 sh_stream->rx.rx_cnt++;
2720
2721 if (info->ts == sh_stream->rx.last_info.ts) {
2722 sh_stream->rx.dup_ts++;
2723 }
2724
2725 if (info->seq_num == sh_stream->rx.last_info.seq_num) {
2726 sh_stream->rx.dup_psn++;
2727 }
2728
2729 if ((info->flags & BT_ISO_FLAGS_VALID) != 0) {
2730 if (buf->len == 0U) {
2731 sh_stream->rx.empty_sdu_pkts++;
2732 } else {
2733 sh_stream->rx.valid_sdu_pkts++;
2734 }
2735 }
2736
2737 if (info->flags & BT_ISO_FLAGS_ERROR) {
2738 sh_stream->rx.err_pkts++;
2739 }
2740
2741 if (info->flags & BT_ISO_FLAGS_LOST) {
2742 sh_stream->rx.lost_pkts++;
2743 }
2744
2745 if ((sh_stream->rx.rx_cnt % bap_stats_interval) == 0) {
2746 shell_print(ctx_shell,
2747 "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u "
2748 "(valid %zu, dup ts %zu, dup psn %zu, err_pkts %zu, lost_pkts %zu, "
2749 "empty SDUs %zu)",
2750 sh_stream->rx.rx_cnt, stream, buf->len, info->ts, info->seq_num,
2751 info->flags, sh_stream->rx.valid_sdu_pkts, sh_stream->rx.dup_ts,
2752 sh_stream->rx.dup_psn, sh_stream->rx.err_pkts, sh_stream->rx.lost_pkts,
2753 sh_stream->rx.empty_sdu_pkts);
2754 }
2755
2756 (void)memcpy(&sh_stream->rx.last_info, info, sizeof(sh_stream->rx.last_info));
2757
2758 #if defined(CONFIG_LIBLC3)
2759 if (sh_stream->rx.lc3_decoder != NULL) {
2760 const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu;
2761 const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame;
2762 const uint8_t chan_cnt = sh_stream->lc3_chan_cnt;
2763 struct lc3_data *data;
2764
2765 /* Allocate a context that holds both the buffer and the stream so that we can
2766 * send both of these values to the LC3 decoder thread as a single struct
2767 * in a FIFO
2768 */
2769 if (k_mem_slab_alloc(&lc3_data_slab, (void **)&data, K_NO_WAIT)) {
2770 shell_warn(ctx_shell, "Could not allocate LC3 data item");
2771
2772 return;
2773 }
2774
2775 if ((info->flags & BT_ISO_FLAGS_VALID) == 0) {
2776 data->do_plc = true;
2777 } else if (buf->len != (octets_per_frame * chan_cnt * frame_blocks_per_sdu)) {
2778 if (buf->len != 0U) {
2779 shell_error(
2780 ctx_shell,
2781 "Expected %u frame blocks with %u channels of size %u, but "
2782 "length is %u",
2783 frame_blocks_per_sdu, chan_cnt, octets_per_frame, buf->len);
2784 }
2785
2786 data->do_plc = true;
2787 }
2788
2789 data->buf = net_buf_ref(buf);
2790 data->sh_stream = sh_stream;
2791 if (info->flags & BT_ISO_FLAGS_TS) {
2792 data->ts = info->ts;
2793 } else {
2794 data->ts = 0U;
2795 }
2796
2797 k_fifo_put(&lc3_in_fifo, data);
2798 }
2799 #endif /* CONFIG_LIBLC3 */
2800 }
2801 #endif /* CONFIG_BT_AUDIO_RX */
2802
2803 #if defined(CONFIG_BT_BAP_UNICAST)
stream_enabled_cb(struct bt_bap_stream * stream)2804 static void stream_enabled_cb(struct bt_bap_stream *stream)
2805 {
2806 shell_print(ctx_shell, "Stream %p enabled", stream);
2807
2808 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
2809 struct bt_bap_ep_info ep_info;
2810 struct bt_conn_info conn_info;
2811 int err;
2812
2813 err = bt_conn_get_info(stream->conn, &conn_info);
2814 if (err != 0) {
2815 shell_error(ctx_shell, "Failed to get conn info: %d", err);
2816 return;
2817 }
2818
2819 if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
2820 return; /* We also want to autonomously start the stream as the server */
2821 }
2822
2823 err = bt_bap_ep_get_info(stream->ep, &ep_info);
2824 if (err != 0) {
2825 shell_error(ctx_shell, "Failed to get ep info: %d", err);
2826 return;
2827 }
2828
2829 if (ep_info.dir == BT_AUDIO_DIR_SINK) {
2830 /* Automatically do the receiver start ready operation */
2831 err = bt_bap_stream_start(stream);
2832
2833 if (err != 0) {
2834 shell_error(ctx_shell, "Failed to start stream: %d", err);
2835 return;
2836 }
2837 }
2838 }
2839 }
2840 #endif /* CONFIG_BT_BAP_UNICAST */
2841
stream_started_cb(struct bt_bap_stream * bap_stream)2842 static void stream_started_cb(struct bt_bap_stream *bap_stream)
2843 {
2844 struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
2845 struct bt_bap_ep_info info = {0};
2846 int ret;
2847
2848 printk("Stream %p started\n", bap_stream);
2849
2850 ret = bt_bap_ep_get_info(bap_stream->ep, &info);
2851 if (ret != 0) {
2852 shell_error(ctx_shell, "Failed to get EP info: %d", ret);
2853 return;
2854 }
2855
2856 sh_stream->is_rx = info.can_recv;
2857 sh_stream->is_tx = info.can_send;
2858
2859 #if defined(CONFIG_LIBLC3)
2860 const struct bt_audio_codec_cfg *codec_cfg = bap_stream->codec_cfg;
2861
2862 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
2863 if (sh_stream->is_tx) {
2864 atomic_set(&sh_stream->tx.lc3_enqueue_cnt, PRIME_COUNT);
2865 sh_stream->tx.lc3_sdu_cnt = 0U;
2866 }
2867
2868 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
2869 if (ret >= 0) {
2870 ret = bt_audio_codec_cfg_freq_to_freq_hz(ret);
2871
2872 if (ret > 0) {
2873 if (ret == 8000 || ret == 16000 || ret == 24000 || ret == 32000 ||
2874 ret == 48000) {
2875 sh_stream->lc3_freq_hz = (uint32_t)ret;
2876 } else {
2877 shell_error(ctx_shell, "Unsupported frequency for LC3: %d",
2878 ret);
2879 sh_stream->lc3_freq_hz = 0U;
2880 }
2881 } else {
2882 shell_error(ctx_shell, "Invalid frequency: %d", ret);
2883 sh_stream->lc3_freq_hz = 0U;
2884 }
2885 } else {
2886 shell_error(ctx_shell, "Could not get frequency: %d", ret);
2887 sh_stream->lc3_freq_hz = 0U;
2888 }
2889
2890 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
2891 if (ret >= 0) {
2892 ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
2893 if (ret > 0) {
2894 sh_stream->lc3_frame_duration_us = (uint32_t)ret;
2895 } else {
2896 shell_error(ctx_shell, "Invalid frame duration: %d", ret);
2897 sh_stream->lc3_frame_duration_us = 0U;
2898 }
2899 } else {
2900 shell_error(ctx_shell, "Could not get frame duration: %d", ret);
2901 sh_stream->lc3_frame_duration_us = 0U;
2902 }
2903
2904 ret = bt_audio_codec_cfg_get_chan_allocation(
2905 codec_cfg, &sh_stream->lc3_chan_allocation, false);
2906 if (ret == 0) {
2907 sh_stream->lc3_chan_cnt =
2908 bt_audio_get_chan_count(sh_stream->lc3_chan_allocation);
2909 } else {
2910 shell_error(ctx_shell, "Could not get channel allocation: %d", ret);
2911 sh_stream->lc3_chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
2912 sh_stream->lc3_chan_cnt = 1U;
2913 }
2914
2915 ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
2916 if (ret >= 0) {
2917 sh_stream->lc3_frame_blocks_per_sdu = (uint8_t)ret;
2918 } else {
2919 shell_error(ctx_shell, "Could not get frame blocks per SDU: %d", ret);
2920 sh_stream->lc3_frame_blocks_per_sdu = 0U;
2921 }
2922
2923 ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
2924 if (ret >= 0) {
2925 sh_stream->lc3_octets_per_frame = (uint16_t)ret;
2926 } else {
2927 shell_error(ctx_shell, "Could not get octets per frame: %d", ret);
2928 sh_stream->lc3_octets_per_frame = 0U;
2929 }
2930
2931 #if defined(CONFIG_BT_AUDIO_TX)
2932 if (sh_stream->is_tx && sh_stream->tx.lc3_encoder == NULL) {
2933 const int err = init_lc3_encoder(sh_stream);
2934
2935 if (err != 0) {
2936 shell_error(ctx_shell, "Failed to init LC3 encoder: %d", err);
2937
2938 return;
2939 }
2940
2941 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2942 /* Always mark as active when using USB */
2943 sh_stream->tx.active = true;
2944 }
2945 }
2946 #endif /* CONFIG_BT_AUDIO_TX */
2947
2948 #if defined(CONFIG_BT_AUDIO_RX)
2949 if (sh_stream->is_rx) {
2950 if (sh_stream->rx.lc3_decoder == NULL) {
2951 const int err = init_lc3_decoder(sh_stream);
2952
2953 if (err != 0) {
2954 shell_error(ctx_shell, "Failed to init LC3 decoder: %d",
2955 err);
2956
2957 return;
2958 }
2959 }
2960
2961 sh_stream->rx.decoded_cnt = 0U;
2962
2963 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2964 if ((sh_stream->lc3_chan_allocation &
2965 BT_AUDIO_LOCATION_FRONT_LEFT) != 0) {
2966 if (usb_left_stream == NULL) {
2967 shell_info(ctx_shell,
2968 "Setting USB left stream to %p",
2969 sh_stream);
2970 usb_left_stream = sh_stream;
2971 } else {
2972 shell_warn(ctx_shell,
2973 "Multiple left streams started");
2974 }
2975 }
2976
2977 if ((sh_stream->lc3_chan_allocation &
2978 BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) {
2979 if (usb_right_stream == NULL) {
2980 shell_info(ctx_shell,
2981 "Setting USB right stream to %p",
2982 sh_stream);
2983 usb_right_stream = sh_stream;
2984 } else {
2985 shell_warn(ctx_shell,
2986 "Multiple right streams started");
2987 }
2988 }
2989 }
2990 }
2991 #endif /* CONFIG_BT_AUDIO_RX */
2992 }
2993 #endif /* CONFIG_LIBLC3 */
2994
2995 #if defined(CONFIG_BT_AUDIO_TX)
2996 if (sh_stream->is_tx) {
2997 sh_stream->tx.connected_at_ticks = k_uptime_ticks();
2998 }
2999 #endif /* CONFIG_BT_AUDIO_TX */
3000
3001 #if defined(CONFIG_BT_AUDIO_RX)
3002 if (sh_stream->is_rx) {
3003 sh_stream->rx.empty_sdu_pkts = 0U;
3004 sh_stream->rx.valid_sdu_pkts = 0U;
3005 sh_stream->rx.lost_pkts = 0U;
3006 sh_stream->rx.err_pkts = 0U;
3007 sh_stream->rx.dup_psn = 0U;
3008 sh_stream->rx.rx_cnt = 0U;
3009 sh_stream->rx.dup_ts = 0U;
3010
3011 rx_streaming_cnt++;
3012 }
3013 #endif
3014 }
3015
3016 #if defined(CONFIG_LIBLC3)
update_usb_streams_cb(struct shell_stream * sh_stream,void * user_data)3017 static void update_usb_streams_cb(struct shell_stream *sh_stream, void *user_data)
3018 {
3019 if (sh_stream->is_rx) {
3020 if (usb_left_stream == NULL &&
3021 (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) {
3022 shell_info(ctx_shell, "Setting new USB left stream to %p", sh_stream);
3023 usb_left_stream = sh_stream;
3024 }
3025
3026 if (usb_right_stream == NULL &&
3027 (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) {
3028 shell_info(ctx_shell, "Setting new USB right stream to %p", sh_stream);
3029 usb_right_stream = sh_stream;
3030 }
3031 }
3032 }
3033
update_usb_streams(struct shell_stream * sh_stream)3034 static void update_usb_streams(struct shell_stream *sh_stream)
3035 {
3036 if (sh_stream->is_rx) {
3037 if (sh_stream == usb_left_stream) {
3038 shell_info(ctx_shell, "Clearing USB left stream (%p)", usb_left_stream);
3039 usb_left_stream = NULL;
3040 }
3041
3042 if (sh_stream == usb_right_stream) {
3043 shell_info(ctx_shell, "Clearing USB right stream (%p)", usb_right_stream);
3044 usb_right_stream = NULL;
3045 }
3046
3047 bap_foreach_stream(update_usb_streams_cb, NULL);
3048 }
3049 }
3050 #endif /* CONFIG_LIBLC3 */
3051
clear_stream_data(struct shell_stream * sh_stream)3052 static void clear_stream_data(struct shell_stream *sh_stream)
3053 {
3054 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
3055 if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) {
3056 if (default_broadcast_sink.stream_cnt != 0) {
3057 default_broadcast_sink.stream_cnt--;
3058 }
3059
3060 if (default_broadcast_sink.stream_cnt == 0) {
3061 /* All streams in the broadcast sink has been terminated */
3062 memset(&default_broadcast_sink.received_base, 0,
3063 sizeof(default_broadcast_sink.received_base));
3064 default_broadcast_sink.broadcast_id = 0;
3065 default_broadcast_sink.syncable = false;
3066 }
3067 }
3068 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
3069
3070 #if defined(CONFIG_BT_AUDIO_RX)
3071 if (sh_stream->is_rx) {
3072 rx_streaming_cnt--;
3073 memset(&sh_stream->rx, 0, sizeof(sh_stream->rx));
3074 }
3075 #endif
3076
3077 #if defined(CONFIG_BT_AUDIO_TX)
3078 if (sh_stream->is_tx) {
3079 memset(&sh_stream->tx, 0, sizeof(sh_stream->tx));
3080 }
3081 #endif
3082
3083 sh_stream->is_rx = sh_stream->is_tx = false;
3084
3085 #if defined(CONFIG_LIBLC3)
3086 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
3087 update_usb_streams(sh_stream);
3088 }
3089 #endif /* CONFIG_LIBLC3 */
3090 }
3091
stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)3092 static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
3093 {
3094 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
3095
3096 printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
3097
3098 clear_stream_data(sh_stream);
3099 }
3100
3101 #if defined(CONFIG_BT_BAP_UNICAST)
stream_configured_cb(struct bt_bap_stream * stream,const struct bt_audio_codec_qos_pref * pref)3102 static void stream_configured_cb(struct bt_bap_stream *stream,
3103 const struct bt_audio_codec_qos_pref *pref)
3104 {
3105 shell_print(ctx_shell, "Stream %p configured\n", stream);
3106 }
3107
stream_released_cb(struct bt_bap_stream * stream)3108 static void stream_released_cb(struct bt_bap_stream *stream)
3109 {
3110 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
3111
3112 shell_print(ctx_shell, "Stream %p released\n", stream);
3113
3114 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
3115 if (default_unicast_group != NULL) {
3116 bool group_can_be_deleted = true;
3117
3118 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
3119 const struct bt_bap_stream *bap_stream =
3120 bap_stream_from_shell_stream(&unicast_streams[i]);
3121
3122 if (bap_stream->ep != NULL) {
3123 struct bt_bap_ep_info ep_info;
3124 int err;
3125
3126 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
3127 if (err == 0 && ep_info.state != BT_BAP_EP_STATE_CODEC_CONFIGURED &&
3128 ep_info.state != BT_BAP_EP_STATE_IDLE) {
3129 group_can_be_deleted = false;
3130 break;
3131 }
3132 }
3133 }
3134
3135 if (group_can_be_deleted) {
3136 int err;
3137
3138 shell_print(ctx_shell, "All streams released, deleting group\n");
3139
3140 err = bt_bap_unicast_group_delete(default_unicast_group);
3141
3142 if (err != 0) {
3143 shell_error(ctx_shell, "Failed to delete unicast group: %d", err);
3144 } else {
3145 default_unicast_group = NULL;
3146 }
3147 }
3148 }
3149 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
3150
3151 clear_stream_data(sh_stream);
3152 }
3153 #endif /* CONFIG_BT_BAP_UNICAST */
3154
3155 static struct bt_bap_stream_ops stream_ops = {
3156 #if defined(CONFIG_BT_AUDIO_RX)
3157 .recv = audio_recv,
3158 #endif /* CONFIG_BT_AUDIO_RX */
3159 #if defined(CONFIG_BT_BAP_UNICAST)
3160 .configured = stream_configured_cb,
3161 .released = stream_released_cb,
3162 .enabled = stream_enabled_cb,
3163 #endif /* CONFIG_BT_BAP_UNICAST */
3164 .started = stream_started_cb,
3165 .stopped = stream_stopped_cb,
3166 #if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX)
3167 .sent = lc3_sent_cb,
3168 #endif
3169 };
3170
3171 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
cmd_select_broadcast_source(const struct shell * sh,size_t argc,char * argv[])3172 static int cmd_select_broadcast_source(const struct shell *sh, size_t argc,
3173 char *argv[])
3174 {
3175 unsigned long index;
3176 int err = 0;
3177
3178 index = shell_strtoul(argv[1], 0, &err);
3179 if (err != 0) {
3180 shell_error(sh, "Could not parse index: %d", err);
3181
3182 return -ENOEXEC;
3183 }
3184
3185 if (index > ARRAY_SIZE(broadcast_source_streams)) {
3186 shell_error(sh, "Invalid index: %lu", index);
3187
3188 return -ENOEXEC;
3189 }
3190
3191 default_stream = bap_stream_from_shell_stream(&broadcast_source_streams[index]);
3192
3193 return 0;
3194 }
3195
cmd_create_broadcast(const struct shell * sh,size_t argc,char * argv[])3196 static int cmd_create_broadcast(const struct shell *sh, size_t argc,
3197 char *argv[])
3198 {
3199 struct bt_bap_broadcast_source_stream_param
3200 stream_params[ARRAY_SIZE(broadcast_source_streams)];
3201 struct bt_bap_broadcast_source_subgroup_param subgroup_param;
3202 struct bt_bap_broadcast_source_param create_param = {0};
3203 const struct named_lc3_preset *named_preset;
3204 int err;
3205
3206 if (default_source.bap_source != NULL) {
3207 shell_info(sh, "Broadcast source already created");
3208 return -ENOEXEC;
3209 }
3210
3211 named_preset = &default_broadcast_source_preset;
3212
3213 for (size_t i = 1U; i < argc; i++) {
3214 char *arg = argv[i];
3215
3216 if (strcmp(arg, "enc") == 0) {
3217 if (argc > i) {
3218 size_t bcode_len;
3219
3220 i++;
3221 arg = argv[i];
3222
3223 bcode_len = hex2bin(arg, strlen(arg),
3224 create_param.broadcast_code,
3225 sizeof(create_param.broadcast_code));
3226
3227 if (bcode_len != sizeof(create_param.broadcast_code)) {
3228 shell_error(sh, "Invalid Broadcast Code Length: %zu",
3229 bcode_len);
3230
3231 return -ENOEXEC;
3232 }
3233
3234 create_param.encryption = true;
3235 } else {
3236 shell_help(sh);
3237
3238 return SHELL_CMD_HELP_PRINTED;
3239 }
3240 } else if (strcmp(arg, "preset") == 0) {
3241 if (argc > i) {
3242
3243 i++;
3244 arg = argv[i];
3245
3246 named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE,
3247 arg);
3248 if (named_preset == NULL) {
3249 shell_error(sh, "Unable to parse named_preset %s",
3250 arg);
3251
3252 return -ENOEXEC;
3253 }
3254 } else {
3255 shell_help(sh);
3256
3257 return SHELL_CMD_HELP_PRINTED;
3258 }
3259 }
3260 }
3261
3262 copy_broadcast_source_preset(&default_source, named_preset);
3263
3264 (void)memset(stream_params, 0, sizeof(stream_params));
3265 for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) {
3266 stream_params[i].stream =
3267 bap_stream_from_shell_stream(&broadcast_source_streams[i]);
3268 }
3269 subgroup_param.params_count = ARRAY_SIZE(stream_params);
3270 subgroup_param.params = stream_params;
3271 subgroup_param.codec_cfg = &default_source.codec_cfg;
3272 create_param.params_count = 1U;
3273 create_param.params = &subgroup_param;
3274 create_param.qos = &default_source.qos;
3275
3276 err = bt_bap_broadcast_source_create(&create_param, &default_source.bap_source);
3277 if (err != 0) {
3278 shell_error(sh, "Unable to create broadcast source: %d", err);
3279 return err;
3280 }
3281
3282 shell_print(sh, "Broadcast source created: preset %s",
3283 named_preset->name);
3284
3285 if (default_stream == NULL) {
3286 default_stream = bap_stream_from_shell_stream(&broadcast_source_streams[0]);
3287 }
3288
3289 return 0;
3290 }
3291
cmd_start_broadcast(const struct shell * sh,size_t argc,char * argv[])3292 static int cmd_start_broadcast(const struct shell *sh, size_t argc,
3293 char *argv[])
3294 {
3295 struct bt_le_ext_adv *adv = adv_sets[selected_adv];
3296 int err;
3297
3298 if (adv == NULL) {
3299 shell_info(sh, "Extended advertising set is NULL");
3300 return -ENOEXEC;
3301 }
3302
3303 if (default_source.bap_source == NULL || default_source.is_cap) {
3304 shell_info(sh, "Broadcast source not created");
3305 return -ENOEXEC;
3306 }
3307
3308 err = bt_bap_broadcast_source_start(default_source.bap_source, adv_sets[selected_adv]);
3309 if (err != 0) {
3310 shell_error(sh, "Unable to start broadcast source: %d", err);
3311 return err;
3312 }
3313
3314 return 0;
3315 }
3316
cmd_stop_broadcast(const struct shell * sh,size_t argc,char * argv[])3317 static int cmd_stop_broadcast(const struct shell *sh, size_t argc, char *argv[])
3318 {
3319 int err;
3320
3321 if (default_source.bap_source == NULL || default_source.is_cap) {
3322 shell_info(sh, "Broadcast source not created");
3323 return -ENOEXEC;
3324 }
3325
3326 err = bt_bap_broadcast_source_stop(default_source.bap_source);
3327 if (err != 0) {
3328 shell_error(sh, "Unable to stop broadcast source: %d", err);
3329 return err;
3330 }
3331
3332 return 0;
3333 }
3334
cmd_delete_broadcast(const struct shell * sh,size_t argc,char * argv[])3335 static int cmd_delete_broadcast(const struct shell *sh, size_t argc,
3336 char *argv[])
3337 {
3338 int err;
3339
3340 if (default_source.bap_source == NULL || default_source.is_cap) {
3341 shell_info(sh, "Broadcast source not created");
3342 return -ENOEXEC;
3343 }
3344
3345 err = bt_bap_broadcast_source_delete(default_source.bap_source);
3346 if (err != 0) {
3347 shell_error(sh, "Unable to delete broadcast source: %d", err);
3348 return err;
3349 }
3350 default_source.bap_source = NULL;
3351
3352 return 0;
3353 }
3354 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3355
3356 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
cmd_create_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3357 static int cmd_create_broadcast_sink(const struct shell *sh, size_t argc, char *argv[])
3358 {
3359 struct bt_le_per_adv_sync *per_adv_sync = per_adv_syncs[selected_per_adv_sync];
3360 unsigned long broadcast_id;
3361 int err = 0;
3362
3363 broadcast_id = shell_strtoul(argv[1], 0, &err);
3364 if (err != 0) {
3365 shell_error(sh, "Could not parse broadcast_id: %d", err);
3366
3367 return -ENOEXEC;
3368 }
3369
3370 if (broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
3371 shell_error(sh, "Invalid broadcast_id: %lu", broadcast_id);
3372
3373 return -ENOEXEC;
3374 }
3375
3376 if (per_adv_sync == NULL) {
3377 const struct bt_le_scan_param param = {
3378 .type = BT_LE_SCAN_TYPE_ACTIVE,
3379 .options = BT_LE_SCAN_OPT_NONE,
3380 .interval = BT_GAP_SCAN_FAST_INTERVAL,
3381 .window = BT_GAP_SCAN_FAST_WINDOW,
3382 .timeout = 1000, /* 10ms units -> 10 second timeout */
3383 };
3384
3385 shell_print(sh, "No PA sync available, starting scanning for broadcast_id");
3386
3387 err = bt_le_scan_start(¶m, NULL);
3388 if (err) {
3389 shell_print(sh, "Fail to start scanning: %d", err);
3390
3391 return -ENOEXEC;
3392 }
3393
3394 auto_scan.broadcast_sink = &default_broadcast_sink;
3395 auto_scan.broadcast_id = broadcast_id;
3396 auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync];
3397 } else {
3398 shell_print(sh, "Creating broadcast sink with broadcast ID 0x%06X",
3399 (uint32_t)broadcast_id);
3400
3401 err = bt_bap_broadcast_sink_create(per_adv_sync, (uint32_t)broadcast_id,
3402 &default_broadcast_sink.bap_sink);
3403
3404 if (err != 0) {
3405 shell_error(sh, "Failed to create broadcast sink: %d", err);
3406
3407 return -ENOEXEC;
3408 }
3409 }
3410
3411 return 0;
3412 }
3413
cmd_sync_broadcast(const struct shell * sh,size_t argc,char * argv[])3414 static int cmd_sync_broadcast(const struct shell *sh, size_t argc, char *argv[])
3415 {
3416 struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)];
3417 uint8_t bcode[BT_AUDIO_BROADCAST_CODE_SIZE] = {0};
3418 bool bcode_set = false;
3419 uint32_t bis_bitfield;
3420 size_t stream_cnt;
3421 int err = 0;
3422
3423 bis_bitfield = 0;
3424 stream_cnt = 0U;
3425 for (size_t argn = 1U; argn < argc; argn++) {
3426 const char *arg = argv[argn];
3427
3428 if (strcmp(argv[argn], "bcode") == 0) {
3429 size_t len;
3430
3431 if (++argn == argc) {
3432 shell_help(sh);
3433
3434 return SHELL_CMD_HELP_PRINTED;
3435 }
3436
3437 arg = argv[argn];
3438
3439 len = hex2bin(arg, strlen(arg), bcode, sizeof(bcode));
3440 if (len == 0) {
3441 shell_print(sh, "Invalid broadcast code: %s", arg);
3442
3443 return -ENOEXEC;
3444 }
3445
3446 bcode_set = true;
3447 } else if (strcmp(argv[argn], "bcode_str") == 0) {
3448 if (++argn == argc) {
3449 shell_help(sh);
3450
3451 return SHELL_CMD_HELP_PRINTED;
3452 }
3453
3454 arg = argv[argn];
3455
3456 if (strlen(arg) == 0U || strlen(arg) > sizeof(bcode)) {
3457 shell_print(sh, "Invalid broadcast code: %s", arg);
3458
3459 return -ENOEXEC;
3460 }
3461
3462 memcpy(bcode, arg, strlen(arg));
3463 bcode_set = true;
3464 } else {
3465 unsigned long val;
3466
3467 val = shell_strtoul(arg, 0, &err);
3468 if (err != 0) {
3469 shell_error(sh, "Could not parse BIS index val: %d", err);
3470
3471 return -ENOEXEC;
3472 }
3473
3474 if (!IN_RANGE(val, BT_ISO_BIS_INDEX_MIN, BT_ISO_BIS_INDEX_MAX)) {
3475 shell_error(sh, "Invalid index: %lu", val);
3476
3477 return -ENOEXEC;
3478 }
3479
3480 bis_bitfield |= BT_ISO_BIS_INDEX_BIT(val);
3481 stream_cnt++;
3482 }
3483 }
3484
3485 if (default_broadcast_sink.bap_sink == NULL) {
3486 shell_error(sh, "No sink available");
3487 return -ENOEXEC;
3488 }
3489
3490 (void)memset(streams, 0, sizeof(streams));
3491 for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
3492 streams[i] = bap_stream_from_shell_stream(&broadcast_sink_streams[i]);
3493 }
3494
3495 err = bt_bap_broadcast_sink_sync(default_broadcast_sink.bap_sink, bis_bitfield, streams,
3496 bcode_set ? bcode : NULL);
3497 if (err != 0) {
3498 shell_error(sh, "Failed to sync to broadcast: %d", err);
3499 return err;
3500 }
3501
3502 default_broadcast_sink.stream_cnt = stream_cnt;
3503
3504 return 0;
3505 }
3506
cmd_stop_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3507 static int cmd_stop_broadcast_sink(const struct shell *sh, size_t argc,
3508 char *argv[])
3509 {
3510 int err;
3511
3512 if (default_broadcast_sink.bap_sink == NULL) {
3513 shell_error(sh, "No sink available");
3514 return -ENOEXEC;
3515 }
3516
3517 err = bt_bap_broadcast_sink_stop(default_broadcast_sink.bap_sink);
3518 if (err != 0) {
3519 shell_error(sh, "Failed to stop sink: %d", err);
3520 return err;
3521 }
3522
3523 return err;
3524 }
3525
cmd_term_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3526 static int cmd_term_broadcast_sink(const struct shell *sh, size_t argc,
3527 char *argv[])
3528 {
3529 int err;
3530
3531 if (default_broadcast_sink.bap_sink == NULL) {
3532 shell_error(sh, "No sink available");
3533 return -ENOEXEC;
3534 }
3535
3536 err = bt_bap_broadcast_sink_delete(default_broadcast_sink.bap_sink);
3537 if (err != 0) {
3538 shell_error(sh, "Failed to term sink: %d", err);
3539 return err;
3540 }
3541
3542 default_broadcast_sink.bap_sink = NULL;
3543 default_broadcast_sink.syncable = false;
3544
3545 return err;
3546 }
3547 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
3548
cmd_set_loc(const struct shell * sh,size_t argc,char * argv[])3549 static int cmd_set_loc(const struct shell *sh, size_t argc, char *argv[])
3550 {
3551 int err = 0;
3552 enum bt_audio_dir dir;
3553 enum bt_audio_location loc;
3554 unsigned long loc_val;
3555
3556 if (!strcmp(argv[1], "sink")) {
3557 dir = BT_AUDIO_DIR_SINK;
3558 } else if (!strcmp(argv[1], "source")) {
3559 dir = BT_AUDIO_DIR_SOURCE;
3560 } else {
3561 shell_error(sh, "Unsupported dir: %s", argv[1]);
3562 return -ENOEXEC;
3563 }
3564
3565 loc_val = shell_strtoul(argv[2], 16, &err);
3566 if (err != 0) {
3567 shell_error(sh, "Could not parse loc_val: %d", err);
3568
3569 return -ENOEXEC;
3570 }
3571
3572 if (loc_val > BT_AUDIO_LOCATION_ANY) {
3573 shell_error(sh, "Invalid location: %lu", loc_val);
3574
3575 return -ENOEXEC;
3576 }
3577
3578 loc = loc_val;
3579
3580 err = bt_pacs_set_location(dir, loc);
3581 if (err) {
3582 shell_error(ctx_shell, "Set available contexts err %d", err);
3583 return -ENOEXEC;
3584 }
3585
3586 return 0;
3587 }
3588
cmd_context(const struct shell * sh,size_t argc,char * argv[])3589 static int cmd_context(const struct shell *sh, size_t argc, char *argv[])
3590 {
3591 int err = 0;
3592 enum bt_audio_dir dir;
3593 enum bt_audio_context ctx;
3594 unsigned long ctx_val;
3595
3596 if (!strcmp(argv[1], "sink")) {
3597 dir = BT_AUDIO_DIR_SINK;
3598 } else if (!strcmp(argv[1], "source")) {
3599 dir = BT_AUDIO_DIR_SOURCE;
3600 } else {
3601 shell_error(sh, "Unsupported dir: %s", argv[1]);
3602 return -ENOEXEC;
3603 }
3604
3605 ctx_val = shell_strtoul(argv[2], 16, &err);
3606 if (err) {
3607 shell_error(sh, "Could not parse context: %d", err);
3608
3609 return err;
3610 }
3611
3612 if (ctx_val == BT_AUDIO_CONTEXT_TYPE_PROHIBITED ||
3613 ctx_val > BT_AUDIO_CONTEXT_TYPE_ANY) {
3614 shell_error(sh, "Invalid context: %lu", ctx_val);
3615
3616 return -ENOEXEC;
3617 }
3618
3619 ctx = ctx_val;
3620
3621 if (!strcmp(argv[3], "supported")) {
3622 err = bt_pacs_set_supported_contexts(dir, ctx);
3623 if (err) {
3624 shell_error(ctx_shell, "Set supported contexts err %d", err);
3625 return err;
3626 }
3627 } else if (!strcmp(argv[3], "available")) {
3628 err = bt_pacs_set_available_contexts(dir, ctx);
3629 if (err) {
3630 shell_error(ctx_shell, "Set available contexts err %d", err);
3631 return err;
3632 }
3633 } else {
3634 shell_error(sh, "Unsupported context type: %s", argv[3]);
3635 return -ENOEXEC;
3636 }
3637
3638 return 0;
3639 }
3640
cmd_init(const struct shell * sh,size_t argc,char * argv[])3641 static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
3642 {
3643 int err, i;
3644
3645 ctx_shell = sh;
3646
3647 if (initialized) {
3648 shell_print(sh, "Already initialized");
3649 return -ENOEXEC;
3650 }
3651
3652 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
3653 bt_bap_unicast_server_register_cb(&unicast_server_cb);
3654 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
3655
3656 #if defined(CONFIG_BT_PAC_SNK)
3657 bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
3658 #endif /* CONFIG_BT_PAC_SNK */
3659 #if defined(CONFIG_BT_PAC_SRC)
3660 bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source);
3661 #endif /* CONFIG_BT_PAC_SNK */
3662
3663 if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
3664 err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, LOCATION);
3665 __ASSERT(err == 0, "Failed to set sink location: %d", err);
3666
3667 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK,
3668 CONTEXT);
3669 __ASSERT(err == 0, "Failed to set sink supported contexts: %d",
3670 err);
3671
3672 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
3673 CONTEXT);
3674 __ASSERT(err == 0, "Failed to set sink available contexts: %d",
3675 err);
3676 }
3677
3678 if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
3679 err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, LOCATION);
3680 __ASSERT(err == 0, "Failed to set source location: %d", err);
3681
3682 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
3683 CONTEXT);
3684 __ASSERT(err == 0, "Failed to set sink supported contexts: %d",
3685 err);
3686
3687 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
3688 CONTEXT);
3689 __ASSERT(err == 0,
3690 "Failed to set source available contexts: %d",
3691 err);
3692 }
3693
3694 #if defined(CONFIG_BT_BAP_UNICAST)
3695 for (i = 0; i < ARRAY_SIZE(unicast_streams); i++) {
3696 bt_bap_stream_cb_register(bap_stream_from_shell_stream(&unicast_streams[i]),
3697 &stream_ops);
3698
3699 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
3700 IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
3701 /* If we use the cap initiator, we need to register the callbacks for CAP
3702 * as well, as CAP will override and use the BAP callbacks if doing a CAP
3703 * procedure
3704 */
3705 bt_cap_stream_ops_register(&unicast_streams[i].stream, &stream_ops);
3706 }
3707 }
3708 #endif /* CONFIG_BT_BAP_UNICAST */
3709
3710 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
3711 bt_bap_broadcast_sink_register_cb(&sink_cbs);
3712 bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
3713 bt_le_scan_cb_register(&bap_scan_cb);
3714
3715 for (i = 0; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
3716 bt_bap_stream_cb_register(bap_stream_from_shell_stream(&broadcast_sink_streams[i]),
3717 &stream_ops);
3718 }
3719 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3720
3721 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
3722 for (i = 0; i < ARRAY_SIZE(broadcast_source_streams); i++) {
3723 bt_bap_stream_cb_register(
3724 bap_stream_from_shell_stream(&broadcast_source_streams[i]), &stream_ops);
3725 }
3726 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3727
3728 #if defined(CONFIG_LIBLC3)
3729 #if defined(CONFIG_BT_AUDIO_RX)
3730 static K_KERNEL_STACK_DEFINE(lc3_decoder_thread_stack, 4096);
3731 const int lc3_decoder_thread_prio = K_PRIO_PREEMPT(5);
3732 static struct k_thread lc3_decoder_thread;
3733
3734 k_thread_create(&lc3_decoder_thread, lc3_decoder_thread_stack,
3735 K_KERNEL_STACK_SIZEOF(lc3_decoder_thread_stack), lc3_decoder_thread_func,
3736 NULL, NULL, NULL, lc3_decoder_thread_prio, 0, K_NO_WAIT);
3737 k_thread_name_set(&lc3_decoder_thread, "LC3 Decoder");
3738 #endif /* CONFIG_BT_AUDIO_RX */
3739
3740 #if defined(CONFIG_BT_AUDIO_TX)
3741 static K_KERNEL_STACK_DEFINE(lc3_encoder_thread_stack, 4096);
3742 const int lc3_encoder_thread_prio = K_PRIO_PREEMPT(5);
3743 static struct k_thread lc3_encoder_thread;
3744
3745 k_thread_create(&lc3_encoder_thread, lc3_encoder_thread_stack,
3746 K_KERNEL_STACK_SIZEOF(lc3_encoder_thread_stack), lc3_encoder_thread_func,
3747 NULL, NULL, NULL, lc3_encoder_thread_prio, 0, K_NO_WAIT);
3748 k_thread_name_set(&lc3_encoder_thread, "LC3 Encoder");
3749
3750 #endif /* CONFIG_BT_AUDIO_TX */
3751
3752 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) &&
3753 (IS_ENABLED(CONFIG_BT_AUDIO_RX) || IS_ENABLED(CONFIG_BT_AUDIO_TX))) {
3754 err = bap_usb_init();
3755 __ASSERT(err == 0, "Failed to enable USB: %d", err);
3756 }
3757 #endif /* CONFIG_LIBLC3 */
3758
3759 initialized = true;
3760
3761 return 0;
3762 }
3763
3764 #if defined(CONFIG_BT_AUDIO_TX)
3765
3766 #define DATA_MTU CONFIG_BT_ISO_TX_MTU
3767 NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
3768
cmd_send(const struct shell * sh,size_t argc,char * argv[])3769 static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
3770 {
3771 static uint8_t data[DATA_MTU - BT_ISO_CHAN_SEND_RESERVE];
3772 int ret, len;
3773 struct net_buf *buf;
3774
3775 if (default_stream == NULL) {
3776 shell_error(sh, "Invalid (NULL) stream");
3777
3778 return -ENOEXEC;
3779 }
3780
3781 if (default_stream->qos == NULL) {
3782 shell_error(sh, "NULL stream QoS");
3783
3784 return -ENOEXEC;
3785 }
3786
3787 if (argc > 1) {
3788 len = hex2bin(argv[1], strlen(argv[1]), data, sizeof(data));
3789 if (len > default_stream->qos->sdu) {
3790 shell_print(sh, "Unable to send: len %d > %u MTU",
3791 len, default_stream->qos->sdu);
3792
3793 return -ENOEXEC;
3794 }
3795 } else {
3796 len = MIN(default_stream->qos->sdu, sizeof(data));
3797 memset(data, 0xff, len);
3798 }
3799
3800 buf = net_buf_alloc(&tx_pool, K_FOREVER);
3801 net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
3802
3803 net_buf_add_mem(buf, data, len);
3804
3805 ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(default_stream));
3806 if (ret < 0) {
3807 shell_print(sh, "Unable to send: %d", -ret);
3808 net_buf_unref(buf);
3809
3810 return -ENOEXEC;
3811 }
3812
3813 shell_print(sh, "Sending:");
3814 shell_hexdump(sh, data, len);
3815
3816 return 0;
3817 }
3818
3819 #if GENERATE_SINE_SUPPORTED
start_sine_stream_cb(struct shell_stream * sh_stream,void * user_data)3820 static void start_sine_stream_cb(struct shell_stream *sh_stream, void *user_data)
3821 {
3822 if (sh_stream->is_tx) {
3823 struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream);
3824 const struct shell *sh = user_data;
3825 int err;
3826
3827 err = init_lc3_encoder(sh_stream);
3828 if (err != 0) {
3829 shell_error(sh, "Failed to init LC3 %d for stream %p", err, bap_stream);
3830
3831 return;
3832 }
3833
3834 sh_stream->tx.active = true;
3835 sh_stream->tx.seq_num = get_next_seq_num(bap_stream_from_shell_stream(sh_stream));
3836
3837 shell_print(sh, "Started transmitting sine on stream %p", bap_stream);
3838 }
3839 }
3840
cmd_start_sine(const struct shell * sh,size_t argc,char * argv[])3841 static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
3842 {
3843 bool start_all = false;
3844
3845 if (argc > 1) {
3846 if (strcmp(argv[1], "all") == 0) {
3847 start_all = true;
3848 } else {
3849 shell_help(sh);
3850
3851 return SHELL_CMD_HELP_PRINTED;
3852 }
3853 }
3854
3855 if (start_all) {
3856 bap_foreach_stream(start_sine_stream_cb, (void *)sh);
3857 } else {
3858 struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream);
3859
3860 start_sine_stream_cb(sh_stream, (void *)sh);
3861 }
3862
3863 return 0;
3864 }
3865
stop_sine_stream_cb(struct shell_stream * sh_stream,void * user_data)3866 static void stop_sine_stream_cb(struct shell_stream *sh_stream, void *user_data)
3867 {
3868 if (sh_stream->is_tx) {
3869 struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream);
3870 const struct shell *sh = user_data;
3871
3872 shell_print(sh, "Stopped transmitting on stream %p", bap_stream);
3873
3874 sh_stream->tx.active = false;
3875 }
3876 }
3877
cmd_stop_sine(const struct shell * sh,size_t argc,char * argv[])3878 static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[])
3879 {
3880 bool stop_all = false;
3881
3882 if (argc > 1) {
3883 if (strcmp(argv[1], "all") == 0) {
3884 stop_all = true;
3885 } else {
3886 shell_help(sh);
3887
3888 return SHELL_CMD_HELP_PRINTED;
3889 }
3890 }
3891
3892 if (stop_all) {
3893 bap_foreach_stream(stop_sine_stream_cb, (void *)sh);
3894 } else {
3895 struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream);
3896
3897 stop_sine_stream_cb(sh_stream, (void *)sh);
3898 }
3899
3900 return 0;
3901 }
3902 #endif /* GENERATE_SINE_SUPPORTED */
3903 #endif /* CONFIG_BT_AUDIO_TX */
3904
cmd_bap_stats(const struct shell * sh,size_t argc,char * argv[])3905 static int cmd_bap_stats(const struct shell *sh, size_t argc, char *argv[])
3906 {
3907 if (argc == 1) {
3908 shell_info(sh, "Current stats interval: %lu", bap_stats_interval);
3909 } else {
3910 int err = 0;
3911 unsigned long interval;
3912
3913 interval = shell_strtoul(argv[1], 0, &err);
3914 if (err != 0) {
3915 shell_error(sh, "Could not parse interval: %d", err);
3916
3917 return -ENOEXEC;
3918 }
3919
3920 if (interval == 0U) {
3921 shell_error(sh, "Interval cannot be 0");
3922
3923 return -ENOEXEC;
3924 }
3925
3926 bap_stats_interval = interval;
3927 }
3928
3929 return 0;
3930 }
3931
3932 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
print_ase_info(struct bt_bap_ep * ep,void * user_data)3933 static void print_ase_info(struct bt_bap_ep *ep, void *user_data)
3934 {
3935 struct bt_bap_ep_info info;
3936 int err;
3937
3938 err = bt_bap_ep_get_info(ep, &info);
3939 if (err == 0) {
3940 printk("ASE info: id %u state %u dir %u\n", info.id, info.state, info.dir);
3941 }
3942 }
3943
cmd_print_ase_info(const struct shell * sh,size_t argc,char * argv[])3944 static int cmd_print_ase_info(const struct shell *sh, size_t argc, char *argv[])
3945 {
3946 if (!default_conn) {
3947 shell_error(sh, "Not connected");
3948 return -ENOEXEC;
3949 }
3950
3951 bt_bap_unicast_server_foreach_ep(default_conn, print_ase_info, NULL);
3952
3953 return 0;
3954 }
3955 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
3956
3957 /* 31 is a unit separator - without t the tab is seemingly ignored*/
3958 #define HELP_SEP "\n\31\t"
3959
3960 #define HELP_CFG_DATA \
3961 "\n[config" HELP_SEP "[freq <frequency>]" HELP_SEP "[dur <duration>]" HELP_SEP \
3962 "[chan_alloc <location>]" HELP_SEP "[frame_len <frame length>]" HELP_SEP \
3963 "[frame_blks <frame blocks>]]"
3964
3965 #define HELP_CFG_META \
3966 "\n[meta" HELP_SEP "[pref_ctx <context>]" HELP_SEP "[stream_ctx <context>]" HELP_SEP \
3967 "[program_info <program info>]" HELP_SEP "[lang <ISO 639-3 lang>]" HELP_SEP \
3968 "[ccid_list <ccids>]" HELP_SEP "[parental_rating <rating>]" HELP_SEP \
3969 "[program_info_uri <URI>]" HELP_SEP "[audio_active_state <state>]" HELP_SEP \
3970 "[bcast_flag]" HELP_SEP "[extended <meta>]" HELP_SEP "[vendor <meta>]]"
3971
3972 SHELL_STATIC_SUBCMD_SET_CREATE(
3973 bap_cmds, SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0),
3974 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
3975 SHELL_CMD_ARG(select_broadcast, NULL, "<stream>", cmd_select_broadcast_source, 2, 0),
3976 SHELL_CMD_ARG(create_broadcast, NULL, "[preset <preset_name>] [enc <broadcast_code>]",
3977 cmd_create_broadcast, 1, 2),
3978 SHELL_CMD_ARG(start_broadcast, NULL, "", cmd_start_broadcast, 1, 0),
3979 SHELL_CMD_ARG(stop_broadcast, NULL, "", cmd_stop_broadcast, 1, 0),
3980 SHELL_CMD_ARG(delete_broadcast, NULL, "", cmd_delete_broadcast, 1, 0),
3981 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3982 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
3983 SHELL_CMD_ARG(create_broadcast_sink, NULL, "0x<broadcast_id>", cmd_create_broadcast_sink, 2,
3984 0),
3985 SHELL_CMD_ARG(sync_broadcast, NULL,
3986 "0x<bis_index> [[[0x<bis_index>] 0x<bis_index>] ...] "
3987 "[bcode <broadcast code> || bcode_str <broadcast code as string>]",
3988 cmd_sync_broadcast, 2, ARRAY_SIZE(broadcast_sink_streams) + 1),
3989 SHELL_CMD_ARG(stop_broadcast_sink, NULL, "Stops broadcast sink", cmd_stop_broadcast_sink, 1,
3990 0),
3991 SHELL_CMD_ARG(term_broadcast_sink, NULL, "", cmd_term_broadcast_sink, 1, 0),
3992 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
3993 #if defined(CONFIG_BT_BAP_UNICAST)
3994 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
3995 SHELL_CMD_ARG(discover, NULL, "[dir: sink, source]", cmd_discover, 1, 1),
3996 SHELL_CMD_ARG(config, NULL,
3997 "<direction: sink, source> <index> [loc <loc_bits>] [preset <preset_name>]",
3998 cmd_config, 3, 4),
3999 SHELL_CMD_ARG(stream_qos, NULL, "interval [framing] [latency] [pd] [sdu] [phy] [rtn]",
4000 cmd_stream_qos, 2, 6),
4001 SHELL_CMD_ARG(connect, NULL, "Connect the CIS of the stream", cmd_connect, 1, 0),
4002 SHELL_CMD_ARG(qos, NULL, "Send QoS configure for Unicast Group", cmd_qos, 1, 0),
4003 SHELL_CMD_ARG(enable, NULL, "[context]", cmd_enable, 1, 1),
4004 SHELL_CMD_ARG(stop, NULL, NULL, cmd_stop, 1, 0),
4005 SHELL_CMD_ARG(list, NULL, NULL, cmd_list, 1, 0),
4006 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
4007 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
4008 SHELL_CMD_ARG(print_ase_info, NULL, "Print ASE info for default connection",
4009 cmd_print_ase_info, 0, 0),
4010 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
4011 SHELL_CMD_ARG(metadata, NULL, "[context]", cmd_metadata, 1, 1),
4012 SHELL_CMD_ARG(start, NULL, NULL, cmd_start, 1, 0),
4013 SHELL_CMD_ARG(disable, NULL, NULL, cmd_disable, 1, 0),
4014 SHELL_CMD_ARG(release, NULL, NULL, cmd_release, 1, 0),
4015 SHELL_CMD_ARG(select_unicast, NULL, "<stream>", cmd_select_unicast, 2, 0),
4016 #endif /* CONFIG_BT_BAP_UNICAST */
4017 #if IS_BAP_INITIATOR
4018 SHELL_CMD_ARG(preset, NULL,
4019 "<sink, source, broadcast> [preset] " HELP_CFG_DATA " " HELP_CFG_META,
4020 cmd_preset, 2, 34),
4021 #endif /* IS_BAP_INITIATOR */
4022 #if defined(CONFIG_BT_AUDIO_TX)
4023 SHELL_CMD_ARG(send, NULL, "Send to Audio Stream [data]", cmd_send, 1, 1),
4024 #if GENERATE_SINE_SUPPORTED
4025 SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave [all]",
4026 cmd_start_sine, 1, 1),
4027 SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave [all]", cmd_stop_sine,
4028 1, 1),
4029 #endif /* GENERATE_SINE_SUPPORTED */
4030 #endif /* CONFIG_BT_AUDIO_TX */
4031 SHELL_CMD_ARG(bap_stats, NULL,
4032 "Sets or gets the statistics reporting interval in # of packets",
4033 cmd_bap_stats, 1, 1),
4034 SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_location, NULL,
4035 "<direction: sink, source> <location bitmask>", cmd_set_loc, 3, 0),
4036 SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_context, NULL,
4037 "<direction: sink, source>"
4038 "<context bitmask> <type: supported, available>",
4039 cmd_context, 4, 0),
4040 SHELL_SUBCMD_SET_END);
4041
cmd_bap(const struct shell * sh,size_t argc,char ** argv)4042 static int cmd_bap(const struct shell *sh, size_t argc, char **argv)
4043 {
4044 if (argc > 1) {
4045 shell_error(sh, "%s unknown parameter: %s",
4046 argv[0], argv[1]);
4047 } else {
4048 shell_error(sh, "%s Missing subcommand", argv[0]);
4049 }
4050
4051 return -ENOEXEC;
4052 }
4053
4054 SHELL_CMD_ARG_REGISTER(bap, &bap_cmds, "Bluetooth BAP shell commands", cmd_bap, 1, 1);
4055
connectable_ad_data_add(struct bt_data * data_array,size_t data_array_size)4056 static ssize_t connectable_ad_data_add(struct bt_data *data_array,
4057 size_t data_array_size)
4058 {
4059 static const uint8_t ad_ext_uuid16[] = {
4060 IF_ENABLED(CONFIG_BT_MICP_MIC_DEV, (BT_UUID_16_ENCODE(BT_UUID_MICS_VAL),))
4061 IF_ENABLED(CONFIG_BT_ASCS, (BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),))
4062 IF_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR, (BT_UUID_16_ENCODE(BT_UUID_BASS_VAL),))
4063 IF_ENABLED(CONFIG_BT_PACS, (BT_UUID_16_ENCODE(BT_UUID_PACS_VAL),))
4064 IF_ENABLED(CONFIG_BT_GTBS, (BT_UUID_16_ENCODE(BT_UUID_GTBS_VAL),))
4065 IF_ENABLED(CONFIG_BT_TBS, (BT_UUID_16_ENCODE(BT_UUID_TBS_VAL),))
4066 IF_ENABLED(CONFIG_BT_VCP_VOL_REND, (BT_UUID_16_ENCODE(BT_UUID_VCS_VAL),))
4067 IF_ENABLED(CONFIG_BT_HAS, (BT_UUID_16_ENCODE(BT_UUID_HAS_VAL),)) /* Shall be last */
4068 };
4069 size_t ad_len = 0;
4070
4071 if (IS_ENABLED(CONFIG_BT_ASCS)) {
4072 static uint8_t ad_bap_announcement[8] = {
4073 BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),
4074 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
4075 };
4076 enum bt_audio_context snk_context, src_context;
4077
4078 snk_context = bt_pacs_get_available_contexts(BT_AUDIO_DIR_SINK);
4079 sys_put_le16(snk_context, &ad_bap_announcement[3]);
4080
4081 src_context = bt_pacs_get_available_contexts(BT_AUDIO_DIR_SOURCE);
4082 sys_put_le16(src_context, &ad_bap_announcement[5]);
4083
4084 /* Metadata length */
4085 ad_bap_announcement[7] = 0x00;
4086
4087 __ASSERT(data_array_size > ad_len, "No space for AD_BAP_ANNOUNCEMENT");
4088 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4089 data_array[ad_len].data_len = ARRAY_SIZE(ad_bap_announcement);
4090 data_array[ad_len].data = &ad_bap_announcement[0];
4091 ad_len++;
4092 }
4093
4094 if (IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR)) {
4095 ad_len += bap_scan_delegator_ad_data_add(&data_array[ad_len],
4096 data_array_size - ad_len);
4097 }
4098
4099 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR)) {
4100 ad_len += cap_acceptor_ad_data_add(&data_array[ad_len], data_array_size - ad_len,
4101 true);
4102 }
4103
4104 if (IS_ENABLED(CONFIG_BT_GMAP)) {
4105 ad_len += gmap_ad_data_add(&data_array[ad_len], data_array_size - ad_len);
4106 }
4107
4108 if (ARRAY_SIZE(ad_ext_uuid16) > 0) {
4109 size_t uuid16_size;
4110
4111 if (data_array_size <= ad_len) {
4112 shell_warn(ctx_shell, "No space for AD_UUID16");
4113 return ad_len;
4114 }
4115
4116 data_array[ad_len].type = BT_DATA_UUID16_SOME;
4117
4118 if (IS_ENABLED(CONFIG_BT_HAS) && IS_ENABLED(CONFIG_BT_PRIVACY)) {
4119 /* If the HA is in one of the GAP connectable modes and is using a
4120 * resolvable private address, the HA shall not include the Hearing Access
4121 * Service UUID in the Service UUID AD type field of the advertising data
4122 * or scan response.
4123 */
4124 uuid16_size = ARRAY_SIZE(ad_ext_uuid16) - BT_UUID_SIZE_16;
4125 } else {
4126 uuid16_size = ARRAY_SIZE(ad_ext_uuid16);
4127 }
4128
4129 /* We can maximum advertise 127 16-bit UUIDs = 254 octets */
4130 data_array[ad_len].data_len = MIN(uuid16_size, 254);
4131
4132 data_array[ad_len].data = &ad_ext_uuid16[0];
4133 ad_len++;
4134 }
4135
4136 return ad_len;
4137 }
4138
nonconnectable_ad_data_add(struct bt_data * data_array,const size_t data_array_size)4139 static ssize_t nonconnectable_ad_data_add(struct bt_data *data_array,
4140 const size_t data_array_size)
4141 {
4142 static const uint8_t ad_ext_uuid16[] = {
4143 IF_ENABLED(CONFIG_BT_PACS, (BT_UUID_16_ENCODE(BT_UUID_PACS_VAL),))
4144 IF_ENABLED(CONFIG_BT_CAP_ACCEPTOR, (BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),))
4145 };
4146 size_t ad_len = 0;
4147
4148 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR)) {
4149 static const uint8_t ad_cap_announcement[3] = {
4150 BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),
4151 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
4152 };
4153
4154 __ASSERT(data_array_size > ad_len, "No space for AD_CAP_ANNOUNCEMENT");
4155 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4156 data_array[ad_len].data_len = ARRAY_SIZE(ad_cap_announcement);
4157 data_array[ad_len].data = &ad_cap_announcement[0];
4158 ad_len++;
4159 }
4160
4161 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
4162 if (default_source.bap_source != NULL && !default_source.is_cap) {
4163 static uint8_t ad_bap_broadcast_announcement[5] = {
4164 BT_UUID_16_ENCODE(BT_UUID_BROADCAST_AUDIO_VAL),
4165 };
4166 uint32_t broadcast_id;
4167 int err;
4168
4169 err = bt_bap_broadcast_source_get_id(default_source.bap_source, &broadcast_id);
4170 if (err != 0) {
4171 printk("Unable to get broadcast ID: %d\n", err);
4172
4173 return -1;
4174 }
4175
4176 sys_put_le24(broadcast_id, &ad_bap_broadcast_announcement[2]);
4177 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4178 data_array[ad_len].data_len = ARRAY_SIZE(ad_bap_broadcast_announcement);
4179 data_array[ad_len].data = ad_bap_broadcast_announcement;
4180 ad_len++;
4181 }
4182 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
4183
4184 if (ARRAY_SIZE(ad_ext_uuid16) > 0) {
4185 if (data_array_size <= ad_len) {
4186 shell_warn(ctx_shell, "No space for AD_UUID16");
4187 return ad_len;
4188 }
4189
4190 data_array[ad_len].type = BT_DATA_UUID16_SOME;
4191 data_array[ad_len].data_len = ARRAY_SIZE(ad_ext_uuid16);
4192 data_array[ad_len].data = &ad_ext_uuid16[0];
4193 ad_len++;
4194 }
4195
4196 return ad_len;
4197 }
4198
audio_ad_data_add(struct bt_data * data_array,const size_t data_array_size,const bool discoverable,const bool connectable)4199 ssize_t audio_ad_data_add(struct bt_data *data_array, const size_t data_array_size,
4200 const bool discoverable, const bool connectable)
4201 {
4202 ssize_t ad_len = 0;
4203
4204 if (!discoverable) {
4205 return 0;
4206 }
4207
4208 if (connectable) {
4209 ad_len += connectable_ad_data_add(data_array, data_array_size);
4210 } else {
4211 ad_len += nonconnectable_ad_data_add(data_array, data_array_size);
4212 }
4213
4214 if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
4215 ad_len += cap_initiator_ad_data_add(data_array, data_array_size, discoverable,
4216 connectable);
4217 }
4218
4219 return ad_len;
4220 }
4221
audio_pa_data_add(struct bt_data * data_array,const size_t data_array_size)4222 ssize_t audio_pa_data_add(struct bt_data *data_array,
4223 const size_t data_array_size)
4224 {
4225 size_t ad_len = 0;
4226
4227 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
4228 if (default_source.bap_source != NULL && !default_source.is_cap) {
4229 /* Required size of the buffer depends on what has been
4230 * configured. We just use the maximum size possible.
4231 */
4232 NET_BUF_SIMPLE_DEFINE_STATIC(base_buf, UINT8_MAX);
4233 int err;
4234
4235 net_buf_simple_reset(&base_buf);
4236
4237 err = bt_bap_broadcast_source_get_base(default_source.bap_source, &base_buf);
4238 if (err != 0) {
4239 printk("Unable to get BASE: %d\n", err);
4240
4241 return -1;
4242 }
4243
4244 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4245 data_array[ad_len].data_len = base_buf.len;
4246 data_array[ad_len].data = base_buf.data;
4247 ad_len++;
4248 } else if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
4249 return cap_initiator_pa_data_add(data_array, data_array_size);
4250 }
4251 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
4252
4253 return ad_len;
4254 }
4255