1 /**
2 * @file
3 * @brief Bluetooth BAP Broadcast Sink LC3 extension
4 *
5 * This files handles all the LC3 related functionality for the sample
6 *
7 * Copyright (c) 2025 Nordic Semiconductor ASA
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <errno.h>
13 #include <stdbool.h>
14 #include <stddef.h>
15 #include <stdint.h>
16 #include <string.h>
17
18 #include <zephyr/autoconf.h>
19 #include <zephyr/bluetooth/audio/audio.h>
20 #include <zephyr/bluetooth/hci_types.h>
21 #include <zephyr/bluetooth/iso.h>
22 #include <zephyr/device.h>
23 #include <zephyr/devicetree.h>
24 #include <zephyr/kernel.h>
25 #include <zephyr/logging/log.h>
26 #include <zephyr/logging/log_core.h>
27 #include <zephyr/net_buf.h>
28 #include <zephyr/shell/shell.h>
29 #include <zephyr/sys/ring_buffer.h>
30 #include <zephyr/sys/util.h>
31 #include <zephyr/sys/util_macro.h>
32 #include <zephyr/sys_clock.h>
33 #include <zephyr/toolchain.h>
34 #include <zephyr/usb/usb_device.h>
35 #include <zephyr/usb/class/usb_audio.h>
36
37 #include <lc3.h>
38
39 #include "lc3.h"
40 #include "stream_rx.h"
41 #include "usb.h"
42
43 LOG_MODULE_REGISTER(lc3, CONFIG_LOG_DEFAULT_LEVEL);
44
45 #define LC3_ENCODER_STACK_SIZE 4096
46 #define LC3_ENCODER_PRIORITY 5
47
48 struct lc3_data {
49 void *fifo_reserved; /* 1st word reserved for use by FIFO */
50 struct net_buf *buf;
51 struct stream_rx *stream;
52 uint32_t ts;
53 bool do_plc;
54 };
55
56 K_MEM_SLAB_DEFINE_STATIC(lc3_data_slab, sizeof(struct lc3_data), CONFIG_BT_ISO_RX_BUF_COUNT,
57 __alignof__(struct lc3_data));
58
59 static int16_t lc3_rx_buf[LC3_MAX_NUM_SAMPLES_MONO];
60 static K_FIFO_DEFINE(lc3_in_fifo);
61
62 /* We only want to send USB to left/right from a single stream. If we have 2 left streams, the
63 * outgoing audio is going to be terrible.
64 * Since a stream can contain stereo data, both of these may be the same stream.
65 */
66 static struct stream_rx *usb_left_stream;
67 static struct stream_rx *usb_right_stream;
68 static size_t rx_streaming_cnt;
69
init_lc3_decoder(struct stream_rx * stream,uint32_t lc3_frame_duration_us,uint32_t lc3_freq_hz)70 static int init_lc3_decoder(struct stream_rx *stream, uint32_t lc3_frame_duration_us,
71 uint32_t lc3_freq_hz)
72 {
73 if (stream == NULL) {
74 LOG_ERR("NULL stream to init LC3 decoder");
75 return -EINVAL;
76 }
77
78 if (stream->lc3_decoder != NULL) {
79 LOG_ERR("Already initialized");
80 return -EALREADY;
81 }
82
83 if (lc3_freq_hz == 0U || lc3_frame_duration_us == 0U) {
84 LOG_ERR("Invalid freq (%u) or frame duration (%u)", lc3_freq_hz,
85 lc3_frame_duration_us);
86
87 return -EINVAL;
88 }
89
90 LOG_INF("Initializing the LC3 decoder with %u us duration and %u Hz frequency",
91 lc3_frame_duration_us, lc3_freq_hz);
92 /* Create the decoder instance. This shall complete before stream_started() is called. */
93 stream->lc3_decoder =
94 lc3_setup_decoder(lc3_frame_duration_us, lc3_freq_hz,
95 IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE_HZ : 0,
96 &stream->lc3_decoder_mem);
97 if (stream->lc3_decoder == NULL) {
98 LOG_ERR("Failed to setup LC3 decoder - wrong parameters?\n");
99 return -EINVAL;
100 }
101
102 LOG_INF("Initialized LC3 decoder for %p", stream);
103 rx_streaming_cnt++;
104
105 return 0;
106 }
107
decode_frame(struct lc3_data * data,size_t frame_cnt)108 static bool decode_frame(struct lc3_data *data, size_t frame_cnt)
109 {
110 const struct stream_rx *stream = data->stream;
111 const size_t total_frames = stream->lc3_chan_cnt * stream->lc3_frame_blocks_per_sdu;
112 const uint16_t octets_per_frame = stream->lc3_octets_per_frame;
113 struct net_buf *buf = data->buf;
114 void *iso_data;
115 int err;
116
117 if (data->do_plc) {
118 iso_data = NULL; /* perform PLC */
119
120 #if CONFIG_INFO_REPORTING_INTERVAL > 0
121 if ((stream->reporting_info.lc3_decoded_cnt % CONFIG_INFO_REPORTING_INTERVAL) ==
122 0) {
123 LOG_DBG("[%zu]: Performing PLC", stream->reporting_info.lc3_decoded_cnt);
124 }
125 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
126
127 data->do_plc = false; /* clear flag */
128 } else {
129 iso_data = net_buf_pull_mem(data->buf, octets_per_frame);
130
131 #if CONFIG_INFO_REPORTING_INTERVAL > 0
132 if ((stream->reporting_info.lc3_decoded_cnt % CONFIG_INFO_REPORTING_INTERVAL) ==
133 0) {
134 LOG_DBG("[%zu]: Decoding frame of size %u (%u/%u)",
135 stream->reporting_info.lc3_decoded_cnt, octets_per_frame,
136 frame_cnt + 1, total_frames);
137 }
138 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
139 }
140
141 err = lc3_decode(stream->lc3_decoder, iso_data, octets_per_frame, LC3_PCM_FORMAT_S16,
142 lc3_rx_buf, 1);
143 if (err < 0) {
144 LOG_ERR("Failed to decode LC3 data (%u/%u - %u/%u)", frame_cnt + 1, total_frames,
145 octets_per_frame * frame_cnt, buf->len);
146 return false;
147 }
148
149 return true;
150 }
151
get_lc3_chan_alloc_from_index(const struct stream_rx * stream,uint8_t index,enum bt_audio_location * chan_alloc)152 static int get_lc3_chan_alloc_from_index(const struct stream_rx *stream, uint8_t index,
153 enum bt_audio_location *chan_alloc)
154 {
155 #if defined(CONFIG_USB_DEVICE_AUDIO)
156 const bool has_left = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0;
157 const bool has_right = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0;
158 const bool is_mono = stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO;
159 const bool is_left = index == 0 && has_left;
160 const bool is_right = has_right && (index == 0U || (index == 1U && has_left));
161
162 /* LC3 is always Left before Right, so we can use the index and the stream channel
163 * allocation to determine if index 0 is left or right.
164 */
165 if (is_left) {
166 *chan_alloc = BT_AUDIO_LOCATION_FRONT_LEFT;
167 } else if (is_right) {
168 *chan_alloc = BT_AUDIO_LOCATION_FRONT_RIGHT;
169 } else if (is_mono) {
170 *chan_alloc = BT_AUDIO_LOCATION_MONO_AUDIO;
171 } else {
172 /* Not suitable for USB */
173 return -EINVAL;
174 }
175
176 return 0;
177 #else /* !CONFIG_USB_DEVICE_AUDIO */
178 return -EINVAL;
179 #endif /* CONFIG_USB_DEVICE_AUDIO */
180 }
181
decode_frame_block(struct lc3_data * data,size_t frame_cnt)182 static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt)
183 {
184 const struct stream_rx *stream = data->stream;
185 const uint8_t chan_cnt = stream->lc3_chan_cnt;
186 size_t decoded_frames = 0U;
187
188 for (uint8_t i = 0U; i < chan_cnt; i++) {
189 /* We provide the total number of decoded frames to `decode_frame` for logging
190 * purposes
191 */
192 if (decode_frame(data, frame_cnt + decoded_frames)) {
193 decoded_frames++;
194
195 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
196 enum bt_audio_location chan_alloc;
197 int err;
198
199 err = get_lc3_chan_alloc_from_index(stream, i, &chan_alloc);
200 if (err != 0) {
201 /* Not suitable for USB */
202 continue;
203 }
204
205 /* We only want to left or right from one stream to USB */
206 if ((chan_alloc == BT_AUDIO_LOCATION_FRONT_LEFT &&
207 stream != usb_left_stream) ||
208 (chan_alloc == BT_AUDIO_LOCATION_FRONT_RIGHT &&
209 stream != usb_right_stream)) {
210 continue;
211 }
212
213 /* TODO: Add support for properly support the presentation delay.
214 * For now we just send audio to USB as soon as we get it
215 */
216 err = usb_add_frame_to_usb(chan_alloc, lc3_rx_buf,
217 sizeof(lc3_rx_buf), data->ts);
218 if (err == -EINVAL) {
219 continue;
220 }
221 }
222 } else {
223 /* If decoding failed, we clear the data to USB as it would contain
224 * invalid data
225 */
226 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
227 usb_clear_frames_to_usb();
228 }
229
230 break;
231 }
232 }
233
234 return decoded_frames;
235 }
236
do_lc3_decode(struct lc3_data * data)237 static void do_lc3_decode(struct lc3_data *data)
238 {
239 struct stream_rx *stream = data->stream;
240
241 if (stream->lc3_decoder != NULL) {
242 const uint8_t frame_blocks_per_sdu = stream->lc3_frame_blocks_per_sdu;
243 size_t frame_cnt;
244
245 frame_cnt = 0;
246 for (uint8_t i = 0U; i < frame_blocks_per_sdu; i++) {
247 const size_t decoded_frames = decode_frame_block(data, frame_cnt);
248
249 if (decoded_frames == 0) {
250 break;
251 }
252
253 frame_cnt += decoded_frames;
254 }
255
256 #if CONFIG_INFO_REPORTING_INTERVAL > 0
257 stream->reporting_info.lc3_decoded_cnt++;
258 #endif /* CONFIG_INFO_REPORTING_INTERVAL > 0 */
259 }
260
261 net_buf_unref(data->buf);
262 }
263
lc3_decoder_thread_func(void * arg1,void * arg2,void * arg3)264 static void lc3_decoder_thread_func(void *arg1, void *arg2, void *arg3)
265 {
266 while (true) {
267 struct lc3_data *data = k_fifo_get(&lc3_in_fifo, K_FOREVER);
268 struct stream_rx *stream = data->stream;
269
270 if (stream->lc3_decoder == NULL) {
271 LOG_WRN("Decoder is NULL, discarding data from FIFO");
272 k_mem_slab_free(&lc3_data_slab, (void *)data);
273 continue; /* Wait for new data */
274 }
275
276 do_lc3_decode(data);
277
278 k_mem_slab_free(&lc3_data_slab, (void *)data);
279 }
280 }
281
lc3_enable(struct stream_rx * stream)282 int lc3_enable(struct stream_rx *stream)
283 {
284 const struct bt_audio_codec_cfg *codec_cfg = stream->stream.codec_cfg;
285 uint32_t lc3_frame_duration_us;
286 uint32_t lc3_freq_hz;
287 int ret;
288
289 if (codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) {
290 return -EINVAL;
291 }
292
293 ret = bt_audio_codec_cfg_get_freq(codec_cfg);
294 if (ret >= 0) {
295 ret = bt_audio_codec_cfg_freq_to_freq_hz(ret);
296
297 if (ret > 0) {
298 if (ret == 8000 || ret == 16000 || ret == 24000 || ret == 32000 ||
299 ret == 48000) {
300 lc3_freq_hz = (uint32_t)ret;
301 } else {
302 LOG_ERR("Unsupported frequency for LC3: %d", ret);
303 lc3_freq_hz = 0U;
304 }
305 } else {
306 LOG_ERR("Invalid frequency: %d", ret);
307 lc3_freq_hz = 0U;
308 }
309 } else {
310 LOG_ERR("Could not get frequency: %d", ret);
311 lc3_freq_hz = 0U;
312 }
313
314 if (lc3_freq_hz == 0U) {
315 return -EINVAL;
316 }
317
318 ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
319 if (ret >= 0) {
320 ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
321 if (ret > 0) {
322 lc3_frame_duration_us = (uint32_t)ret;
323 } else {
324 LOG_ERR("Invalid frame duration: %d", ret);
325 lc3_frame_duration_us = 0U;
326 }
327 } else {
328 LOG_ERR("Could not get frame duration: %d", ret);
329 lc3_frame_duration_us = 0U;
330 }
331
332 if (lc3_frame_duration_us == 0U) {
333 return -EINVAL;
334 }
335
336 ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, &stream->lc3_chan_allocation, true);
337 if (ret == 0) {
338 stream->lc3_chan_cnt = bt_audio_get_chan_count(stream->lc3_chan_allocation);
339 } else {
340 LOG_DBG("Could not get channel allocation: %d", ret);
341 stream->lc3_chan_cnt = 0U;
342 }
343
344 if (stream->lc3_chan_cnt == 0U) {
345 return -EINVAL;
346 }
347
348 ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
349 if (ret >= 0) {
350 stream->lc3_frame_blocks_per_sdu = (uint8_t)ret;
351 } else {
352 LOG_ERR("Could not get frame blocks per SDU: %d", ret);
353 stream->lc3_frame_blocks_per_sdu = 0U;
354 }
355
356 if (stream->lc3_frame_blocks_per_sdu == 0U) {
357 return -EINVAL;
358 }
359
360 ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
361 if (ret >= 0) {
362 stream->lc3_octets_per_frame = (uint16_t)ret;
363 } else {
364 LOG_ERR("Could not get octets per frame: %d", ret);
365 stream->lc3_octets_per_frame = 0U;
366 }
367
368 if (stream->lc3_octets_per_frame == 0U) {
369 return -EINVAL;
370 }
371
372 if (stream->lc3_decoder == NULL) {
373 const int err = init_lc3_decoder(stream, lc3_frame_duration_us, lc3_freq_hz);
374
375 if (err != 0) {
376 LOG_ERR("Failed to init LC3 decoder: %d", err);
377
378 return err;
379 }
380 }
381
382 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
383 if ((stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) {
384 if (usb_left_stream == NULL) {
385 LOG_INF("Setting USB left stream to %p", stream);
386 usb_left_stream = stream;
387 } else {
388 LOG_WRN("Multiple left streams started");
389 }
390 }
391
392 if ((stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0) {
393 if (usb_right_stream == NULL) {
394 LOG_INF("Setting USB right stream to %p", stream);
395 usb_right_stream = stream;
396 } else {
397 LOG_WRN("Multiple right streams started");
398 }
399 }
400 }
401
402 return 0;
403 }
404
lc3_disable(struct stream_rx * stream)405 int lc3_disable(struct stream_rx *stream)
406 {
407 if (rx_streaming_cnt == 0 || stream->lc3_decoder == NULL) {
408 return -EINVAL;
409 }
410
411 stream->lc3_decoder = NULL;
412 rx_streaming_cnt--;
413
414 if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) {
415 if (usb_left_stream == stream) {
416 usb_left_stream = NULL;
417 }
418 if (usb_right_stream == stream) {
419 usb_right_stream = NULL;
420 }
421 }
422
423 return 0;
424 }
425
lc3_enqueue_for_decoding(struct stream_rx * stream,const struct bt_iso_recv_info * info,struct net_buf * buf)426 void lc3_enqueue_for_decoding(struct stream_rx *stream, const struct bt_iso_recv_info *info,
427 struct net_buf *buf)
428 {
429 const uint8_t frame_blocks_per_sdu = stream->lc3_frame_blocks_per_sdu;
430 const uint16_t octets_per_frame = stream->lc3_octets_per_frame;
431 const uint8_t chan_cnt = stream->lc3_chan_cnt;
432 struct lc3_data *data;
433
434 if (stream->lc3_decoder == NULL) {
435 return;
436 }
437
438 /* Allocate a context that holds both the buffer and the stream so that we can
439 * send both of these values to the LC3 decoder thread as a single struct
440 * in a FIFO
441 */
442 if (k_mem_slab_alloc(&lc3_data_slab, (void **)&data, K_NO_WAIT)) {
443 LOG_WRN("Could not allocate LC3 data item");
444 return;
445 }
446
447 if ((info->flags & BT_ISO_FLAGS_VALID) == 0) {
448 data->do_plc = true;
449 } else if (buf->len != (octets_per_frame * chan_cnt * frame_blocks_per_sdu)) {
450 if (buf->len != 0U) {
451 LOG_WRN("Expected %u frame blocks with %u channels of size %u, but "
452 "length is %u",
453 frame_blocks_per_sdu, chan_cnt, octets_per_frame, buf->len);
454 }
455
456 data->do_plc = true;
457 }
458
459 data->buf = net_buf_ref(buf);
460 data->stream = stream;
461 if (info->flags & BT_ISO_FLAGS_TS) {
462 data->ts = info->ts;
463 } else {
464 data->ts = 0U;
465 }
466
467 k_fifo_put(&lc3_in_fifo, data);
468 }
469
lc3_init(void)470 int lc3_init(void)
471 {
472 static K_KERNEL_STACK_DEFINE(lc3_decoder_thread_stack, 4096);
473 const int lc3_decoder_thread_prio = K_PRIO_PREEMPT(5);
474 static struct k_thread lc3_decoder_thread;
475 static bool initialized;
476
477 if (initialized) {
478 return -EALREADY;
479 }
480
481 k_thread_create(&lc3_decoder_thread, lc3_decoder_thread_stack,
482 K_KERNEL_STACK_SIZEOF(lc3_decoder_thread_stack), lc3_decoder_thread_func,
483 NULL, NULL, NULL, lc3_decoder_thread_prio, 0, K_NO_WAIT);
484 k_thread_name_set(&lc3_decoder_thread, "LC3 Decoder");
485
486 LOG_INF("LC3 initialized");
487 initialized = true;
488
489 return 0;
490 }
491
lc3_get_rx_streaming_cnt(void)492 size_t lc3_get_rx_streaming_cnt(void)
493 {
494 return rx_streaming_cnt;
495 }
496