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 "host/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_bap_qos_cfg_pref qos_pref =
623 BT_BAP_QOS_CFG_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_bap_qos_cfg_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_bap_qos_cfg_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_bap_qos_cfg_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_bap_qos_cfg_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_bap_qos_cfg * qos,struct bt_bap_ascs_rsp * rsp)681 static int lc3_qos(struct bt_bap_stream *stream, const struct bt_bap_qos_cfg *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_bap_qos_cfg *snk_qos[BAP_UNICAST_AC_MAX_SNK];
826 struct bt_bap_qos_cfg *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_bap_qos_cfg *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
set_group_param(const struct shell * sh,struct bt_bap_unicast_group_param * group_param,struct bt_bap_unicast_group_stream_pair_param pair_param[ARRAY_SIZE (unicast_streams)],struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE (unicast_streams)])1440 static int set_group_param(
1441 const struct shell *sh, struct bt_bap_unicast_group_param *group_param,
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 {
1445 size_t source_cnt = 0;
1446 size_t sink_cnt = 0;
1447 size_t cnt = 0;
1448
1449 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
1450 struct bt_bap_stream *stream = bap_stream_from_shell_stream(&unicast_streams[i]);
1451 struct shell_stream *uni_stream = &unicast_streams[i];
1452
1453 if (stream->ep != NULL) {
1454 struct bt_bap_unicast_group_stream_param *stream_param;
1455
1456 stream_param = &stream_params[cnt];
1457
1458 stream_param->stream = stream;
1459 if (stream_dir(stream) == BT_AUDIO_DIR_SINK) {
1460 stream_param->qos = &uni_stream->qos;
1461 pair_param[sink_cnt++].tx_param = stream_param;
1462 } else {
1463 stream_param->qos = &uni_stream->qos;
1464 pair_param[source_cnt++].rx_param = stream_param;
1465 }
1466
1467 cnt++;
1468 }
1469 }
1470
1471 if (cnt == 0U) {
1472 shell_error(sh, "Stream cnt is 0");
1473
1474 return -ENOEXEC;
1475 }
1476
1477 group_param->packing = BT_ISO_PACKING_SEQUENTIAL;
1478 group_param->params = pair_param;
1479 group_param->params_count = MAX(source_cnt, sink_cnt);
1480
1481 return 0;
1482 }
1483
create_unicast_group(const struct shell * sh)1484 static int create_unicast_group(const struct shell *sh)
1485 {
1486 struct bt_bap_unicast_group_stream_pair_param pair_param[ARRAY_SIZE(unicast_streams)] = {0};
1487 struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(unicast_streams)] = {0};
1488 struct bt_bap_unicast_group_param group_param = {0};
1489 int err;
1490
1491 err = set_group_param(sh, &group_param, pair_param, stream_params);
1492 if (err != 0) {
1493 return err;
1494 }
1495
1496 err = bt_bap_unicast_group_create(&group_param, &default_unicast_group);
1497 if (err != 0) {
1498 shell_error(sh, "Unable to create default unicast group: %d", err);
1499
1500 return -ENOEXEC;
1501 }
1502
1503 return 0;
1504 }
1505
reconfig_unicast_group(const struct shell * sh)1506 static int reconfig_unicast_group(const struct shell *sh)
1507 {
1508 struct bt_bap_unicast_group_stream_pair_param pair_param[ARRAY_SIZE(unicast_streams)] = {0};
1509 struct bt_bap_unicast_group_stream_param stream_params[ARRAY_SIZE(unicast_streams)] = {0};
1510 struct bt_bap_unicast_group_param group_param = {0};
1511 int err;
1512
1513 err = set_group_param(sh, &group_param, pair_param, stream_params);
1514 if (err != 0) {
1515 return err;
1516 }
1517
1518 err = bt_bap_unicast_group_reconfig(default_unicast_group, &group_param);
1519 if (err != 0) {
1520 shell_error(sh, "Unable to create default unicast group: %d", err);
1521
1522 return -ENOEXEC;
1523 }
1524
1525 return 0;
1526 }
1527
cmd_qos(const struct shell * sh,size_t argc,char * argv[])1528 static int cmd_qos(const struct shell *sh, size_t argc, char *argv[])
1529 {
1530 int err;
1531
1532 if (default_stream == NULL) {
1533 shell_print(sh, "No stream selected");
1534 return -ENOEXEC;
1535 }
1536
1537 if (default_conn == NULL) {
1538 shell_error(sh, "Not connected");
1539 return -ENOEXEC;
1540 }
1541
1542 if (default_unicast_group == NULL) {
1543 err = create_unicast_group(sh);
1544 if (err != 0) {
1545 return err;
1546 }
1547 } else {
1548 err = reconfig_unicast_group(sh);
1549 if (err != 0) {
1550 return err;
1551 }
1552 }
1553
1554 err = bt_bap_stream_qos(default_conn, default_unicast_group);
1555 if (err) {
1556 shell_error(sh, "Unable to setup QoS: %d", err);
1557 return -ENOEXEC;
1558 }
1559
1560 return 0;
1561 }
1562
cmd_enable(const struct shell * sh,size_t argc,char * argv[])1563 static int cmd_enable(const struct shell *sh, size_t argc, char *argv[])
1564 {
1565 struct bt_audio_codec_cfg *codec_cfg;
1566 int err;
1567
1568 if (default_stream == NULL) {
1569 shell_error(sh, "No stream selected");
1570 return -ENOEXEC;
1571 }
1572
1573 codec_cfg = default_stream->codec_cfg;
1574
1575 if (argc > 1) {
1576 err = set_metadata(codec_cfg, argv[1]);
1577 if (err != 0) {
1578 shell_error(sh, "Unable to handle metadata update: %d", err);
1579 return err;
1580 }
1581 }
1582
1583 err = bt_bap_stream_enable(default_stream, codec_cfg->meta, codec_cfg->meta_len);
1584 if (err) {
1585 shell_error(sh, "Unable to enable Channel");
1586 return -ENOEXEC;
1587 }
1588
1589 return 0;
1590 }
1591
cmd_stop(const struct shell * sh,size_t argc,char * argv[])1592 static int cmd_stop(const struct shell *sh, size_t argc, char *argv[])
1593 {
1594 int err;
1595
1596 if (default_stream == NULL) {
1597 shell_error(sh, "No stream selected");
1598 return -ENOEXEC;
1599 }
1600
1601 err = bt_bap_stream_stop(default_stream);
1602 if (err) {
1603 shell_error(sh, "Unable to stop Channel");
1604 return -ENOEXEC;
1605 }
1606
1607 return 0;
1608 }
1609
cmd_connect(const struct shell * sh,size_t argc,char * argv[])1610 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
1611 {
1612 int err;
1613
1614 if (default_stream == NULL) {
1615 shell_error(sh, "No stream selected");
1616 return -ENOEXEC;
1617 }
1618
1619 err = bt_bap_stream_connect(default_stream);
1620 if (err) {
1621 shell_error(sh, "Unable to connect stream");
1622 return -ENOEXEC;
1623 }
1624
1625 return 0;
1626 }
1627 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1628
cmd_metadata(const struct shell * sh,size_t argc,char * argv[])1629 static int cmd_metadata(const struct shell *sh, size_t argc, char *argv[])
1630 {
1631 struct bt_audio_codec_cfg *codec_cfg;
1632 int err;
1633
1634 if (default_stream == NULL) {
1635 shell_error(sh, "No stream selected");
1636 return -ENOEXEC;
1637 }
1638
1639 codec_cfg = default_stream->codec_cfg;
1640
1641 if (argc > 1) {
1642 err = set_metadata(codec_cfg, argv[1]);
1643 if (err != 0) {
1644 shell_error(sh, "Unable to handle metadata update: %d", err);
1645 return err;
1646 }
1647 }
1648
1649 err = bt_bap_stream_metadata(default_stream, codec_cfg->meta, codec_cfg->meta_len);
1650 if (err) {
1651 shell_error(sh, "Unable to set Channel metadata");
1652 return -ENOEXEC;
1653 }
1654
1655 return 0;
1656 }
1657
cmd_start(const struct shell * sh,size_t argc,char * argv[])1658 static int cmd_start(const struct shell *sh, size_t argc, char *argv[])
1659 {
1660 int err;
1661
1662 if (default_stream == NULL) {
1663 shell_error(sh, "No stream selected");
1664 return -ENOEXEC;
1665 }
1666
1667 err = bt_bap_stream_start(default_stream);
1668 if (err) {
1669 shell_error(sh, "Unable to start Channel");
1670 return -ENOEXEC;
1671 }
1672
1673 return 0;
1674 }
1675
cmd_disable(const struct shell * sh,size_t argc,char * argv[])1676 static int cmd_disable(const struct shell *sh, size_t argc, char *argv[])
1677 {
1678 int err;
1679
1680 if (default_stream == NULL) {
1681 shell_error(sh, "No stream selected");
1682 return -ENOEXEC;
1683 }
1684
1685 err = bt_bap_stream_disable(default_stream);
1686 if (err) {
1687 shell_error(sh, "Unable to disable Channel");
1688 return -ENOEXEC;
1689 }
1690
1691 return 0;
1692 }
1693
1694 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
conn_list_eps(struct bt_conn * conn,void * data)1695 static void conn_list_eps(struct bt_conn *conn, void *data)
1696 {
1697 const struct shell *sh = (const struct shell *)data;
1698 uint8_t conn_index = bt_conn_index(conn);
1699
1700 shell_print(sh, "Conn: %p", conn);
1701 shell_print(sh, " Sinks:");
1702
1703 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0
1704 for (size_t i = 0U; i < ARRAY_SIZE(snks[conn_index]); i++) {
1705 const struct bt_bap_ep *ep = snks[conn_index][i];
1706
1707 if (ep != NULL) {
1708 struct bt_bap_ep_info ep_info;
1709 int err;
1710
1711 err = bt_bap_ep_get_info(ep, &ep_info);
1712 if (err == 0) {
1713 shell_print(sh, " #%u: ep %p (state: %d)", i, ep, ep_info.state);
1714 }
1715 }
1716 }
1717 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SNK_COUNT > 0 */
1718
1719 #if CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0
1720 shell_print(sh, " Sources:");
1721
1722 for (size_t i = 0U; i < ARRAY_SIZE(srcs[conn_index]); i++) {
1723 const struct bt_bap_ep *ep = srcs[conn_index][i];
1724
1725 if (ep != NULL) {
1726 struct bt_bap_ep_info ep_info;
1727 int err;
1728
1729 err = bt_bap_ep_get_info(ep, &ep_info);
1730 if (err == 0) {
1731 shell_print(sh, " #%u: ep %p (state: %d)", i, ep, ep_info.state);
1732 }
1733 }
1734 }
1735 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT > 0 */
1736 }
1737 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1738
1739 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
cmd_list(const struct shell * sh,size_t argc,char * argv[])1740 static int cmd_list(const struct shell *sh, size_t argc, char *argv[])
1741 {
1742 shell_print(sh, "Configured Channels:");
1743
1744 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
1745 struct bt_bap_stream *stream = &unicast_streams[i].stream.bap_stream;
1746
1747 if (stream != NULL && stream->conn != NULL) {
1748 shell_print(sh, " %s#%u: stream %p dir 0x%02x group %p",
1749 stream == default_stream ? "*" : " ", i, stream,
1750 stream_dir(stream), stream->group);
1751 }
1752 }
1753
1754 bt_conn_foreach(BT_CONN_TYPE_LE, conn_list_eps, (void *)sh);
1755
1756 return 0;
1757 }
1758 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
1759
cmd_release(const struct shell * sh,size_t argc,char * argv[])1760 static int cmd_release(const struct shell *sh, size_t argc, char *argv[])
1761 {
1762 int err;
1763
1764 if (default_stream == NULL) {
1765 shell_print(sh, "No stream selected");
1766 return -ENOEXEC;
1767 }
1768
1769 err = bt_bap_stream_release(default_stream);
1770 if (err) {
1771 shell_error(sh, "Unable to release Channel");
1772 return -ENOEXEC;
1773 }
1774
1775 return 0;
1776 }
1777 #endif /* CONFIG_BT_BAP_UNICAST */
1778
1779 #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)1780 static ssize_t parse_config_data_args(const struct shell *sh, size_t argn, size_t argc,
1781 char *argv[], struct bt_audio_codec_cfg *codec_cfg)
1782 {
1783 for (; argn < argc; argn++) {
1784 const char *arg = argv[argn];
1785 unsigned long val;
1786 int err = 0;
1787
1788 if (strcmp(arg, "freq") == 0) {
1789 if (++argn == argc) {
1790 shell_help(sh);
1791
1792 return -1;
1793 }
1794
1795 arg = argv[argn];
1796
1797 val = shell_strtoul(arg, 0, &err);
1798 if (err != 0) {
1799 shell_error(sh, "Failed to parse freq from %s: %d", arg, err);
1800
1801 return -1;
1802 }
1803
1804 if (val > UINT8_MAX) {
1805 shell_error(sh, "Invalid freq value: %lu", val);
1806
1807 return -1;
1808 }
1809
1810 err = bt_audio_codec_cfg_set_freq(codec_cfg,
1811 (enum bt_audio_codec_cfg_freq)val);
1812 if (err < 0) {
1813 shell_error(sh, "Failed to set freq with value %lu: %d", val, err);
1814
1815 return -1;
1816 }
1817 } else if (strcmp(arg, "dur") == 0) {
1818 if (++argn == argc) {
1819 shell_help(sh);
1820
1821 return -1;
1822 }
1823
1824 arg = argv[argn];
1825
1826 val = shell_strtoul(arg, 0, &err);
1827 if (err != 0) {
1828 shell_error(sh, "Failed to parse dur from %s: %d", arg, err);
1829
1830 return -1;
1831 }
1832
1833 if (val > UINT8_MAX) {
1834 shell_error(sh, "Invalid dur value: %lu", val);
1835
1836 return -1;
1837 }
1838
1839 err = bt_audio_codec_cfg_set_frame_dur(
1840 codec_cfg, (enum bt_audio_codec_cfg_frame_dur)val);
1841 if (err < 0) {
1842 shell_error(sh, "Failed to set dur with value %lu: %d", val, err);
1843
1844 return -1;
1845 }
1846 } else if (strcmp(arg, "chan_alloc") == 0) {
1847 if (++argn == argc) {
1848 shell_help(sh);
1849
1850 return -1;
1851 }
1852
1853 arg = argv[argn];
1854
1855 val = shell_strtoul(arg, 0, &err);
1856 if (err != 0) {
1857 shell_error(sh, "Failed to parse chan alloc from %s: %d", arg, err);
1858
1859 return -1;
1860 }
1861
1862 if (val > UINT32_MAX) {
1863 shell_error(sh, "Invalid chan alloc value: %lu", val);
1864
1865 return -1;
1866 }
1867
1868 err = bt_audio_codec_cfg_set_chan_allocation(codec_cfg,
1869 (enum bt_audio_location)val);
1870 if (err < 0) {
1871 shell_error(sh, "Failed to set chan alloc with value %lu: %d", val,
1872 err);
1873
1874 return -1;
1875 }
1876 } else if (strcmp(arg, "frame_len") == 0) {
1877 if (++argn == argc) {
1878 shell_help(sh);
1879
1880 return -1;
1881 }
1882
1883 arg = argv[argn];
1884
1885 val = shell_strtoul(arg, 0, &err);
1886 if (err != 0) {
1887 shell_error(sh, "Failed to frame len from %s: %d", arg, err);
1888
1889 return -1;
1890 }
1891
1892 if (val > UINT16_MAX) {
1893 shell_error(sh, "Invalid frame len value: %lu", val);
1894
1895 return -1;
1896 }
1897
1898 err = bt_audio_codec_cfg_set_octets_per_frame(codec_cfg, (uint16_t)val);
1899 if (err < 0) {
1900 shell_error(sh, "Failed to set frame len with value %lu: %d", val,
1901 err);
1902
1903 return -1;
1904 }
1905 } else if (strcmp(arg, "frame_blks") == 0) {
1906 if (++argn == argc) {
1907 shell_help(sh);
1908
1909 return -1;
1910 }
1911
1912 arg = argv[argn];
1913
1914 val = shell_strtoul(arg, 0, &err);
1915 if (err != 0) {
1916 shell_error(sh, "Failed to parse frame blks from %s: %d", arg, err);
1917
1918 return -1;
1919 }
1920
1921 if (val > UINT8_MAX) {
1922 shell_error(sh, "Invalid frame blks value: %lu", val);
1923
1924 return -1;
1925 }
1926
1927 err = bt_audio_codec_cfg_set_frame_blocks_per_sdu(codec_cfg, (uint8_t)val);
1928 if (err < 0) {
1929 shell_error(sh, "Failed to set frame blks with value %lu: %d", val,
1930 err);
1931
1932 return -1;
1933 }
1934 } else { /* we are no longer parsing codec config values */
1935 /* Decrement to return taken argument */
1936 argn--;
1937 break;
1938 }
1939 }
1940
1941 return argn;
1942 }
1943
parse_config_meta_args(const struct shell * sh,size_t argn,size_t argc,char * argv[],struct bt_audio_codec_cfg * codec_cfg)1944 static ssize_t parse_config_meta_args(const struct shell *sh, size_t argn, size_t argc,
1945 char *argv[], struct bt_audio_codec_cfg *codec_cfg)
1946 {
1947 for (; argn < argc; argn++) {
1948 const char *arg = argv[argn];
1949 unsigned long val;
1950 int err = 0;
1951
1952 if (strcmp(arg, "pref_ctx") == 0) {
1953 if (++argn == argc) {
1954 shell_help(sh);
1955
1956 return -1;
1957 }
1958
1959 arg = argv[argn];
1960
1961 val = shell_strtoul(arg, 0, &err);
1962 if (err != 0) {
1963 shell_error(sh, "Failed to parse pref ctx from %s: %d", arg, err);
1964
1965 return -1;
1966 }
1967
1968 if (val > UINT16_MAX) {
1969 shell_error(sh, "Invalid pref ctx value: %lu", val);
1970
1971 return -1;
1972 }
1973
1974 err = bt_audio_codec_cfg_meta_set_pref_context(codec_cfg,
1975 (enum bt_audio_context)val);
1976 if (err < 0) {
1977 shell_error(sh, "Failed to set pref ctx with value %lu: %d", val,
1978 err);
1979
1980 return -1;
1981 }
1982 } else if (strcmp(arg, "stream_ctx") == 0) {
1983 if (++argn == argc) {
1984 shell_help(sh);
1985
1986 return -1;
1987 }
1988
1989 arg = argv[argn];
1990
1991 val = shell_strtoul(arg, 0, &err);
1992 if (err != 0) {
1993 shell_error(sh, "Failed to parse stream ctx from %s: %d", arg, err);
1994
1995 return -1;
1996 }
1997
1998 if (val > UINT16_MAX) {
1999 shell_error(sh, "Invalid stream ctx value: %lu", val);
2000
2001 return -1;
2002 }
2003
2004 err = bt_audio_codec_cfg_meta_set_stream_context(
2005 codec_cfg, (enum bt_audio_context)val);
2006 if (err < 0) {
2007 shell_error(sh, "Failed to set stream ctx with value %lu: %d", val,
2008 err);
2009
2010 return -1;
2011 }
2012 } else if (strcmp(arg, "program_info") == 0) {
2013 if (++argn == argc) {
2014 shell_help(sh);
2015
2016 return -1;
2017 }
2018
2019 arg = argv[argn];
2020
2021 err = bt_audio_codec_cfg_meta_set_program_info(codec_cfg, arg, strlen(arg));
2022 if (err != 0) {
2023 shell_error(sh, "Failed to set program info with value %s: %d", arg,
2024 err);
2025
2026 return -1;
2027 }
2028 } else if (strcmp(arg, "lang") == 0) {
2029 if (++argn == argc) {
2030 shell_help(sh);
2031
2032 return -1;
2033 }
2034
2035 arg = argv[argn];
2036
2037 if (strlen(arg) != BT_AUDIO_LANG_SIZE) {
2038 shell_error(sh, "Failed to parse lang from %s", arg);
2039
2040 return -1;
2041 }
2042
2043 err = bt_audio_codec_cfg_meta_set_lang(codec_cfg, arg);
2044 if (err < 0) {
2045 shell_error(sh, "Failed to set lang with value %s: %d", arg, err);
2046
2047 return -1;
2048 }
2049 } else if (strcmp(arg, "ccid_list") == 0) {
2050 uint8_t ccid_list[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2051 size_t ccid_list_len;
2052
2053 if (++argn == argc) {
2054 shell_help(sh);
2055
2056 return -1;
2057 }
2058
2059 arg = argv[argn];
2060
2061 ccid_list_len = hex2bin(arg, strlen(arg), ccid_list, sizeof(ccid_list));
2062 if (ccid_list_len == 0) {
2063 shell_error(sh, "Failed to parse ccid list from %s", arg);
2064
2065 return -1;
2066 }
2067
2068 err = bt_audio_codec_cfg_meta_set_ccid_list(codec_cfg, ccid_list,
2069 ccid_list_len);
2070 if (err < 0) {
2071 shell_error(sh, "Failed to set ccid list with value %s: %d", arg,
2072 err);
2073
2074 return -1;
2075 }
2076 } else if (strcmp(arg, "parental_rating") == 0) {
2077 if (++argn == argc) {
2078 shell_help(sh);
2079
2080 return -1;
2081 }
2082
2083 arg = argv[argn];
2084
2085 val = shell_strtoul(arg, 0, &err);
2086 if (err != 0) {
2087 shell_error(sh, "Failed to parse parental rating from %s: %d", arg,
2088 err);
2089
2090 return -1;
2091 }
2092
2093 if (val > UINT8_MAX) {
2094 shell_error(sh, "Invalid parental rating value: %lu", val);
2095
2096 return -1;
2097 }
2098
2099 err = bt_audio_codec_cfg_meta_set_parental_rating(
2100 codec_cfg, (enum bt_audio_parental_rating)val);
2101 if (err < 0) {
2102 shell_error(sh, "Failed to set parental rating with value %lu: %d",
2103 val, err);
2104
2105 return -1;
2106 }
2107 } else if (strcmp(arg, "program_info_uri") == 0) {
2108 if (++argn == argc) {
2109 shell_help(sh);
2110
2111 return -1;
2112 }
2113
2114 arg = argv[argn];
2115
2116 err = bt_audio_codec_cfg_meta_set_program_info_uri(codec_cfg, arg,
2117 strlen(arg));
2118 if (err < 0) {
2119 shell_error(sh, "Failed to set program info URI with value %s: %d",
2120 arg, err);
2121
2122 return -1;
2123 }
2124 } else if (strcmp(arg, "audio_active_state") == 0) {
2125 if (++argn == argc) {
2126 shell_help(sh);
2127
2128 return -1;
2129 }
2130
2131 arg = argv[argn];
2132
2133 val = shell_strtoul(arg, 0, &err);
2134 if (err != 0) {
2135 shell_error(sh, "Failed to parse audio active state from %s: %d",
2136 arg, err);
2137
2138 return -1;
2139 }
2140
2141 if (val > UINT8_MAX) {
2142 shell_error(sh, "Invalid audio active state value: %lu", val);
2143
2144 return -1;
2145 }
2146
2147 err = bt_audio_codec_cfg_meta_set_audio_active_state(
2148 codec_cfg, (enum bt_audio_active_state)val);
2149 if (err < 0) {
2150 shell_error(sh,
2151 "Failed to set audio active state with value %lu: %d",
2152 val, err);
2153
2154 return -1;
2155 }
2156 } else if (strcmp(arg, "bcast_flag") == 0) {
2157 err = bt_audio_codec_cfg_meta_set_bcast_audio_immediate_rend_flag(
2158 codec_cfg);
2159 if (err < 0) {
2160 shell_error(sh, "Failed to set audio active state: %d", err);
2161
2162 return -1;
2163 }
2164 } else if (strcmp(arg, "extended") == 0) {
2165 uint8_t extended[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2166 size_t extended_len;
2167
2168 if (++argn == argc) {
2169 shell_help(sh);
2170
2171 return -1;
2172 }
2173
2174 arg = argv[argn];
2175
2176 extended_len = hex2bin(arg, strlen(arg), extended, sizeof(extended));
2177 if (extended_len == 0) {
2178 shell_error(sh, "Failed to parse extended meta from %s", arg);
2179
2180 return -1;
2181 }
2182
2183 err = bt_audio_codec_cfg_meta_set_extended(codec_cfg, extended,
2184 extended_len);
2185 if (err < 0) {
2186 shell_error(sh, "Failed to set extended meta with value %s: %d",
2187 arg, err);
2188
2189 return -1;
2190 }
2191 } else if (strcmp(arg, "vendor") == 0) {
2192 uint8_t vendor[CONFIG_BT_AUDIO_CODEC_CFG_MAX_DATA_SIZE];
2193 size_t vendor_len;
2194
2195 if (++argn == argc) {
2196 shell_help(sh);
2197
2198 return -1;
2199 }
2200
2201 arg = argv[argn];
2202
2203 vendor_len = hex2bin(arg, strlen(arg), vendor, sizeof(vendor));
2204 if (vendor_len == 0) {
2205 shell_error(sh, "Failed to parse vendor meta from %s", arg);
2206
2207 return -1;
2208 }
2209
2210 err = bt_audio_codec_cfg_meta_set_vendor(codec_cfg, vendor, vendor_len);
2211 if (err < 0) {
2212 shell_error(sh, "Failed to set vendor meta with value %s: %d", arg,
2213 err);
2214
2215 return -1;
2216 }
2217 } else { /* we are no longer parsing codec config meta values */
2218 /* Decrement to return taken argument */
2219 argn--;
2220 break;
2221 }
2222 }
2223
2224 return argn;
2225 }
2226
cmd_preset(const struct shell * sh,size_t argc,char * argv[])2227 static int cmd_preset(const struct shell *sh, size_t argc, char *argv[])
2228 {
2229 const struct named_lc3_preset *named_preset;
2230 enum bt_audio_dir dir;
2231 bool unicast = true;
2232
2233 if (!strcmp(argv[1], "sink")) {
2234 dir = BT_AUDIO_DIR_SINK;
2235 named_preset = &default_sink_preset;
2236 } else if (!strcmp(argv[1], "source")) {
2237 dir = BT_AUDIO_DIR_SOURCE;
2238 named_preset = &default_source_preset;
2239 } else if (!strcmp(argv[1], "broadcast")) {
2240 unicast = false;
2241 dir = BT_AUDIO_DIR_SOURCE;
2242
2243 named_preset = &default_broadcast_source_preset;
2244 } else {
2245 shell_error(sh, "Unsupported dir: %s", argv[1]);
2246 return -ENOEXEC;
2247 }
2248
2249 if (argc > 2) {
2250 struct bt_audio_codec_cfg *codec_cfg;
2251
2252 named_preset = bap_get_named_preset(unicast, dir, argv[2]);
2253 if (named_preset == NULL) {
2254 shell_error(sh, "Unable to parse named_preset %s", argv[2]);
2255 return -ENOEXEC;
2256 }
2257
2258 if (!strcmp(argv[1], "sink")) {
2259 named_preset = memcpy(&default_sink_preset, named_preset,
2260 sizeof(default_sink_preset));
2261 codec_cfg = &default_sink_preset.preset.codec_cfg;
2262 } else if (!strcmp(argv[1], "source")) {
2263 named_preset = memcpy(&default_source_preset, named_preset,
2264 sizeof(default_sink_preset));
2265 codec_cfg = &default_source_preset.preset.codec_cfg;
2266 } else if (!strcmp(argv[1], "broadcast")) {
2267 named_preset = memcpy(&default_broadcast_source_preset, named_preset,
2268 sizeof(default_sink_preset));
2269 codec_cfg = &default_broadcast_source_preset.preset.codec_cfg;
2270 } else {
2271 shell_error(sh, "Invalid dir: %s", argv[1]);
2272
2273 return -ENOEXEC;
2274 }
2275
2276 if (argc > 3) {
2277 struct bt_audio_codec_cfg codec_cfg_backup;
2278
2279 memcpy(&codec_cfg_backup, codec_cfg, sizeof(codec_cfg_backup));
2280
2281 for (size_t argn = 3; argn < argc; argn++) {
2282 const char *arg = argv[argn];
2283
2284 if (strcmp(arg, "config") == 0) {
2285 ssize_t ret;
2286
2287 if (++argn == argc) {
2288 shell_help(sh);
2289
2290 memcpy(codec_cfg, &codec_cfg_backup,
2291 sizeof(codec_cfg_backup));
2292
2293 return SHELL_CMD_HELP_PRINTED;
2294 }
2295
2296 ret = parse_config_data_args(sh, argn, argc, argv,
2297 codec_cfg);
2298 if (ret < 0) {
2299 memcpy(codec_cfg, &codec_cfg_backup,
2300 sizeof(codec_cfg_backup));
2301
2302 return -ENOEXEC;
2303 }
2304
2305 argn = ret;
2306 } else if (strcmp(arg, "meta") == 0) {
2307 ssize_t ret;
2308
2309 if (++argn == argc) {
2310 shell_help(sh);
2311
2312 memcpy(codec_cfg, &codec_cfg_backup,
2313 sizeof(codec_cfg_backup));
2314
2315 return SHELL_CMD_HELP_PRINTED;
2316 }
2317
2318 ret = parse_config_meta_args(sh, argn, argc, argv,
2319 codec_cfg);
2320 if (ret < 0) {
2321 memcpy(codec_cfg, &codec_cfg_backup,
2322 sizeof(codec_cfg_backup));
2323
2324 return -ENOEXEC;
2325 }
2326
2327 argn = ret;
2328 } else {
2329 shell_error(sh, "Invalid argument: %s", arg);
2330 shell_help(sh);
2331
2332 return -ENOEXEC;
2333 }
2334 }
2335 }
2336 }
2337
2338 shell_print(sh, "%s", named_preset->name);
2339
2340 print_codec_cfg(ctx_shell, 0, &named_preset->preset.codec_cfg);
2341 print_qos(ctx_shell, &named_preset->preset.qos);
2342
2343 return 0;
2344 }
2345 #endif /* IS_BAP_INITIATOR */
2346
2347 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
2348 #define PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO 20 /* Set the timeout relative to interval */
2349 #define PA_SYNC_SKIP 5
2350
2351 struct bt_broadcast_info {
2352 uint32_t broadcast_id;
2353 char broadcast_name[BT_AUDIO_BROADCAST_NAME_LEN_MAX + 1];
2354 };
2355
2356 static struct broadcast_sink_auto_scan {
2357 struct broadcast_sink *broadcast_sink;
2358 struct bt_broadcast_info broadcast_info;
2359 struct bt_le_per_adv_sync **out_sync;
2360 } auto_scan = {
2361 .broadcast_info = {
2362 .broadcast_id = BT_BAP_INVALID_BROADCAST_ID,
2363 },
2364 };
2365
clear_auto_scan(void)2366 static void clear_auto_scan(void)
2367 {
2368 memset(&auto_scan, 0, sizeof(auto_scan));
2369 auto_scan.broadcast_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
2370 }
2371
interval_to_sync_timeout(uint16_t interval)2372 static uint16_t interval_to_sync_timeout(uint16_t interval)
2373 {
2374 uint32_t interval_us;
2375 uint32_t timeout;
2376
2377 /* Add retries and convert to unit in 10's of ms */
2378 interval_us = BT_GAP_PER_ADV_INTERVAL_TO_US(interval);
2379 timeout =
2380 BT_GAP_US_TO_PER_ADV_SYNC_TIMEOUT(interval_us) * PA_SYNC_INTERVAL_TO_TIMEOUT_RATIO;
2381
2382 /* Enforce restraints */
2383 timeout = CLAMP(timeout, BT_GAP_PER_ADV_MIN_TIMEOUT, BT_GAP_PER_ADV_MAX_TIMEOUT);
2384
2385 return (uint16_t)timeout;
2386 }
2387
scan_check_and_sync_broadcast(struct bt_data * data,void * user_data)2388 static bool scan_check_and_sync_broadcast(struct bt_data *data, void *user_data)
2389 {
2390 struct bt_broadcast_info *sr_info = (struct bt_broadcast_info *)user_data;
2391 struct bt_uuid_16 adv_uuid;
2392
2393 switch (data->type) {
2394 case BT_DATA_SVC_DATA16:
2395 if (data->data_len < BT_UUID_SIZE_16 + BT_AUDIO_BROADCAST_ID_SIZE) {
2396 return true;
2397 }
2398
2399 if (!bt_uuid_create(&adv_uuid.uuid, data->data, BT_UUID_SIZE_16)) {
2400 return true;
2401 }
2402
2403 if (bt_uuid_cmp(&adv_uuid.uuid, BT_UUID_BROADCAST_AUDIO) != 0) {
2404 return true;
2405 }
2406
2407 sr_info->broadcast_id = sys_get_le24(data->data + BT_UUID_SIZE_16);
2408 return true;
2409 case BT_DATA_BROADCAST_NAME:
2410 if (!IN_RANGE(data->data_len, BT_AUDIO_BROADCAST_NAME_LEN_MIN,
2411 BT_AUDIO_BROADCAST_NAME_LEN_MAX)) {
2412 return false;
2413 }
2414
2415 memcpy(sr_info->broadcast_name, data->data, data->data_len);
2416 sr_info->broadcast_name[data->data_len] = '\0';
2417 return true;
2418 default:
2419 return true;
2420 }
2421 }
2422
broadcast_scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)2423 static void broadcast_scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
2424 {
2425 struct bt_broadcast_info sr_info = {0};
2426 char addr_str[BT_ADDR_LE_STR_LEN];
2427 bool identified_broadcast = false;
2428
2429 sr_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
2430
2431 if ((auto_scan.broadcast_info.broadcast_id == BT_BAP_INVALID_BROADCAST_ID) &&
2432 (strlen(auto_scan.broadcast_info.broadcast_name) == 0U)) {
2433 /* no op */
2434 return;
2435 }
2436
2437 if (!passes_scan_filter(info, ad)) {
2438 return;
2439 }
2440
2441 bt_data_parse(ad, scan_check_and_sync_broadcast, (void *)&sr_info);
2442
2443 /* Verify that it is a BAP broadcaster*/
2444 if (sr_info.broadcast_id == BT_BAP_INVALID_BROADCAST_ID) {
2445 return;
2446 }
2447
2448 bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
2449
2450 if (sr_info.broadcast_id == auto_scan.broadcast_info.broadcast_id) {
2451 identified_broadcast = true;
2452 } else if ((strlen(auto_scan.broadcast_info.broadcast_name) != 0U) &&
2453 is_substring(auto_scan.broadcast_info.broadcast_name, sr_info.broadcast_name)) {
2454 auto_scan.broadcast_info.broadcast_id = sr_info.broadcast_id;
2455 identified_broadcast = true;
2456
2457 shell_print(ctx_shell, "Found matched broadcast name '%s' with address %s",
2458 sr_info.broadcast_name, addr_str);
2459 }
2460
2461 if (identified_broadcast && (auto_scan.broadcast_sink != NULL) &&
2462 (auto_scan.broadcast_sink->pa_sync == NULL)) {
2463 struct bt_le_per_adv_sync_param create_params = {0};
2464 int err;
2465
2466 shell_print(ctx_shell,
2467 "Found broadcaster with ID 0x%06X and addr %s and sid 0x%02X ",
2468 sr_info.broadcast_id, addr_str, info->sid);
2469
2470 err = bt_le_scan_stop();
2471 if (err != 0) {
2472 shell_error(ctx_shell, "Could not stop scan: %d", err);
2473 }
2474
2475 bt_addr_le_copy(&create_params.addr, info->addr);
2476 create_params.options = BT_LE_PER_ADV_SYNC_OPT_FILTER_DUPLICATE;
2477 create_params.sid = info->sid;
2478 create_params.skip = PA_SYNC_SKIP;
2479 create_params.timeout = interval_to_sync_timeout(info->interval);
2480
2481 shell_print(ctx_shell, "Attempting to PA sync to the broadcaster");
2482 err = bt_le_per_adv_sync_create(&create_params, auto_scan.out_sync);
2483 if (err != 0) {
2484 shell_error(ctx_shell, "Could not create Broadcast PA sync: %d", err);
2485 } else {
2486 auto_scan.broadcast_sink->pa_sync = *auto_scan.out_sync;
2487 }
2488 }
2489 }
2490
base_recv(struct bt_bap_broadcast_sink * sink,const struct bt_bap_base * base,size_t base_size)2491 static void base_recv(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base,
2492 size_t base_size)
2493 {
2494 /* Don't print duplicates */
2495 if (base_size != default_broadcast_sink.base_size ||
2496 memcmp(base, &default_broadcast_sink.received_base, base_size) != 0) {
2497 shell_print(ctx_shell, "Received BASE from sink %p:", sink);
2498 (void)memcpy(&default_broadcast_sink.received_base, base, base_size);
2499 default_broadcast_sink.base_size = base_size;
2500
2501 print_base(base);
2502 }
2503 }
2504
syncable(struct bt_bap_broadcast_sink * sink,const struct bt_iso_biginfo * biginfo)2505 static void syncable(struct bt_bap_broadcast_sink *sink, const struct bt_iso_biginfo *biginfo)
2506 {
2507 if (default_broadcast_sink.bap_sink == sink) {
2508 if (default_broadcast_sink.syncable) {
2509 return;
2510 }
2511
2512 shell_print(ctx_shell, "Sink %p is ready to sync %s encryption", sink,
2513 biginfo->encryption ? "with" : "without");
2514 default_broadcast_sink.syncable = true;
2515 }
2516 }
2517
bap_pa_sync_synced_cb(struct bt_le_per_adv_sync * sync,struct bt_le_per_adv_sync_synced_info * info)2518 static void bap_pa_sync_synced_cb(struct bt_le_per_adv_sync *sync,
2519 struct bt_le_per_adv_sync_synced_info *info)
2520 {
2521 if (auto_scan.broadcast_sink != NULL && auto_scan.out_sync != NULL &&
2522 sync == *auto_scan.out_sync) {
2523 shell_print(ctx_shell, "PA synced to broadcast with broadcast ID 0x%06x",
2524 auto_scan.broadcast_info.broadcast_id);
2525
2526 if (auto_scan.broadcast_sink->bap_sink == NULL) {
2527 shell_print(ctx_shell, "Attempting to create the sink");
2528 int err;
2529
2530 err = bt_bap_broadcast_sink_create(sync,
2531 auto_scan.broadcast_info.broadcast_id,
2532 &auto_scan.broadcast_sink->bap_sink);
2533 if (err != 0) {
2534 shell_error(ctx_shell, "Could not create broadcast sink: %d", err);
2535 }
2536 } else {
2537 shell_print(ctx_shell, "Sink is already created");
2538 }
2539 }
2540
2541 clear_auto_scan();
2542 }
2543
bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync * sync,const struct bt_le_per_adv_sync_term_info * info)2544 static void bap_pa_sync_terminated_cb(struct bt_le_per_adv_sync *sync,
2545 const struct bt_le_per_adv_sync_term_info *info)
2546 {
2547 if (default_broadcast_sink.pa_sync == sync) {
2548 default_broadcast_sink.syncable = false;
2549 (void)memset(&default_broadcast_sink.received_base, 0,
2550 sizeof(default_broadcast_sink.received_base));
2551 }
2552
2553 clear_auto_scan();
2554 }
2555
broadcast_scan_timeout_cb(void)2556 static void broadcast_scan_timeout_cb(void)
2557 {
2558 shell_print(ctx_shell, "Scan timeout");
2559
2560 clear_auto_scan();
2561 }
2562
2563 static struct bt_bap_broadcast_sink_cb sink_cbs = {
2564 .base_recv = base_recv,
2565 .syncable = syncable,
2566 };
2567
2568 static struct bt_le_per_adv_sync_cb bap_pa_sync_cb = {
2569 .synced = bap_pa_sync_synced_cb,
2570 .term = bap_pa_sync_terminated_cb,
2571 };
2572
2573 static struct bt_le_scan_cb bap_scan_cb = {
2574 .timeout = broadcast_scan_timeout_cb,
2575 .recv = broadcast_scan_recv,
2576 };
2577 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
2578
2579 #if defined(CONFIG_BT_AUDIO_RX)
2580 static size_t rx_streaming_cnt;
2581
bap_get_rx_streaming_cnt(void)2582 size_t bap_get_rx_streaming_cnt(void)
2583 {
2584 return rx_streaming_cnt;
2585 }
2586
2587 #if defined(CONFIG_LIBLC3)
2588 struct lc3_data {
2589 void *fifo_reserved; /* 1st word reserved for use by FIFO */
2590 struct net_buf *buf;
2591 struct shell_stream *sh_stream;
2592 uint32_t ts;
2593 bool do_plc;
2594 };
2595
2596 K_MEM_SLAB_DEFINE(lc3_data_slab, sizeof(struct lc3_data), CONFIG_BT_ISO_RX_BUF_COUNT,
2597 __alignof__(struct lc3_data));
2598
2599 static int16_t lc3_rx_buf[LC3_MAX_NUM_SAMPLES_MONO];
2600 static K_FIFO_DEFINE(lc3_in_fifo);
2601
2602 /* We only want to send USB to left/right from a single stream. If we have 2 left streams, the
2603 * outgoing audio is going to be terrible.
2604 * Since a stream can contain stereo data, both of these may be the same stream.
2605 */
2606 static struct shell_stream *usb_left_stream;
2607 static struct shell_stream *usb_right_stream;
2608
init_lc3_decoder(struct shell_stream * sh_stream)2609 static int init_lc3_decoder(struct shell_stream *sh_stream)
2610 {
2611 if (sh_stream == NULL) {
2612 shell_error(ctx_shell, "NULL stream to init LC3 decoder");
2613 return -EINVAL;
2614 }
2615
2616 if (!sh_stream->is_rx) {
2617 shell_error(ctx_shell, "Invalid stream to init LC3 decoder");
2618 return -EINVAL;
2619 }
2620
2621 if (sh_stream->rx.lc3_decoder != NULL) {
2622 shell_error(ctx_shell, "Already initialized");
2623 return -EALREADY;
2624 }
2625
2626 if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) {
2627 shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)",
2628 sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us);
2629
2630 return -EINVAL;
2631 }
2632
2633 shell_print(ctx_shell,
2634 "Initializing the LC3 decoder with %u us duration and %u Hz frequency",
2635 sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz);
2636 /* Create the decoder instance. This shall complete before stream_started() is called. */
2637 sh_stream->rx.lc3_decoder =
2638 lc3_setup_decoder(sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz,
2639 IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE : 0,
2640 &sh_stream->rx.lc3_decoder_mem);
2641 if (sh_stream->rx.lc3_decoder == NULL) {
2642 shell_error(ctx_shell, "Failed to setup LC3 decoder - wrong parameters?\n");
2643 return -EINVAL;
2644 }
2645
2646 return 0;
2647 }
2648
decode_frame(struct lc3_data * data,size_t frame_cnt)2649 static bool decode_frame(struct lc3_data *data, size_t frame_cnt)
2650 {
2651 const struct shell_stream *sh_stream = data->sh_stream;
2652 const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu;
2653 const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame;
2654 struct net_buf *buf = data->buf;
2655 void *iso_data;
2656 int err;
2657
2658 if (data->do_plc) {
2659 iso_data = NULL; /* perform PLC */
2660
2661 if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) {
2662 shell_print(ctx_shell, "[%zu]: Performing PLC", sh_stream->rx.decoded_cnt);
2663 }
2664
2665 data->do_plc = false; /* clear flag */
2666 } else {
2667 iso_data = net_buf_pull_mem(data->buf, octets_per_frame);
2668
2669 if ((sh_stream->rx.decoded_cnt % bap_stats_interval) == 0) {
2670 shell_print(ctx_shell, "[%zu]: Decoding frame of size %u (%u/%u)",
2671 sh_stream->rx.decoded_cnt, octets_per_frame, frame_cnt + 1,
2672 total_frames);
2673 }
2674 }
2675
2676 err = lc3_decode(sh_stream->rx.lc3_decoder, iso_data, octets_per_frame, LC3_PCM_FORMAT_S16,
2677 lc3_rx_buf, 1);
2678 if (err < 0) {
2679 shell_error(ctx_shell, "Failed to decode LC3 data (%u/%u - %u/%u)", frame_cnt + 1,
2680 total_frames, octets_per_frame * frame_cnt, buf->len);
2681 return false;
2682 }
2683
2684 return true;
2685 }
2686
decode_frame_block(struct lc3_data * data,size_t frame_cnt)2687 static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt)
2688 {
2689 const struct shell_stream *sh_stream = data->sh_stream;
2690 const uint8_t chan_cnt = sh_stream->lc3_chan_cnt;
2691 size_t decoded_frames = 0U;
2692
2693 for (uint8_t i = 0U; i < chan_cnt; i++) {
2694 /* We provide the total number of decoded frames to `decode_frame` for logging
2695 * purposes
2696 */
2697 if (decode_frame(data, frame_cnt + decoded_frames)) {
2698 decoded_frames++;
2699
2700 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2701 enum bt_audio_location chan_alloc;
2702 int err;
2703
2704 err = get_lc3_chan_alloc_from_index(sh_stream, i, &chan_alloc);
2705 if (err != 0) {
2706 /* Not suitable for USB */
2707 continue;
2708 }
2709
2710 /* We only want to left or right from one stream to USB */
2711 if ((chan_alloc == BT_AUDIO_LOCATION_FRONT_LEFT &&
2712 sh_stream != usb_left_stream) ||
2713 (chan_alloc == BT_AUDIO_LOCATION_FRONT_RIGHT &&
2714 sh_stream != usb_right_stream)) {
2715 continue;
2716 }
2717
2718 err = bap_usb_add_frame_to_usb(chan_alloc, lc3_rx_buf,
2719 sizeof(lc3_rx_buf), data->ts);
2720 if (err == -EINVAL) {
2721 continue;
2722 }
2723 }
2724 } else {
2725 /* If decoding failed, we clear the data to USB as it would contain
2726 * invalid data
2727 */
2728 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
2729 bap_usb_clear_frames_to_usb();
2730 }
2731
2732 break;
2733 }
2734 }
2735
2736 return decoded_frames;
2737 }
2738
do_lc3_decode(struct lc3_data * data)2739 static void do_lc3_decode(struct lc3_data *data)
2740 {
2741 struct shell_stream *sh_stream = data->sh_stream;
2742
2743 if (sh_stream->is_rx && sh_stream->rx.lc3_decoder != NULL) {
2744 const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu;
2745 size_t frame_cnt;
2746
2747 frame_cnt = 0;
2748 for (uint8_t i = 0U; i < frame_blocks_per_sdu; i++) {
2749 const size_t decoded_frames = decode_frame_block(data, frame_cnt);
2750
2751 if (decoded_frames == 0) {
2752 break;
2753 }
2754
2755 frame_cnt += decoded_frames;
2756 }
2757
2758 sh_stream->rx.decoded_cnt++;
2759 }
2760
2761 net_buf_unref(data->buf);
2762 }
2763
lc3_decoder_thread_func(void * arg1,void * arg2,void * arg3)2764 static void lc3_decoder_thread_func(void *arg1, void *arg2, void *arg3)
2765 {
2766 while (true) {
2767 struct lc3_data *data = k_fifo_get(&lc3_in_fifo, K_FOREVER);
2768 struct shell_stream *sh_stream = data->sh_stream;
2769
2770 if (sh_stream->is_rx && sh_stream->rx.lc3_decoder == NULL) {
2771 shell_warn(ctx_shell, "Decoder is NULL, discarding data from FIFO");
2772 k_mem_slab_free(&lc3_data_slab, (void *)data);
2773 continue; /* Wait for new data */
2774 }
2775
2776 do_lc3_decode(data);
2777
2778 k_mem_slab_free(&lc3_data_slab, (void *)data);
2779 }
2780 }
2781
2782 #endif /* CONFIG_LIBLC3*/
2783
audio_recv(struct bt_bap_stream * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)2784 static void audio_recv(struct bt_bap_stream *stream,
2785 const struct bt_iso_recv_info *info,
2786 struct net_buf *buf)
2787 {
2788 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
2789
2790 if (!sh_stream->is_rx) {
2791 return;
2792 }
2793
2794 sh_stream->rx.rx_cnt++;
2795
2796 if (info->ts == sh_stream->rx.last_info.ts) {
2797 sh_stream->rx.dup_ts++;
2798 }
2799
2800 if (info->seq_num == sh_stream->rx.last_info.seq_num) {
2801 sh_stream->rx.dup_psn++;
2802 }
2803
2804 if ((info->flags & BT_ISO_FLAGS_VALID) != 0) {
2805 if (buf->len == 0U) {
2806 sh_stream->rx.empty_sdu_pkts++;
2807 } else {
2808 sh_stream->rx.valid_sdu_pkts++;
2809 }
2810 }
2811
2812 if (info->flags & BT_ISO_FLAGS_ERROR) {
2813 sh_stream->rx.err_pkts++;
2814 }
2815
2816 if (info->flags & BT_ISO_FLAGS_LOST) {
2817 sh_stream->rx.lost_pkts++;
2818 }
2819
2820 if ((sh_stream->rx.rx_cnt % bap_stats_interval) == 0) {
2821 shell_print(ctx_shell,
2822 "[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u "
2823 "(valid %zu, dup ts %zu, dup psn %zu, err_pkts %zu, lost_pkts %zu, "
2824 "empty SDUs %zu)",
2825 sh_stream->rx.rx_cnt, stream, buf->len, info->ts, info->seq_num,
2826 info->flags, sh_stream->rx.valid_sdu_pkts, sh_stream->rx.dup_ts,
2827 sh_stream->rx.dup_psn, sh_stream->rx.err_pkts, sh_stream->rx.lost_pkts,
2828 sh_stream->rx.empty_sdu_pkts);
2829 }
2830
2831 (void)memcpy(&sh_stream->rx.last_info, info, sizeof(sh_stream->rx.last_info));
2832
2833 #if defined(CONFIG_LIBLC3)
2834 if (sh_stream->rx.lc3_decoder != NULL) {
2835 const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu;
2836 const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame;
2837 const uint8_t chan_cnt = sh_stream->lc3_chan_cnt;
2838 struct lc3_data *data;
2839
2840 /* Allocate a context that holds both the buffer and the stream so that we can
2841 * send both of these values to the LC3 decoder thread as a single struct
2842 * in a FIFO
2843 */
2844 if (k_mem_slab_alloc(&lc3_data_slab, (void **)&data, K_NO_WAIT)) {
2845 shell_warn(ctx_shell, "Could not allocate LC3 data item");
2846
2847 return;
2848 }
2849
2850 if ((info->flags & BT_ISO_FLAGS_VALID) == 0) {
2851 data->do_plc = true;
2852 } else if (buf->len != (octets_per_frame * chan_cnt * frame_blocks_per_sdu)) {
2853 if (buf->len != 0U) {
2854 shell_error(
2855 ctx_shell,
2856 "Expected %u frame blocks with %u channels of size %u, but "
2857 "length is %u",
2858 frame_blocks_per_sdu, chan_cnt, octets_per_frame, buf->len);
2859 }
2860
2861 data->do_plc = true;
2862 }
2863
2864 data->buf = net_buf_ref(buf);
2865 data->sh_stream = sh_stream;
2866 if (info->flags & BT_ISO_FLAGS_TS) {
2867 data->ts = info->ts;
2868 } else {
2869 data->ts = 0U;
2870 }
2871
2872 k_fifo_put(&lc3_in_fifo, data);
2873 }
2874 #endif /* CONFIG_LIBLC3 */
2875 }
2876 #endif /* CONFIG_BT_AUDIO_RX */
2877
2878 #if defined(CONFIG_BT_BAP_UNICAST)
stream_enabled_cb(struct bt_bap_stream * stream)2879 static void stream_enabled_cb(struct bt_bap_stream *stream)
2880 {
2881 shell_print(ctx_shell, "Stream %p enabled", stream);
2882
2883 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER)) {
2884 struct bt_bap_ep_info ep_info;
2885 struct bt_conn_info conn_info;
2886 int err;
2887
2888 err = bt_conn_get_info(stream->conn, &conn_info);
2889 if (err != 0) {
2890 shell_error(ctx_shell, "Failed to get conn info: %d", err);
2891 return;
2892 }
2893
2894 if (conn_info.role == BT_CONN_ROLE_CENTRAL) {
2895 return; /* We also want to autonomously start the stream as the server */
2896 }
2897
2898 err = bt_bap_ep_get_info(stream->ep, &ep_info);
2899 if (err != 0) {
2900 shell_error(ctx_shell, "Failed to get ep info: %d", err);
2901 return;
2902 }
2903
2904 if (ep_info.dir == BT_AUDIO_DIR_SINK) {
2905 /* Automatically do the receiver start ready operation */
2906 err = bt_bap_stream_start(stream);
2907
2908 if (err != 0) {
2909 shell_error(ctx_shell, "Failed to start stream: %d", err);
2910 return;
2911 }
2912 }
2913 }
2914 }
2915 #endif /* CONFIG_BT_BAP_UNICAST */
2916
stream_started_cb(struct bt_bap_stream * bap_stream)2917 static void stream_started_cb(struct bt_bap_stream *bap_stream)
2918 {
2919 struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
2920 struct bt_bap_ep_info info = {0};
2921 int ret;
2922
2923 printk("Stream %p started\n", bap_stream);
2924
2925 ret = bt_bap_ep_get_info(bap_stream->ep, &info);
2926 if (ret != 0) {
2927 shell_error(ctx_shell, "Failed to get EP info: %d", ret);
2928 return;
2929 }
2930
2931 sh_stream->is_rx = info.can_recv;
2932 sh_stream->is_tx = info.can_send;
2933
2934 #if defined(CONFIG_LIBLC3)
2935 const struct bt_audio_codec_cfg *codec_cfg = bap_stream->codec_cfg;
2936
2937 if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) {
2938 if (sh_stream->is_tx) {
2939 atomic_set(&sh_stream->tx.lc3_enqueue_cnt, PRIME_COUNT);
2940 sh_stream->tx.lc3_sdu_cnt = 0U;
2941 }
2942
2943 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
2944 if (ret >= 0) {
2945 ret = bt_audio_codec_cfg_freq_to_freq_hz(ret);
2946
2947 if (ret > 0) {
2948 if (ret == 8000 || ret == 16000 || ret == 24000 || ret == 32000 ||
2949 ret == 48000) {
2950 sh_stream->lc3_freq_hz = (uint32_t)ret;
2951 } else {
2952 shell_error(ctx_shell, "Unsupported frequency for LC3: %d",
2953 ret);
2954 sh_stream->lc3_freq_hz = 0U;
2955 }
2956 } else {
2957 shell_error(ctx_shell, "Invalid frequency: %d", ret);
2958 sh_stream->lc3_freq_hz = 0U;
2959 }
2960 } else {
2961 shell_error(ctx_shell, "Could not get frequency: %d", ret);
2962 sh_stream->lc3_freq_hz = 0U;
2963 }
2964
2965 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
2966 if (ret >= 0) {
2967 ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
2968 if (ret > 0) {
2969 sh_stream->lc3_frame_duration_us = (uint32_t)ret;
2970 } else {
2971 shell_error(ctx_shell, "Invalid frame duration: %d", ret);
2972 sh_stream->lc3_frame_duration_us = 0U;
2973 }
2974 } else {
2975 shell_error(ctx_shell, "Could not get frame duration: %d", ret);
2976 sh_stream->lc3_frame_duration_us = 0U;
2977 }
2978
2979 ret = bt_audio_codec_cfg_get_chan_allocation(
2980 codec_cfg, &sh_stream->lc3_chan_allocation, false);
2981 if (ret == 0) {
2982 sh_stream->lc3_chan_cnt =
2983 bt_audio_get_chan_count(sh_stream->lc3_chan_allocation);
2984 } else {
2985 shell_error(ctx_shell, "Could not get channel allocation: %d", ret);
2986 sh_stream->lc3_chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO;
2987 sh_stream->lc3_chan_cnt = 1U;
2988 }
2989
2990 ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
2991 if (ret >= 0) {
2992 sh_stream->lc3_frame_blocks_per_sdu = (uint8_t)ret;
2993 } else {
2994 shell_error(ctx_shell, "Could not get frame blocks per SDU: %d", ret);
2995 sh_stream->lc3_frame_blocks_per_sdu = 0U;
2996 }
2997
2998 ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
2999 if (ret >= 0) {
3000 sh_stream->lc3_octets_per_frame = (uint16_t)ret;
3001 } else {
3002 shell_error(ctx_shell, "Could not get octets per frame: %d", ret);
3003 sh_stream->lc3_octets_per_frame = 0U;
3004 }
3005
3006 #if defined(CONFIG_BT_AUDIO_TX)
3007 if (sh_stream->is_tx && sh_stream->tx.lc3_encoder == NULL) {
3008 const int err = init_lc3_encoder(sh_stream);
3009
3010 if (err != 0) {
3011 shell_error(ctx_shell, "Failed to init LC3 encoder: %d", err);
3012
3013 return;
3014 }
3015
3016 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
3017 /* Always mark as active when using USB */
3018 sh_stream->tx.active = true;
3019 }
3020 }
3021 #endif /* CONFIG_BT_AUDIO_TX */
3022
3023 #if defined(CONFIG_BT_AUDIO_RX)
3024 if (sh_stream->is_rx) {
3025 if (sh_stream->rx.lc3_decoder == NULL) {
3026 const int err = init_lc3_decoder(sh_stream);
3027
3028 if (err != 0) {
3029 shell_error(ctx_shell, "Failed to init LC3 decoder: %d",
3030 err);
3031
3032 return;
3033 }
3034 }
3035
3036 sh_stream->rx.decoded_cnt = 0U;
3037
3038 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
3039 if ((sh_stream->lc3_chan_allocation &
3040 BT_AUDIO_LOCATION_FRONT_LEFT) != 0) {
3041 if (usb_left_stream == NULL) {
3042 shell_info(ctx_shell,
3043 "Setting USB left stream to %p",
3044 sh_stream);
3045 usb_left_stream = sh_stream;
3046 } else {
3047 shell_warn(ctx_shell,
3048 "Multiple left streams started");
3049 }
3050 }
3051
3052 if ((sh_stream->lc3_chan_allocation &
3053 BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) {
3054 if (usb_right_stream == NULL) {
3055 shell_info(ctx_shell,
3056 "Setting USB right stream to %p",
3057 sh_stream);
3058 usb_right_stream = sh_stream;
3059 } else {
3060 shell_warn(ctx_shell,
3061 "Multiple right streams started");
3062 }
3063 }
3064 }
3065 }
3066 #endif /* CONFIG_BT_AUDIO_RX */
3067 }
3068 #endif /* CONFIG_LIBLC3 */
3069
3070 #if defined(CONFIG_BT_AUDIO_TX)
3071 if (sh_stream->is_tx) {
3072 sh_stream->tx.connected_at_ticks = k_uptime_ticks();
3073 }
3074 #endif /* CONFIG_BT_AUDIO_TX */
3075
3076 #if defined(CONFIG_BT_AUDIO_RX)
3077 if (sh_stream->is_rx) {
3078 sh_stream->rx.empty_sdu_pkts = 0U;
3079 sh_stream->rx.valid_sdu_pkts = 0U;
3080 sh_stream->rx.lost_pkts = 0U;
3081 sh_stream->rx.err_pkts = 0U;
3082 sh_stream->rx.dup_psn = 0U;
3083 sh_stream->rx.rx_cnt = 0U;
3084 sh_stream->rx.dup_ts = 0U;
3085
3086 rx_streaming_cnt++;
3087 }
3088 #endif
3089 }
3090
3091 #if defined(CONFIG_LIBLC3)
update_usb_streams_cb(struct shell_stream * sh_stream,void * user_data)3092 static void update_usb_streams_cb(struct shell_stream *sh_stream, void *user_data)
3093 {
3094 if (sh_stream->is_rx) {
3095 if (usb_left_stream == NULL &&
3096 (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) {
3097 shell_info(ctx_shell, "Setting new USB left stream to %p", sh_stream);
3098 usb_left_stream = sh_stream;
3099 }
3100
3101 if (usb_right_stream == NULL &&
3102 (sh_stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) {
3103 shell_info(ctx_shell, "Setting new USB right stream to %p", sh_stream);
3104 usb_right_stream = sh_stream;
3105 }
3106 }
3107 }
3108
update_usb_streams(struct shell_stream * sh_stream)3109 static void update_usb_streams(struct shell_stream *sh_stream)
3110 {
3111 if (sh_stream->is_rx) {
3112 if (sh_stream == usb_left_stream) {
3113 shell_info(ctx_shell, "Clearing USB left stream (%p)", usb_left_stream);
3114 usb_left_stream = NULL;
3115 }
3116
3117 if (sh_stream == usb_right_stream) {
3118 shell_info(ctx_shell, "Clearing USB right stream (%p)", usb_right_stream);
3119 usb_right_stream = NULL;
3120 }
3121
3122 bap_foreach_stream(update_usb_streams_cb, NULL);
3123 }
3124 }
3125 #endif /* CONFIG_LIBLC3 */
3126
clear_stream_data(struct shell_stream * sh_stream)3127 static void clear_stream_data(struct shell_stream *sh_stream)
3128 {
3129 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
3130 if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) {
3131 if (default_broadcast_sink.stream_cnt != 0) {
3132 default_broadcast_sink.stream_cnt--;
3133 }
3134
3135 if (default_broadcast_sink.stream_cnt == 0) {
3136 /* All streams in the broadcast sink has been terminated */
3137 memset(&default_broadcast_sink.received_base, 0,
3138 sizeof(default_broadcast_sink.received_base));
3139 default_broadcast_sink.broadcast_id = 0;
3140 default_broadcast_sink.syncable = false;
3141 }
3142 }
3143 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
3144
3145 #if defined(CONFIG_BT_AUDIO_RX)
3146 if (sh_stream->is_rx) {
3147 rx_streaming_cnt--;
3148 memset(&sh_stream->rx, 0, sizeof(sh_stream->rx));
3149 }
3150 #endif
3151
3152 #if defined(CONFIG_BT_AUDIO_TX)
3153 if (sh_stream->is_tx) {
3154 memset(&sh_stream->tx, 0, sizeof(sh_stream->tx));
3155 }
3156 #endif
3157
3158 sh_stream->is_rx = sh_stream->is_tx = false;
3159
3160 #if defined(CONFIG_LIBLC3)
3161 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
3162 update_usb_streams(sh_stream);
3163 }
3164 #endif /* CONFIG_LIBLC3 */
3165 }
3166
stream_stopped_cb(struct bt_bap_stream * stream,uint8_t reason)3167 static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
3168 {
3169 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
3170
3171 printk("Stream %p stopped with reason 0x%02X\n", stream, reason);
3172
3173 clear_stream_data(sh_stream);
3174 }
3175
3176 #if defined(CONFIG_BT_BAP_UNICAST)
stream_configured_cb(struct bt_bap_stream * stream,const struct bt_bap_qos_cfg_pref * pref)3177 static void stream_configured_cb(struct bt_bap_stream *stream,
3178 const struct bt_bap_qos_cfg_pref *pref)
3179 {
3180 shell_print(ctx_shell, "Stream %p configured\n", stream);
3181 }
3182
stream_released_cb(struct bt_bap_stream * stream)3183 static void stream_released_cb(struct bt_bap_stream *stream)
3184 {
3185 struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
3186
3187 shell_print(ctx_shell, "Stream %p released\n", stream);
3188
3189 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
3190 if (default_unicast_group != NULL) {
3191 bool group_can_be_deleted = true;
3192
3193 for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
3194 const struct bt_bap_stream *bap_stream =
3195 bap_stream_from_shell_stream(&unicast_streams[i]);
3196
3197 if (bap_stream->ep != NULL) {
3198 struct bt_bap_ep_info ep_info;
3199 int err;
3200
3201 err = bt_bap_ep_get_info(bap_stream->ep, &ep_info);
3202 if (err == 0 && ep_info.state != BT_BAP_EP_STATE_CODEC_CONFIGURED &&
3203 ep_info.state != BT_BAP_EP_STATE_IDLE) {
3204 group_can_be_deleted = false;
3205 break;
3206 }
3207 }
3208 }
3209
3210 if (group_can_be_deleted) {
3211 int err;
3212
3213 shell_print(ctx_shell, "All streams released, deleting group\n");
3214
3215 err = bt_bap_unicast_group_delete(default_unicast_group);
3216
3217 if (err != 0) {
3218 shell_error(ctx_shell, "Failed to delete unicast group: %d", err);
3219 } else {
3220 default_unicast_group = NULL;
3221 }
3222 }
3223 }
3224 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
3225
3226 clear_stream_data(sh_stream);
3227 }
3228 #endif /* CONFIG_BT_BAP_UNICAST */
3229
3230 static struct bt_bap_stream_ops stream_ops = {
3231 #if defined(CONFIG_BT_AUDIO_RX)
3232 .recv = audio_recv,
3233 #endif /* CONFIG_BT_AUDIO_RX */
3234 #if defined(CONFIG_BT_BAP_UNICAST)
3235 .configured = stream_configured_cb,
3236 .released = stream_released_cb,
3237 .enabled = stream_enabled_cb,
3238 #endif /* CONFIG_BT_BAP_UNICAST */
3239 .started = stream_started_cb,
3240 .stopped = stream_stopped_cb,
3241 #if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX)
3242 .sent = lc3_sent_cb,
3243 #endif
3244 };
3245
3246 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
cmd_select_broadcast_source(const struct shell * sh,size_t argc,char * argv[])3247 static int cmd_select_broadcast_source(const struct shell *sh, size_t argc,
3248 char *argv[])
3249 {
3250 unsigned long index;
3251 int err = 0;
3252
3253 index = shell_strtoul(argv[1], 0, &err);
3254 if (err != 0) {
3255 shell_error(sh, "Could not parse index: %d", err);
3256
3257 return -ENOEXEC;
3258 }
3259
3260 if (index > ARRAY_SIZE(broadcast_source_streams)) {
3261 shell_error(sh, "Invalid index: %lu", index);
3262
3263 return -ENOEXEC;
3264 }
3265
3266 default_stream = bap_stream_from_shell_stream(&broadcast_source_streams[index]);
3267
3268 return 0;
3269 }
3270
cmd_create_broadcast(const struct shell * sh,size_t argc,char * argv[])3271 static int cmd_create_broadcast(const struct shell *sh, size_t argc,
3272 char *argv[])
3273 {
3274 struct bt_bap_broadcast_source_stream_param
3275 stream_params[ARRAY_SIZE(broadcast_source_streams)];
3276 struct bt_bap_broadcast_source_subgroup_param subgroup_param;
3277 struct bt_bap_broadcast_source_param create_param = {0};
3278 const struct named_lc3_preset *named_preset;
3279 int err;
3280
3281 if (default_source.bap_source != NULL) {
3282 shell_info(sh, "Broadcast source already created");
3283 return -ENOEXEC;
3284 }
3285
3286 named_preset = &default_broadcast_source_preset;
3287
3288 for (size_t i = 1U; i < argc; i++) {
3289 char *arg = argv[i];
3290
3291 if (strcmp(arg, "enc") == 0) {
3292 if (argc > i) {
3293 size_t bcode_len;
3294
3295 i++;
3296 arg = argv[i];
3297
3298 bcode_len = hex2bin(arg, strlen(arg),
3299 create_param.broadcast_code,
3300 sizeof(create_param.broadcast_code));
3301
3302 if (bcode_len != sizeof(create_param.broadcast_code)) {
3303 shell_error(sh, "Invalid Broadcast Code Length: %zu",
3304 bcode_len);
3305
3306 return -ENOEXEC;
3307 }
3308
3309 create_param.encryption = true;
3310 } else {
3311 shell_help(sh);
3312
3313 return SHELL_CMD_HELP_PRINTED;
3314 }
3315 } else if (strcmp(arg, "preset") == 0) {
3316 if (argc > i) {
3317
3318 i++;
3319 arg = argv[i];
3320
3321 named_preset = bap_get_named_preset(false, BT_AUDIO_DIR_SOURCE,
3322 arg);
3323 if (named_preset == NULL) {
3324 shell_error(sh, "Unable to parse named_preset %s",
3325 arg);
3326
3327 return -ENOEXEC;
3328 }
3329 } else {
3330 shell_help(sh);
3331
3332 return SHELL_CMD_HELP_PRINTED;
3333 }
3334 }
3335 }
3336
3337 copy_broadcast_source_preset(&default_source, named_preset);
3338
3339 (void)memset(stream_params, 0, sizeof(stream_params));
3340 for (size_t i = 0; i < ARRAY_SIZE(stream_params); i++) {
3341 stream_params[i].stream =
3342 bap_stream_from_shell_stream(&broadcast_source_streams[i]);
3343 }
3344 subgroup_param.params_count = ARRAY_SIZE(stream_params);
3345 subgroup_param.params = stream_params;
3346 subgroup_param.codec_cfg = &default_source.codec_cfg;
3347 create_param.params_count = 1U;
3348 create_param.params = &subgroup_param;
3349 create_param.qos = &default_source.qos;
3350
3351 err = bt_bap_broadcast_source_create(&create_param, &default_source.bap_source);
3352 if (err != 0) {
3353 shell_error(sh, "Unable to create broadcast source: %d", err);
3354 return err;
3355 }
3356
3357 shell_print(sh, "Broadcast source created: preset %s",
3358 named_preset->name);
3359
3360 if (default_stream == NULL) {
3361 default_stream = bap_stream_from_shell_stream(&broadcast_source_streams[0]);
3362 }
3363
3364 return 0;
3365 }
3366
cmd_start_broadcast(const struct shell * sh,size_t argc,char * argv[])3367 static int cmd_start_broadcast(const struct shell *sh, size_t argc,
3368 char *argv[])
3369 {
3370 struct bt_le_ext_adv *adv = adv_sets[selected_adv];
3371 int err;
3372
3373 if (adv == NULL) {
3374 shell_info(sh, "Extended advertising set is NULL");
3375 return -ENOEXEC;
3376 }
3377
3378 if (default_source.bap_source == NULL || default_source.is_cap) {
3379 shell_info(sh, "Broadcast source not created");
3380 return -ENOEXEC;
3381 }
3382
3383 err = bt_bap_broadcast_source_start(default_source.bap_source, adv_sets[selected_adv]);
3384 if (err != 0) {
3385 shell_error(sh, "Unable to start broadcast source: %d", err);
3386 return err;
3387 }
3388
3389 return 0;
3390 }
3391
cmd_stop_broadcast(const struct shell * sh,size_t argc,char * argv[])3392 static int cmd_stop_broadcast(const struct shell *sh, size_t argc, char *argv[])
3393 {
3394 int err;
3395
3396 if (default_source.bap_source == NULL || default_source.is_cap) {
3397 shell_info(sh, "Broadcast source not created");
3398 return -ENOEXEC;
3399 }
3400
3401 err = bt_bap_broadcast_source_stop(default_source.bap_source);
3402 if (err != 0) {
3403 shell_error(sh, "Unable to stop broadcast source: %d", err);
3404 return err;
3405 }
3406
3407 return 0;
3408 }
3409
cmd_delete_broadcast(const struct shell * sh,size_t argc,char * argv[])3410 static int cmd_delete_broadcast(const struct shell *sh, size_t argc,
3411 char *argv[])
3412 {
3413 int err;
3414
3415 if (default_source.bap_source == NULL || default_source.is_cap) {
3416 shell_info(sh, "Broadcast source not created");
3417 return -ENOEXEC;
3418 }
3419
3420 err = bt_bap_broadcast_source_delete(default_source.bap_source);
3421 if (err != 0) {
3422 shell_error(sh, "Unable to delete broadcast source: %d", err);
3423 return err;
3424 }
3425 default_source.bap_source = NULL;
3426
3427 return 0;
3428 }
3429 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3430
3431 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
cmd_create_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3432 static int cmd_create_broadcast_sink(const struct shell *sh, size_t argc, char *argv[])
3433 {
3434 struct bt_le_per_adv_sync *per_adv_sync = per_adv_syncs[selected_per_adv_sync];
3435 unsigned long broadcast_id;
3436 int err = 0;
3437
3438 broadcast_id = shell_strtoul(argv[1], 0, &err);
3439 if (err != 0) {
3440 shell_error(sh, "Could not parse broadcast_id: %d", err);
3441
3442 return -ENOEXEC;
3443 }
3444
3445 if (broadcast_id > BT_AUDIO_BROADCAST_ID_MAX) {
3446 shell_error(sh, "Invalid broadcast_id: %lu", broadcast_id);
3447
3448 return -ENOEXEC;
3449 }
3450
3451 if (per_adv_sync == NULL) {
3452 const struct bt_le_scan_param param = {
3453 .type = BT_LE_SCAN_TYPE_PASSIVE,
3454 .options = BT_LE_SCAN_OPT_NONE,
3455 .interval = BT_GAP_SCAN_FAST_INTERVAL,
3456 .window = BT_GAP_SCAN_FAST_WINDOW,
3457 .timeout = 1000, /* 10ms units -> 10 second timeout */
3458 };
3459
3460 shell_print(sh, "No PA sync available, starting scanning for broadcast_id");
3461
3462 err = bt_le_scan_start(¶m, NULL);
3463 if (err) {
3464 shell_print(sh, "Fail to start scanning: %d", err);
3465
3466 return -ENOEXEC;
3467 }
3468
3469 auto_scan.broadcast_sink = &default_broadcast_sink;
3470 auto_scan.broadcast_info.broadcast_id = broadcast_id;
3471 auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync];
3472 } else {
3473 shell_print(sh, "Creating broadcast sink with broadcast ID 0x%06X",
3474 (uint32_t)broadcast_id);
3475
3476 err = bt_bap_broadcast_sink_create(per_adv_sync, (uint32_t)broadcast_id,
3477 &default_broadcast_sink.bap_sink);
3478
3479 if (err != 0) {
3480 shell_error(sh, "Failed to create broadcast sink: %d", err);
3481
3482 return -ENOEXEC;
3483 }
3484 }
3485
3486 return 0;
3487 }
3488
cmd_create_sink_by_name(const struct shell * sh,size_t argc,char * argv[])3489 static int cmd_create_sink_by_name(const struct shell *sh, size_t argc, char *argv[])
3490 {
3491 const struct bt_le_scan_param param = {
3492 .type = BT_LE_SCAN_TYPE_PASSIVE,
3493 .options = BT_LE_SCAN_OPT_NONE,
3494 .interval = BT_GAP_SCAN_FAST_INTERVAL,
3495 .window = BT_GAP_SCAN_FAST_WINDOW,
3496 .timeout = 1000, /* 10ms units -> 10 second timeout */
3497 };
3498 char *broadcast_name;
3499 int err = 0;
3500
3501 broadcast_name = argv[1];
3502 if (!IN_RANGE(strlen(broadcast_name), BT_AUDIO_BROADCAST_NAME_LEN_MIN,
3503 BT_AUDIO_BROADCAST_NAME_LEN_MAX)) {
3504 shell_error(sh, "Broadcast name should be minimum %d and maximum %d characters",
3505 BT_AUDIO_BROADCAST_NAME_LEN_MIN, BT_AUDIO_BROADCAST_NAME_LEN_MAX);
3506
3507 return -ENOEXEC;
3508 }
3509
3510 shell_print(sh, "Starting scanning for broadcast_name");
3511
3512 err = bt_le_scan_start(¶m, NULL);
3513 if (err) {
3514 shell_print(sh, "Fail to start scanning: %d", err);
3515
3516 return -ENOEXEC;
3517 }
3518
3519 memcpy(auto_scan.broadcast_info.broadcast_name, broadcast_name, strlen(broadcast_name));
3520 auto_scan.broadcast_info.broadcast_name[strlen(broadcast_name)] = '\0';
3521
3522 auto_scan.broadcast_info.broadcast_id = BT_BAP_INVALID_BROADCAST_ID;
3523 auto_scan.broadcast_sink = &default_broadcast_sink;
3524 auto_scan.out_sync = &per_adv_syncs[selected_per_adv_sync];
3525
3526 return 0;
3527 }
3528
cmd_sync_broadcast(const struct shell * sh,size_t argc,char * argv[])3529 static int cmd_sync_broadcast(const struct shell *sh, size_t argc, char *argv[])
3530 {
3531 struct bt_bap_stream *streams[ARRAY_SIZE(broadcast_sink_streams)];
3532 uint8_t bcode[BT_ISO_BROADCAST_CODE_SIZE] = {0};
3533 bool bcode_set = false;
3534 uint32_t bis_bitfield;
3535 size_t stream_cnt;
3536 int err = 0;
3537
3538 bis_bitfield = 0;
3539 stream_cnt = 0U;
3540 for (size_t argn = 1U; argn < argc; argn++) {
3541 const char *arg = argv[argn];
3542
3543 if (strcmp(argv[argn], "bcode") == 0) {
3544 size_t len;
3545
3546 if (++argn == argc) {
3547 shell_help(sh);
3548
3549 return SHELL_CMD_HELP_PRINTED;
3550 }
3551
3552 arg = argv[argn];
3553
3554 len = hex2bin(arg, strlen(arg), bcode, sizeof(bcode));
3555 if (len == 0) {
3556 shell_print(sh, "Invalid broadcast code: %s", arg);
3557
3558 return -ENOEXEC;
3559 }
3560
3561 bcode_set = true;
3562 } else if (strcmp(argv[argn], "bcode_str") == 0) {
3563 if (++argn == argc) {
3564 shell_help(sh);
3565
3566 return SHELL_CMD_HELP_PRINTED;
3567 }
3568
3569 arg = argv[argn];
3570
3571 if (strlen(arg) == 0U || strlen(arg) > sizeof(bcode)) {
3572 shell_print(sh, "Invalid broadcast code: %s", arg);
3573
3574 return -ENOEXEC;
3575 }
3576
3577 memcpy(bcode, arg, strlen(arg));
3578 bcode_set = true;
3579 } else {
3580 unsigned long val;
3581
3582 val = shell_strtoul(arg, 0, &err);
3583 if (err != 0) {
3584 shell_error(sh, "Could not parse BIS index val: %d", err);
3585
3586 return -ENOEXEC;
3587 }
3588
3589 if (!IN_RANGE(val, BT_ISO_BIS_INDEX_MIN, BT_ISO_BIS_INDEX_MAX)) {
3590 shell_error(sh, "Invalid index: %lu", val);
3591
3592 return -ENOEXEC;
3593 }
3594
3595 bis_bitfield |= BT_ISO_BIS_INDEX_BIT(val);
3596 stream_cnt++;
3597 }
3598 }
3599
3600 if (default_broadcast_sink.bap_sink == NULL) {
3601 shell_error(sh, "No sink available");
3602 return -ENOEXEC;
3603 }
3604
3605 (void)memset(streams, 0, sizeof(streams));
3606 for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
3607 streams[i] = bap_stream_from_shell_stream(&broadcast_sink_streams[i]);
3608 }
3609
3610 err = bt_bap_broadcast_sink_sync(default_broadcast_sink.bap_sink, bis_bitfield, streams,
3611 bcode_set ? bcode : NULL);
3612 if (err != 0) {
3613 shell_error(sh, "Failed to sync to broadcast: %d", err);
3614 return err;
3615 }
3616
3617 default_broadcast_sink.stream_cnt = stream_cnt;
3618
3619 return 0;
3620 }
3621
cmd_stop_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3622 static int cmd_stop_broadcast_sink(const struct shell *sh, size_t argc,
3623 char *argv[])
3624 {
3625 int err;
3626
3627 if (default_broadcast_sink.bap_sink == NULL) {
3628 shell_error(sh, "No sink available");
3629 return -ENOEXEC;
3630 }
3631
3632 err = bt_bap_broadcast_sink_stop(default_broadcast_sink.bap_sink);
3633 if (err != 0) {
3634 shell_error(sh, "Failed to stop sink: %d", err);
3635 return err;
3636 }
3637
3638 return err;
3639 }
3640
cmd_term_broadcast_sink(const struct shell * sh,size_t argc,char * argv[])3641 static int cmd_term_broadcast_sink(const struct shell *sh, size_t argc,
3642 char *argv[])
3643 {
3644 int err;
3645
3646 if (default_broadcast_sink.bap_sink == NULL) {
3647 shell_error(sh, "No sink available");
3648 return -ENOEXEC;
3649 }
3650
3651 err = bt_bap_broadcast_sink_delete(default_broadcast_sink.bap_sink);
3652 if (err != 0) {
3653 shell_error(sh, "Failed to term sink: %d", err);
3654 return err;
3655 }
3656
3657 default_broadcast_sink.bap_sink = NULL;
3658 default_broadcast_sink.syncable = false;
3659
3660 return err;
3661 }
3662 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
3663
cmd_set_loc(const struct shell * sh,size_t argc,char * argv[])3664 static int cmd_set_loc(const struct shell *sh, size_t argc, char *argv[])
3665 {
3666 int err = 0;
3667 enum bt_audio_dir dir;
3668 enum bt_audio_location loc;
3669 unsigned long loc_val;
3670
3671 if (!strcmp(argv[1], "sink")) {
3672 dir = BT_AUDIO_DIR_SINK;
3673 } else if (!strcmp(argv[1], "source")) {
3674 dir = BT_AUDIO_DIR_SOURCE;
3675 } else {
3676 shell_error(sh, "Unsupported dir: %s", argv[1]);
3677 return -ENOEXEC;
3678 }
3679
3680 loc_val = shell_strtoul(argv[2], 16, &err);
3681 if (err != 0) {
3682 shell_error(sh, "Could not parse loc_val: %d", err);
3683
3684 return -ENOEXEC;
3685 }
3686
3687 if (loc_val > BT_AUDIO_LOCATION_ANY) {
3688 shell_error(sh, "Invalid location: %lu", loc_val);
3689
3690 return -ENOEXEC;
3691 }
3692
3693 loc = loc_val;
3694
3695 err = bt_pacs_set_location(dir, loc);
3696 if (err) {
3697 shell_error(ctx_shell, "Set available contexts err %d", err);
3698 return -ENOEXEC;
3699 }
3700
3701 return 0;
3702 }
3703
cmd_context(const struct shell * sh,size_t argc,char * argv[])3704 static int cmd_context(const struct shell *sh, size_t argc, char *argv[])
3705 {
3706 int err = 0;
3707 enum bt_audio_dir dir;
3708 enum bt_audio_context ctx;
3709 unsigned long ctx_val;
3710
3711 if (!strcmp(argv[1], "sink")) {
3712 dir = BT_AUDIO_DIR_SINK;
3713 } else if (!strcmp(argv[1], "source")) {
3714 dir = BT_AUDIO_DIR_SOURCE;
3715 } else {
3716 shell_error(sh, "Unsupported dir: %s", argv[1]);
3717 return -ENOEXEC;
3718 }
3719
3720 ctx_val = shell_strtoul(argv[2], 16, &err);
3721 if (err) {
3722 shell_error(sh, "Could not parse context: %d", err);
3723
3724 return err;
3725 }
3726
3727 if (ctx_val > BT_AUDIO_CONTEXT_TYPE_ANY) {
3728 shell_error(sh, "Invalid context: %lu", ctx_val);
3729
3730 return -ENOEXEC;
3731 }
3732
3733 ctx = ctx_val;
3734
3735 if (!strcmp(argv[3], "supported")) {
3736 if (ctx_val == BT_AUDIO_CONTEXT_TYPE_PROHIBITED) {
3737 shell_error(sh, "Invalid context: %lu", ctx_val);
3738
3739 return -ENOEXEC;
3740 }
3741
3742 err = bt_pacs_set_supported_contexts(dir, ctx);
3743 if (err) {
3744 shell_error(ctx_shell, "Set supported contexts err %d", err);
3745 return err;
3746 }
3747 } else if (!strcmp(argv[3], "available")) {
3748 err = bt_pacs_set_available_contexts(dir, ctx);
3749 if (err) {
3750 shell_error(ctx_shell, "Set available contexts err %d", err);
3751 return err;
3752 }
3753 } else {
3754 shell_error(sh, "Unsupported context type: %s", argv[3]);
3755 return -ENOEXEC;
3756 }
3757
3758 return 0;
3759 }
3760
cmd_init(const struct shell * sh,size_t argc,char * argv[])3761 static int cmd_init(const struct shell *sh, size_t argc, char *argv[])
3762 {
3763 int err, i;
3764
3765 ctx_shell = sh;
3766
3767 if (initialized) {
3768 shell_print(sh, "Already initialized");
3769 return -ENOEXEC;
3770 }
3771
3772 if (argc != 1 && (IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) && argc != 3)) {
3773 shell_error(sh, "Invalid argument count");
3774 shell_help(sh);
3775
3776 return SHELL_CMD_HELP_PRINTED;
3777 }
3778
3779 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
3780 unsigned long snk_cnt, src_cnt;
3781 struct bt_bap_unicast_server_register_param unicast_server_param = {
3782 CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT,
3783 CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT
3784 };
3785
3786
3787 if (argc == 3) {
3788 snk_cnt = shell_strtoul(argv[1], 0, &err);
3789 if (snk_cnt > CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT) {
3790 shell_error(sh, "Invalid Sink ASE count: %lu. Valid interval: [0, %u]",
3791 snk_cnt, CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT);
3792
3793 return -ENOEXEC;
3794 }
3795
3796 unicast_server_param.snk_cnt = snk_cnt;
3797
3798 src_cnt = shell_strtoul(argv[2], 0, &err);
3799 if (src_cnt > CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT) {
3800 shell_error(sh, "Invalid Source ASE count: %lu. Valid interval: [0, %u]",
3801 src_cnt, CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT);
3802
3803 return -ENOEXEC;
3804 }
3805
3806 unicast_server_param.src_cnt = src_cnt;
3807 } else {
3808 snk_cnt = CONFIG_BT_ASCS_MAX_ASE_SNK_COUNT;
3809 src_cnt = CONFIG_BT_ASCS_MAX_ASE_SRC_COUNT;
3810 }
3811
3812 bt_bap_unicast_server_register(&unicast_server_param);
3813 bt_bap_unicast_server_register_cb(&unicast_server_cb);
3814 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
3815
3816 #if defined(CONFIG_BT_PAC_SNK)
3817 bt_pacs_cap_register(BT_AUDIO_DIR_SINK, &cap_sink);
3818 #endif /* CONFIG_BT_PAC_SNK */
3819 #if defined(CONFIG_BT_PAC_SRC)
3820 bt_pacs_cap_register(BT_AUDIO_DIR_SOURCE, &cap_source);
3821 #endif /* CONFIG_BT_PAC_SNK */
3822
3823 if (IS_ENABLED(CONFIG_BT_PAC_SNK_LOC)) {
3824 err = bt_pacs_set_location(BT_AUDIO_DIR_SINK, LOCATION);
3825 __ASSERT(err == 0, "Failed to set sink location: %d", err);
3826
3827 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SINK,
3828 CONTEXT);
3829 __ASSERT(err == 0, "Failed to set sink supported contexts: %d",
3830 err);
3831
3832 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SINK,
3833 CONTEXT);
3834 __ASSERT(err == 0, "Failed to set sink available contexts: %d",
3835 err);
3836 }
3837
3838 if (IS_ENABLED(CONFIG_BT_PAC_SRC_LOC)) {
3839 err = bt_pacs_set_location(BT_AUDIO_DIR_SOURCE, LOCATION);
3840 __ASSERT(err == 0, "Failed to set source location: %d", err);
3841
3842 err = bt_pacs_set_supported_contexts(BT_AUDIO_DIR_SOURCE,
3843 CONTEXT);
3844 __ASSERT(err == 0, "Failed to set sink supported contexts: %d",
3845 err);
3846
3847 err = bt_pacs_set_available_contexts(BT_AUDIO_DIR_SOURCE,
3848 CONTEXT);
3849 __ASSERT(err == 0,
3850 "Failed to set source available contexts: %d",
3851 err);
3852 }
3853
3854 #if defined(CONFIG_BT_BAP_UNICAST)
3855 for (i = 0; i < ARRAY_SIZE(unicast_streams); i++) {
3856 bt_bap_stream_cb_register(bap_stream_from_shell_stream(&unicast_streams[i]),
3857 &stream_ops);
3858
3859 if (IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT) &&
3860 IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
3861 /* If we use the cap initiator, we need to register the callbacks for CAP
3862 * as well, as CAP will override and use the BAP callbacks if doing a CAP
3863 * procedure
3864 */
3865 bt_cap_stream_ops_register(&unicast_streams[i].stream, &stream_ops);
3866 }
3867 }
3868 #endif /* CONFIG_BT_BAP_UNICAST */
3869
3870 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
3871 bt_bap_broadcast_sink_register_cb(&sink_cbs);
3872 bt_le_per_adv_sync_cb_register(&bap_pa_sync_cb);
3873 bt_le_scan_cb_register(&bap_scan_cb);
3874
3875 for (i = 0; i < ARRAY_SIZE(broadcast_sink_streams); i++) {
3876 bt_bap_stream_cb_register(bap_stream_from_shell_stream(&broadcast_sink_streams[i]),
3877 &stream_ops);
3878 }
3879 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3880
3881 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
3882 for (i = 0; i < ARRAY_SIZE(broadcast_source_streams); i++) {
3883 bt_bap_stream_cb_register(
3884 bap_stream_from_shell_stream(&broadcast_source_streams[i]), &stream_ops);
3885 }
3886 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
3887
3888 #if defined(CONFIG_LIBLC3)
3889 #if defined(CONFIG_BT_AUDIO_RX)
3890 static K_KERNEL_STACK_DEFINE(lc3_decoder_thread_stack, 4096);
3891 const int lc3_decoder_thread_prio = K_PRIO_PREEMPT(5);
3892 static struct k_thread lc3_decoder_thread;
3893
3894 k_thread_create(&lc3_decoder_thread, lc3_decoder_thread_stack,
3895 K_KERNEL_STACK_SIZEOF(lc3_decoder_thread_stack), lc3_decoder_thread_func,
3896 NULL, NULL, NULL, lc3_decoder_thread_prio, 0, K_NO_WAIT);
3897 k_thread_name_set(&lc3_decoder_thread, "LC3 Decoder");
3898 #endif /* CONFIG_BT_AUDIO_RX */
3899
3900 #if defined(CONFIG_BT_AUDIO_TX)
3901 static K_KERNEL_STACK_DEFINE(lc3_encoder_thread_stack, 4096);
3902 const int lc3_encoder_thread_prio = K_PRIO_PREEMPT(5);
3903 static struct k_thread lc3_encoder_thread;
3904
3905 k_thread_create(&lc3_encoder_thread, lc3_encoder_thread_stack,
3906 K_KERNEL_STACK_SIZEOF(lc3_encoder_thread_stack), lc3_encoder_thread_func,
3907 NULL, NULL, NULL, lc3_encoder_thread_prio, 0, K_NO_WAIT);
3908 k_thread_name_set(&lc3_encoder_thread, "LC3 Encoder");
3909
3910 #endif /* CONFIG_BT_AUDIO_TX */
3911
3912 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) &&
3913 (IS_ENABLED(CONFIG_BT_AUDIO_RX) || IS_ENABLED(CONFIG_BT_AUDIO_TX))) {
3914 err = bap_usb_init();
3915 __ASSERT(err == 0, "Failed to enable USB: %d", err);
3916 }
3917 #endif /* CONFIG_LIBLC3 */
3918
3919 initialized = true;
3920
3921 return 0;
3922 }
3923
3924 #if defined(CONFIG_BT_AUDIO_TX)
3925
3926 #define DATA_MTU CONFIG_BT_ISO_TX_MTU
3927 NET_BUF_POOL_FIXED_DEFINE(tx_pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
3928
cmd_send(const struct shell * sh,size_t argc,char * argv[])3929 static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
3930 {
3931 static uint8_t data[DATA_MTU - BT_ISO_CHAN_SEND_RESERVE];
3932 int ret, len;
3933 struct net_buf *buf;
3934
3935 if (default_stream == NULL) {
3936 shell_error(sh, "Invalid (NULL) stream");
3937
3938 return -ENOEXEC;
3939 }
3940
3941 if (default_stream->qos == NULL) {
3942 shell_error(sh, "NULL stream QoS");
3943
3944 return -ENOEXEC;
3945 }
3946
3947 if (argc > 1) {
3948 len = hex2bin(argv[1], strlen(argv[1]), data, sizeof(data));
3949 if (len > default_stream->qos->sdu) {
3950 shell_print(sh, "Unable to send: len %d > %u MTU",
3951 len, default_stream->qos->sdu);
3952
3953 return -ENOEXEC;
3954 }
3955 } else {
3956 len = MIN(default_stream->qos->sdu, sizeof(data));
3957 memset(data, 0xff, len);
3958 }
3959
3960 buf = net_buf_alloc(&tx_pool, K_FOREVER);
3961 net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
3962
3963 net_buf_add_mem(buf, data, len);
3964
3965 ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(default_stream));
3966 if (ret < 0) {
3967 shell_print(sh, "Unable to send: %d", -ret);
3968 net_buf_unref(buf);
3969
3970 return -ENOEXEC;
3971 }
3972
3973 shell_print(sh, "Sending:");
3974 shell_hexdump(sh, data, len);
3975
3976 return 0;
3977 }
3978
3979 #if GENERATE_SINE_SUPPORTED
start_sine_stream_cb(struct shell_stream * sh_stream,void * user_data)3980 static void start_sine_stream_cb(struct shell_stream *sh_stream, void *user_data)
3981 {
3982 if (sh_stream->is_tx) {
3983 struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream);
3984 const struct shell *sh = user_data;
3985 int err;
3986
3987 err = init_lc3_encoder(sh_stream);
3988 if (err != 0) {
3989 shell_error(sh, "Failed to init LC3 %d for stream %p", err, bap_stream);
3990
3991 return;
3992 }
3993
3994 sh_stream->tx.active = true;
3995 sh_stream->tx.seq_num = get_next_seq_num(bap_stream_from_shell_stream(sh_stream));
3996
3997 shell_print(sh, "Started transmitting sine on stream %p", bap_stream);
3998 }
3999 }
4000
cmd_start_sine(const struct shell * sh,size_t argc,char * argv[])4001 static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
4002 {
4003 bool start_all = false;
4004
4005 if (argc > 1) {
4006 if (strcmp(argv[1], "all") == 0) {
4007 start_all = true;
4008 } else {
4009 shell_help(sh);
4010
4011 return SHELL_CMD_HELP_PRINTED;
4012 }
4013 }
4014
4015 if (start_all) {
4016 bap_foreach_stream(start_sine_stream_cb, (void *)sh);
4017 } else {
4018 struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream);
4019
4020 start_sine_stream_cb(sh_stream, (void *)sh);
4021 }
4022
4023 return 0;
4024 }
4025
stop_sine_stream_cb(struct shell_stream * sh_stream,void * user_data)4026 static void stop_sine_stream_cb(struct shell_stream *sh_stream, void *user_data)
4027 {
4028 if (sh_stream->is_tx) {
4029 struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream);
4030 const struct shell *sh = user_data;
4031
4032 shell_print(sh, "Stopped transmitting on stream %p", bap_stream);
4033
4034 sh_stream->tx.active = false;
4035 }
4036 }
4037
cmd_stop_sine(const struct shell * sh,size_t argc,char * argv[])4038 static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[])
4039 {
4040 bool stop_all = false;
4041
4042 if (argc > 1) {
4043 if (strcmp(argv[1], "all") == 0) {
4044 stop_all = true;
4045 } else {
4046 shell_help(sh);
4047
4048 return SHELL_CMD_HELP_PRINTED;
4049 }
4050 }
4051
4052 if (stop_all) {
4053 bap_foreach_stream(stop_sine_stream_cb, (void *)sh);
4054 } else {
4055 struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream);
4056
4057 stop_sine_stream_cb(sh_stream, (void *)sh);
4058 }
4059
4060 return 0;
4061 }
4062 #endif /* GENERATE_SINE_SUPPORTED */
4063 #endif /* CONFIG_BT_AUDIO_TX */
4064
cmd_bap_stats(const struct shell * sh,size_t argc,char * argv[])4065 static int cmd_bap_stats(const struct shell *sh, size_t argc, char *argv[])
4066 {
4067 if (argc == 1) {
4068 shell_info(sh, "Current stats interval: %lu", bap_stats_interval);
4069 } else {
4070 int err = 0;
4071 unsigned long interval;
4072
4073 interval = shell_strtoul(argv[1], 0, &err);
4074 if (err != 0) {
4075 shell_error(sh, "Could not parse interval: %d", err);
4076
4077 return -ENOEXEC;
4078 }
4079
4080 if (interval == 0U) {
4081 shell_error(sh, "Interval cannot be 0");
4082
4083 return -ENOEXEC;
4084 }
4085
4086 bap_stats_interval = interval;
4087 }
4088
4089 return 0;
4090 }
4091
4092 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
print_ase_info(struct bt_bap_ep * ep,void * user_data)4093 static void print_ase_info(struct bt_bap_ep *ep, void *user_data)
4094 {
4095 struct bt_bap_ep_info info;
4096 int err;
4097
4098 err = bt_bap_ep_get_info(ep, &info);
4099 if (err == 0) {
4100 printk("ASE info: id %u state %u dir %u\n", info.id, info.state, info.dir);
4101 }
4102 }
4103
cmd_print_ase_info(const struct shell * sh,size_t argc,char * argv[])4104 static int cmd_print_ase_info(const struct shell *sh, size_t argc, char *argv[])
4105 {
4106 if (!default_conn) {
4107 shell_error(sh, "Not connected");
4108 return -ENOEXEC;
4109 }
4110
4111 bt_bap_unicast_server_foreach_ep(default_conn, print_ase_info, NULL);
4112
4113 return 0;
4114 }
4115 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
4116
4117 /* 31 is a unit separator - without t the tab is seemingly ignored*/
4118 #define HELP_SEP "\n\31\t"
4119
4120 #define HELP_CFG_DATA \
4121 "\n[config" HELP_SEP "[freq <frequency>]" HELP_SEP "[dur <duration>]" HELP_SEP \
4122 "[chan_alloc <location>]" HELP_SEP "[frame_len <frame length>]" HELP_SEP \
4123 "[frame_blks <frame blocks>]]"
4124
4125 #define HELP_CFG_META \
4126 "\n[meta" HELP_SEP "[pref_ctx <context>]" HELP_SEP "[stream_ctx <context>]" HELP_SEP \
4127 "[program_info <program info>]" HELP_SEP "[lang <ISO 639-3 lang>]" HELP_SEP \
4128 "[ccid_list <ccids>]" HELP_SEP "[parental_rating <rating>]" HELP_SEP \
4129 "[program_info_uri <URI>]" HELP_SEP "[audio_active_state <state>]" HELP_SEP \
4130 "[bcast_flag]" HELP_SEP "[extended <meta>]" HELP_SEP "[vendor <meta>]]"
4131
4132 SHELL_STATIC_SUBCMD_SET_CREATE(
4133 bap_cmds,
4134 SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1,
4135 IS_ENABLED(CONFIG_BT_BAP_UNICAST_SERVER) ? 2 : 0),
4136 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
4137 SHELL_CMD_ARG(select_broadcast, NULL, "<stream>", cmd_select_broadcast_source, 2, 0),
4138 SHELL_CMD_ARG(create_broadcast, NULL, "[preset <preset_name>] [enc <broadcast_code>]",
4139 cmd_create_broadcast, 1, 2),
4140 SHELL_CMD_ARG(start_broadcast, NULL, "", cmd_start_broadcast, 1, 0),
4141 SHELL_CMD_ARG(stop_broadcast, NULL, "", cmd_stop_broadcast, 1, 0),
4142 SHELL_CMD_ARG(delete_broadcast, NULL, "", cmd_delete_broadcast, 1, 0),
4143 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
4144 #if defined(CONFIG_BT_BAP_BROADCAST_SINK)
4145 SHELL_CMD_ARG(create_broadcast_sink, NULL, "0x<broadcast_id>", cmd_create_broadcast_sink, 2,
4146 0),
4147 SHELL_CMD_ARG(create_sink_by_name, NULL, "<broadcast_name>",
4148 cmd_create_sink_by_name, 2, 0),
4149 SHELL_CMD_ARG(sync_broadcast, NULL,
4150 "0x<bis_index> [[[0x<bis_index>] 0x<bis_index>] ...] "
4151 "[bcode <broadcast code> || bcode_str <broadcast code as string>]",
4152 cmd_sync_broadcast, 2, ARRAY_SIZE(broadcast_sink_streams) + 1),
4153 SHELL_CMD_ARG(stop_broadcast_sink, NULL, "Stops broadcast sink", cmd_stop_broadcast_sink, 1,
4154 0),
4155 SHELL_CMD_ARG(term_broadcast_sink, NULL, "", cmd_term_broadcast_sink, 1, 0),
4156 #endif /* CONFIG_BT_BAP_BROADCAST_SINK */
4157 #if defined(CONFIG_BT_BAP_UNICAST)
4158 #if defined(CONFIG_BT_BAP_UNICAST_CLIENT)
4159 SHELL_CMD_ARG(discover, NULL, "[dir: sink, source]", cmd_discover, 1, 1),
4160 SHELL_CMD_ARG(config, NULL,
4161 "<direction: sink, source> <index> [loc <loc_bits>] [preset <preset_name>]",
4162 cmd_config, 3, 4),
4163 SHELL_CMD_ARG(stream_qos, NULL, "interval [framing] [latency] [pd] [sdu] [phy] [rtn]",
4164 cmd_stream_qos, 2, 6),
4165 SHELL_CMD_ARG(connect, NULL, "Connect the CIS of the stream", cmd_connect, 1, 0),
4166 SHELL_CMD_ARG(qos, NULL, "Send QoS configure for Unicast Group", cmd_qos, 1, 0),
4167 SHELL_CMD_ARG(enable, NULL, "[context]", cmd_enable, 1, 1),
4168 SHELL_CMD_ARG(stop, NULL, NULL, cmd_stop, 1, 0),
4169 SHELL_CMD_ARG(list, NULL, NULL, cmd_list, 1, 0),
4170 #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */
4171 #if defined(CONFIG_BT_BAP_UNICAST_SERVER)
4172 SHELL_CMD_ARG(print_ase_info, NULL, "Print ASE info for default connection",
4173 cmd_print_ase_info, 0, 0),
4174 #endif /* CONFIG_BT_BAP_UNICAST_SERVER */
4175 SHELL_CMD_ARG(metadata, NULL, "[context]", cmd_metadata, 1, 1),
4176 SHELL_CMD_ARG(start, NULL, NULL, cmd_start, 1, 0),
4177 SHELL_CMD_ARG(disable, NULL, NULL, cmd_disable, 1, 0),
4178 SHELL_CMD_ARG(release, NULL, NULL, cmd_release, 1, 0),
4179 SHELL_CMD_ARG(select_unicast, NULL, "<stream>", cmd_select_unicast, 2, 0),
4180 #endif /* CONFIG_BT_BAP_UNICAST */
4181 #if IS_BAP_INITIATOR
4182 SHELL_CMD_ARG(preset, NULL,
4183 "<sink, source, broadcast> [preset] " HELP_CFG_DATA " " HELP_CFG_META,
4184 cmd_preset, 2, 34),
4185 #endif /* IS_BAP_INITIATOR */
4186 #if defined(CONFIG_BT_AUDIO_TX)
4187 SHELL_CMD_ARG(send, NULL, "Send to Audio Stream [data]", cmd_send, 1, 1),
4188 #if GENERATE_SINE_SUPPORTED
4189 SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave [all]",
4190 cmd_start_sine, 1, 1),
4191 SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave [all]", cmd_stop_sine,
4192 1, 1),
4193 #endif /* GENERATE_SINE_SUPPORTED */
4194 #endif /* CONFIG_BT_AUDIO_TX */
4195 SHELL_CMD_ARG(bap_stats, NULL,
4196 "Sets or gets the statistics reporting interval in # of packets",
4197 cmd_bap_stats, 1, 1),
4198 SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_location, NULL,
4199 "<direction: sink, source> <location bitmask>", cmd_set_loc, 3, 0),
4200 SHELL_COND_CMD_ARG(CONFIG_BT_PACS, set_context, NULL,
4201 "<direction: sink, source>"
4202 "<context bitmask> <type: supported, available>",
4203 cmd_context, 4, 0),
4204 SHELL_SUBCMD_SET_END);
4205
cmd_bap(const struct shell * sh,size_t argc,char ** argv)4206 static int cmd_bap(const struct shell *sh, size_t argc, char **argv)
4207 {
4208 if (argc > 1) {
4209 shell_error(sh, "%s unknown parameter: %s",
4210 argv[0], argv[1]);
4211 } else {
4212 shell_error(sh, "%s Missing subcommand", argv[0]);
4213 }
4214
4215 return -ENOEXEC;
4216 }
4217
4218 SHELL_CMD_ARG_REGISTER(bap, &bap_cmds, "Bluetooth BAP shell commands", cmd_bap, 1, 1);
4219
connectable_ad_data_add(struct bt_data * data_array,size_t data_array_size)4220 static ssize_t connectable_ad_data_add(struct bt_data *data_array,
4221 size_t data_array_size)
4222 {
4223 static const uint8_t ad_ext_uuid16[] = {
4224 IF_ENABLED(CONFIG_BT_MICP_MIC_DEV, (BT_UUID_16_ENCODE(BT_UUID_MICS_VAL),))
4225 IF_ENABLED(CONFIG_BT_ASCS, (BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),))
4226 IF_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR, (BT_UUID_16_ENCODE(BT_UUID_BASS_VAL),))
4227 IF_ENABLED(CONFIG_BT_PACS, (BT_UUID_16_ENCODE(BT_UUID_PACS_VAL),))
4228 IF_ENABLED(CONFIG_BT_TBS, (BT_UUID_16_ENCODE(BT_UUID_GTBS_VAL),))
4229 IF_ENABLED(CONFIG_BT_TBS_BEARER_COUNT, (BT_UUID_16_ENCODE(BT_UUID_TBS_VAL),))
4230 IF_ENABLED(CONFIG_BT_VCP_VOL_REND, (BT_UUID_16_ENCODE(BT_UUID_VCS_VAL),))
4231 IF_ENABLED(CONFIG_BT_HAS, (BT_UUID_16_ENCODE(BT_UUID_HAS_VAL),)) /* Shall be last */
4232 };
4233 size_t ad_len = 0;
4234
4235 if (IS_ENABLED(CONFIG_BT_ASCS)) {
4236 static uint8_t ad_bap_announcement[8] = {
4237 BT_UUID_16_ENCODE(BT_UUID_ASCS_VAL),
4238 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
4239 };
4240 enum bt_audio_context snk_context, src_context;
4241
4242 snk_context = bt_pacs_get_available_contexts(BT_AUDIO_DIR_SINK);
4243 sys_put_le16(snk_context, &ad_bap_announcement[3]);
4244
4245 src_context = bt_pacs_get_available_contexts(BT_AUDIO_DIR_SOURCE);
4246 sys_put_le16(src_context, &ad_bap_announcement[5]);
4247
4248 /* Metadata length */
4249 ad_bap_announcement[7] = 0x00;
4250
4251 __ASSERT(data_array_size > ad_len, "No space for AD_BAP_ANNOUNCEMENT");
4252 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4253 data_array[ad_len].data_len = ARRAY_SIZE(ad_bap_announcement);
4254 data_array[ad_len].data = &ad_bap_announcement[0];
4255 ad_len++;
4256 }
4257
4258 if (IS_ENABLED(CONFIG_BT_BAP_SCAN_DELEGATOR)) {
4259 ad_len += bap_scan_delegator_ad_data_add(&data_array[ad_len],
4260 data_array_size - ad_len);
4261 }
4262
4263 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR)) {
4264 ad_len += cap_acceptor_ad_data_add(&data_array[ad_len], data_array_size - ad_len,
4265 true);
4266 }
4267
4268 if (IS_ENABLED(CONFIG_BT_GMAP)) {
4269 ad_len += gmap_ad_data_add(&data_array[ad_len], data_array_size - ad_len);
4270 }
4271
4272 if (ARRAY_SIZE(ad_ext_uuid16) > 0) {
4273 size_t uuid16_size;
4274
4275 if (data_array_size <= ad_len) {
4276 shell_warn(ctx_shell, "No space for AD_UUID16");
4277 return ad_len;
4278 }
4279
4280 data_array[ad_len].type = BT_DATA_UUID16_SOME;
4281
4282 if (IS_ENABLED(CONFIG_BT_HAS) && IS_ENABLED(CONFIG_BT_PRIVACY)) {
4283 /* If the HA is in one of the GAP connectable modes and is using a
4284 * resolvable private address, the HA shall not include the Hearing Access
4285 * Service UUID in the Service UUID AD type field of the advertising data
4286 * or scan response.
4287 */
4288 uuid16_size = ARRAY_SIZE(ad_ext_uuid16) - BT_UUID_SIZE_16;
4289 } else {
4290 uuid16_size = ARRAY_SIZE(ad_ext_uuid16);
4291 }
4292
4293 /* We can maximum advertise 127 16-bit UUIDs = 254 octets */
4294 data_array[ad_len].data_len = MIN(uuid16_size, 254);
4295
4296 data_array[ad_len].data = &ad_ext_uuid16[0];
4297 ad_len++;
4298 }
4299
4300 return ad_len;
4301 }
4302
nonconnectable_ad_data_add(struct bt_data * data_array,const size_t data_array_size)4303 static ssize_t nonconnectable_ad_data_add(struct bt_data *data_array,
4304 const size_t data_array_size)
4305 {
4306 static const uint8_t ad_ext_uuid16[] = {
4307 IF_ENABLED(CONFIG_BT_PACS, (BT_UUID_16_ENCODE(BT_UUID_PACS_VAL),))
4308 IF_ENABLED(CONFIG_BT_CAP_ACCEPTOR, (BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),))
4309 };
4310 size_t ad_len = 0;
4311
4312 if (IS_ENABLED(CONFIG_BT_CAP_ACCEPTOR)) {
4313 static const uint8_t ad_cap_announcement[3] = {
4314 BT_UUID_16_ENCODE(BT_UUID_CAS_VAL),
4315 BT_AUDIO_UNICAST_ANNOUNCEMENT_TARGETED,
4316 };
4317
4318 __ASSERT(data_array_size > ad_len, "No space for AD_CAP_ANNOUNCEMENT");
4319 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4320 data_array[ad_len].data_len = ARRAY_SIZE(ad_cap_announcement);
4321 data_array[ad_len].data = &ad_cap_announcement[0];
4322 ad_len++;
4323 }
4324
4325 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
4326 if (default_source.bap_source != NULL && !default_source.is_cap) {
4327 static uint8_t ad_bap_broadcast_announcement[5] = {
4328 BT_UUID_16_ENCODE(BT_UUID_BROADCAST_AUDIO_VAL),
4329 };
4330 uint32_t broadcast_id;
4331 int err;
4332
4333 err = bt_rand(&broadcast_id, BT_AUDIO_BROADCAST_ID_SIZE);
4334 if (err != 0) {
4335 printk("Unable to generate broadcast ID: %d\n", err);
4336
4337 return -1;
4338 }
4339
4340 sys_put_le24(broadcast_id, &ad_bap_broadcast_announcement[2]);
4341 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4342 data_array[ad_len].data_len = ARRAY_SIZE(ad_bap_broadcast_announcement);
4343 data_array[ad_len].data = ad_bap_broadcast_announcement;
4344 ad_len++;
4345 }
4346 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
4347
4348 if (ARRAY_SIZE(ad_ext_uuid16) > 0) {
4349 if (data_array_size <= ad_len) {
4350 shell_warn(ctx_shell, "No space for AD_UUID16");
4351 return ad_len;
4352 }
4353
4354 data_array[ad_len].type = BT_DATA_UUID16_SOME;
4355 data_array[ad_len].data_len = ARRAY_SIZE(ad_ext_uuid16);
4356 data_array[ad_len].data = &ad_ext_uuid16[0];
4357 ad_len++;
4358 }
4359
4360 return ad_len;
4361 }
4362
audio_ad_data_add(struct bt_data * data_array,const size_t data_array_size,const bool discoverable,const bool connectable)4363 ssize_t audio_ad_data_add(struct bt_data *data_array, const size_t data_array_size,
4364 const bool discoverable, const bool connectable)
4365 {
4366 ssize_t ad_len = 0;
4367
4368 if (!discoverable) {
4369 return 0;
4370 }
4371
4372 if (connectable) {
4373 ad_len += connectable_ad_data_add(data_array, data_array_size);
4374 } else {
4375 ad_len += nonconnectable_ad_data_add(data_array, data_array_size);
4376 }
4377
4378 if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
4379 ad_len += cap_initiator_ad_data_add(data_array, data_array_size, discoverable,
4380 connectable);
4381 }
4382
4383 return ad_len;
4384 }
4385
audio_pa_data_add(struct bt_data * data_array,const size_t data_array_size)4386 ssize_t audio_pa_data_add(struct bt_data *data_array,
4387 const size_t data_array_size)
4388 {
4389 size_t ad_len = 0;
4390
4391 #if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
4392 if (default_source.bap_source != NULL && !default_source.is_cap) {
4393 /* Required size of the buffer depends on what has been
4394 * configured. We just use the maximum size possible.
4395 */
4396 NET_BUF_SIMPLE_DEFINE_STATIC(base_buf, UINT8_MAX);
4397 int err;
4398
4399 net_buf_simple_reset(&base_buf);
4400
4401 err = bt_bap_broadcast_source_get_base(default_source.bap_source, &base_buf);
4402 if (err != 0) {
4403 printk("Unable to get BASE: %d\n", err);
4404
4405 return -1;
4406 }
4407
4408 data_array[ad_len].type = BT_DATA_SVC_DATA16;
4409 data_array[ad_len].data_len = base_buf.len;
4410 data_array[ad_len].data = base_buf.data;
4411 ad_len++;
4412 } else if (IS_ENABLED(CONFIG_BT_CAP_INITIATOR)) {
4413 return cap_initiator_pa_data_add(data_array, data_array_size);
4414 }
4415 #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */
4416
4417 return ad_len;
4418 }
4419