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