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