From b4eac67b8b2eee5381d58671fddb8ae9bf2a3989 Mon Sep 17 00:00:00 2001 From: Emil Gydesen Date: Tue, 13 Feb 2024 10:19:15 +0100 Subject: [PATCH] Bluetooth: BAP: Shell: Add support for decoding LC3 data Add support for decoding incoming LC3 data. At this point we only instantiate a single LC3 decoder, so only one frequency and duration is supported. To accomodate for the increased RAM usage, the number of unicast streams support have been decreased. Further more, the LC3 handling in the shell has overall been improved, also for encoding. Signed-off-by: Emil Gydesen --- subsys/bluetooth/audio/shell/audio.h | 20 +- subsys/bluetooth/audio/shell/bap.c | 445 +++++++++++++++++++++------ 2 files changed, 372 insertions(+), 93 deletions(-) diff --git a/subsys/bluetooth/audio/shell/audio.h b/subsys/bluetooth/audio/shell/audio.h index 5ae4dfbc7fb1aa..666ab59c079276 100644 --- a/subsys/bluetooth/audio/shell/audio.h +++ b/subsys/bluetooth/audio/shell/audio.h @@ -46,6 +46,10 @@ ssize_t cap_initiator_pa_data_add(struct bt_data *data_array, const size_t data_ #include #include +#if defined(CONFIG_LIBLC3) +#include "lc3.h" +#endif /* CONFIG_LIBLC3 */ + #define LOCATION BT_AUDIO_LOCATION_FRONT_LEFT | BT_AUDIO_LOCATION_FRONT_RIGHT #define CONTEXT \ (BT_AUDIO_CONTEXT_TYPE_UNSPECIFIED | BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL | \ @@ -67,12 +71,16 @@ struct shell_stream { struct bt_cap_stream stream; struct bt_audio_codec_cfg codec_cfg; struct bt_audio_codec_qos qos; + #if defined(CONFIG_LIBLC3) uint32_t lc3_freq_hz; uint32_t lc3_frame_duration_us; uint16_t lc3_octets_per_frame; - uint8_t lc3_frames_per_sdu; + uint8_t lc3_frame_blocks_per_sdu; + enum bt_audio_location lc3_chan_allocation; + uint8_t lc3_chan_cnt; #endif /* CONFIG_LIBLC3 */ + #if defined(CONFIG_BT_AUDIO_TX) int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */ uint16_t seq_num; @@ -83,6 +91,7 @@ struct shell_stream { size_t lc3_sdu_cnt; #endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_TX */ + #if defined(CONFIG_BT_AUDIO_RX) struct bt_iso_recv_info last_info; size_t empty_sdu_pkts; @@ -91,6 +100,11 @@ struct shell_stream { size_t dup_psn; size_t rx_cnt; size_t dup_ts; +#if defined(CONFIG_LIBLC3) + lc3_decoder_mem_48k_t lc3_decoder_mem; + lc3_decoder_t lc3_decoder; + size_t decoded_cnt; +#endif /* CONFIG_LIBLC3 */ #endif /* CONFIG_BT_AUDIO_RX */ }; @@ -131,8 +145,8 @@ struct broadcast_sink { CONFIG_BT_BAP_UNICAST_CLIENT_ASE_SRC_COUNT), \ (0)) -extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * (UNICAST_SERVER_STREAM_COUNT + - UNICAST_CLIENT_STREAM_COUNT)]; +extern struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * MAX(UNICAST_SERVER_STREAM_COUNT, + UNICAST_CLIENT_STREAM_COUNT)]; #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) diff --git a/subsys/bluetooth/audio/shell/bap.c b/subsys/bluetooth/audio/shell/bap.c index f5609784ccdd23..d42584fec68939 100644 --- a/subsys/bluetooth/audio/shell/bap.c +++ b/subsys/bluetooth/audio/shell/bap.c @@ -27,25 +27,39 @@ #include #include +#include "shell/bt.h" +#include "audio.h" + +/* Determines if we can initiate streaming */ +#define IS_BAP_INITIATOR \ + (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) || IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) + #if defined(CONFIG_LIBLC3) -#include "lc3.h" #define LC3_MAX_SAMPLE_RATE 48000 #define LC3_MAX_FRAME_DURATION_US 10000 #define LC3_MAX_NUM_SAMPLES ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE) / USEC_PER_SEC) -#endif /* CONFIG_LIBLC3 */ -#include "shell/bt.h" -#include "audio.h" +static void clear_lc3_sine_data(struct bt_bap_stream *bap_stream); +static void lc3_decoder_stream_clear(struct shell_stream *sh_stream); -/* Determines if we can initiate streaming */ -#define IS_BAP_INITIATOR \ - (IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SOURCE) || IS_ENABLED(CONFIG_BT_BAP_UNICAST_CLIENT)) +static void lc3_clear_stream(struct shell_stream *sh_stream) +{ +#if defined(CONFIG_BT_AUDIO_TX) + clear_lc3_sine_data(&sh_stream->stream.bap_stream); +#endif /* CONFIG_BT_AUDIO_TX */ + +#if defined(CONFIG_BT_AUDIO_RX) + lc3_decoder_stream_clear(sh_stream); +#endif /* CONFIG_BT_AUDIO_RX */ +} + +#endif /* CONFIG_LIBLC3 */ #if defined(CONFIG_BT_BAP_UNICAST) struct shell_stream unicast_streams[CONFIG_BT_MAX_CONN * - (UNICAST_SERVER_STREAM_COUNT + UNICAST_CLIENT_STREAM_COUNT)]; + MAX(UNICAST_SERVER_STREAM_COUNT, UNICAST_CLIENT_STREAM_COUNT)]; #if defined(CONFIG_BT_BAP_UNICAST_CLIENT) struct bt_bap_unicast_group *default_unicast_group; @@ -197,8 +211,8 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream) * controller ISO buffer to handle jitter. */ #define PRIME_COUNT 2U -NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, - BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), +#define SINE_TX_POOL_SIZE BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU) +NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT, SINE_TX_POOL_SIZE, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL); #include "math.h" @@ -287,7 +301,8 @@ static void lc3_audio_send_data(struct k_work *work) struct shell_stream *sh_stream = CONTAINER_OF(k_work_delayable_from_work(work), struct shell_stream, audio_send_work); struct bt_bap_stream *bap_stream = bap_stream_from_shell_stream(sh_stream); - const uint16_t tx_sdu_len = sh_stream->lc3_frames_per_sdu * sh_stream->lc3_octets_per_frame; + const uint16_t tx_sdu_len = sh_stream->lc3_frame_blocks_per_sdu * sh_stream->lc3_chan_cnt * + sh_stream->lc3_octets_per_frame; struct net_buf *buf; uint8_t *net_buffer; off_t offset = 0; @@ -308,11 +323,13 @@ static void lc3_audio_send_data(struct k_work *work) return; } - if (tx_sdu_len == 0U) { - shell_error( - ctx_shell, - "Cannot send 0 length SDU (from frames per sdu %u and %u octets per frame)", - sh_stream->lc3_frames_per_sdu, sh_stream->lc3_octets_per_frame); + if (tx_sdu_len == 0U || tx_sdu_len > SINE_TX_POOL_SIZE) { + shell_error(ctx_shell, + "Cannot send %u length SDU (from frame blocks per sdu %u, channel " + "count %u and %u octets per frame) for pool size %d", + tx_sdu_len, sh_stream->lc3_frame_blocks_per_sdu, + sh_stream->lc3_chan_cnt, sh_stream->lc3_octets_per_frame, + SINE_TX_POOL_SIZE); return; } @@ -331,22 +348,24 @@ static void lc3_audio_send_data(struct k_work *work) net_buffer = net_buf_tail(buf); buf->len += tx_sdu_len; - for (uint8_t i = 0U; i < sh_stream->lc3_frames_per_sdu; i++) { - int lc3_ret; + for (uint8_t i = 0U; i < sh_stream->lc3_frame_blocks_per_sdu; i++) { + for (uint8_t j = 0U; j < sh_stream->lc3_chan_cnt; j++) { + int lc3_ret; - lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, lc3_tx_buf, 1, - sh_stream->lc3_octets_per_frame, net_buffer + offset); - offset += sh_stream->lc3_octets_per_frame; + lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, lc3_tx_buf, 1, + sh_stream->lc3_octets_per_frame, net_buffer + offset); + offset += sh_stream->lc3_octets_per_frame; - if (lc3_ret == -1) { - shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", - lc3_ret); - net_buf_unref(buf); + if (lc3_ret == -1) { + shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d", + lc3_ret); + net_buf_unref(buf); - /* Reschedule for next interval */ - k_work_reschedule(k_work_delayable_from_work(work), - K_USEC(bap_stream->qos->interval)); - return; + /* Reschedule for next interval */ + k_work_reschedule(k_work_delayable_from_work(work), + K_USEC(bap_stream->qos->interval)); + return; + } } } @@ -2336,6 +2355,154 @@ static struct bt_le_scan_cb bap_scan_cb = { #if defined(CONFIG_BT_AUDIO_RX) static unsigned long recv_stats_interval = 100U; +#if defined(CONFIG_LIBLC3) +struct lc3_data { + void *fifo_reserved; /* 1st word reserved for use by FIFO */ + struct net_buf *buf; + struct shell_stream *sh_stream; +}; + +K_MEM_SLAB_DEFINE(lc3_data_slab, sizeof(struct lc3_data), CONFIG_BT_ISO_RX_BUF_COUNT, + __alignof__(struct lc3_data)); + +static int16_t lc3_rx_buf[LC3_MAX_NUM_SAMPLES]; +static K_FIFO_DEFINE(lc3_in_fifo); + +static int init_lc3_decoder(struct shell_stream *sh_stream) +{ + if (sh_stream == NULL) { + shell_error(ctx_shell, "invalid stream to init LC3"); + return -EINVAL; + } + + if (sh_stream->lc3_decoder != NULL) { + shell_error(ctx_shell, "Already initialized"); + return -EALREADY; + } + + if (sh_stream->lc3_freq_hz == 0 || sh_stream->lc3_frame_duration_us == 0) { + shell_error(ctx_shell, "Invalid freq (%u) or frame duration (%u)", + sh_stream->lc3_freq_hz, sh_stream->lc3_frame_duration_us); + + return -EINVAL; + } + + shell_print(ctx_shell, + "Initializing the LC3 decoder with %u us duration and %u Hz frequency", + sh_stream->lc3_frame_duration_us, sh_stream->lc3_freq_hz); + /* Create the decoder instance. This shall complete before stream_started() is called. */ + sh_stream->lc3_decoder = lc3_setup_decoder(sh_stream->lc3_frame_duration_us, + sh_stream->lc3_freq_hz, 0, /* No resampling */ + &sh_stream->lc3_decoder_mem); + if (sh_stream->lc3_decoder == NULL) { + shell_error(ctx_shell, "Failed to setup LC3 decoder - wrong parameters?\n"); + return -EINVAL; + } + + return 0; +} + +static void lc3_decoder_stream_clear(struct shell_stream *sh_stream) +{ + sh_stream->lc3_decoder = NULL; +} + +static bool decode_frame(struct net_buf *buf, struct shell_stream *sh_stream, size_t frame_cnt) +{ + const size_t total_frames = sh_stream->lc3_chan_cnt * sh_stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame; + void *data; + int err; + + if (buf->len == 0U) { + data = NULL; /* perform PLC */ + + if ((sh_stream->decoded_cnt % recv_stats_interval) == 0) { + shell_print(ctx_shell, "[%zu]: Performing PLC", sh_stream->decoded_cnt); + } + } else { + data = net_buf_pull_mem(buf, octets_per_frame); + + if ((sh_stream->decoded_cnt % recv_stats_interval) == 0) { + shell_print(ctx_shell, "[%zu]: Decoding frame of size %u (%u/%u)", + sh_stream->decoded_cnt, octets_per_frame, frame_cnt + 1, + total_frames); + } + } + + err = lc3_decode(sh_stream->lc3_decoder, data, octets_per_frame, LC3_PCM_FORMAT_S16, + lc3_rx_buf, 1); + if (err < 0) { + shell_error(ctx_shell, "Failed to decode LC3 data (%u/%u - %u/%u)", frame_cnt + 1, + total_frames, octets_per_frame * frame_cnt, buf->len); + return false; + } + + return true; +} + +static size_t decode_frame_block(struct net_buf *buf, struct shell_stream *sh_stream, + size_t frame_cnt) +{ + const uint8_t chan_cnt = sh_stream->lc3_chan_cnt; + size_t decoded_frames = 0U; + + for (uint8_t j = 0U; j < chan_cnt; j++) { + /* We provide the total number of decoded frames to `decode_frame` for logging + * purposes + */ + if (!decode_frame(buf, sh_stream, frame_cnt + decoded_frames)) { + break; + } + + decoded_frames++; + } + + return decoded_frames; +} + +static void do_lc3_decode(struct shell_stream *sh_stream, struct net_buf *buf) +{ + if (sh_stream->lc3_decoder != NULL) { + const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu; + size_t frame_cnt; + + frame_cnt = 0; + for (uint8_t i = 0U; i < frame_blocks_per_sdu; i++) { + const size_t decoded_frames = decode_frame_block(buf, sh_stream, frame_cnt); + + if (decoded_frames == 0) { + break; + } + + frame_cnt += decoded_frames; + } + + sh_stream->decoded_cnt++; + } + + net_buf_unref(buf); +} + +static void lc3_decoder_thread_func(void *arg1, void *arg2, void *arg3) +{ + while (true) { + struct lc3_data *data = k_fifo_get(&lc3_in_fifo, K_FOREVER); + + /* Lock to avoid `lc3_decoder` becoming NULL in case of a stream stop */ + + if (data->sh_stream->lc3_decoder == NULL) { + continue; /* Wait for new data */ + } + + do_lc3_decode(data->sh_stream, data->buf); + + k_mem_slab_free(&lc3_data_slab, (void *)data); + } +} + +#endif /* CONFIG_LIBLC3*/ + static void audio_recv(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info, struct net_buf *buf) @@ -2379,6 +2546,43 @@ static void audio_recv(struct bt_bap_stream *stream, } (void)memcpy(&sh_stream->last_info, info, sizeof(sh_stream->last_info)); + +#if defined(CONFIG_LIBLC3) + if (sh_stream->lc3_decoder != NULL) { + const uint8_t frame_blocks_per_sdu = sh_stream->lc3_frame_blocks_per_sdu; + const uint16_t octets_per_frame = sh_stream->lc3_octets_per_frame; + const uint8_t chan_cnt = sh_stream->lc3_chan_cnt; + struct lc3_data *data; + + /* Allocate a context that holds both the buffer and the stream so that we can + * send both of these values to the LC3 decoder thread as a single struct + * in a FIFO + */ + if (k_mem_slab_alloc(&lc3_data_slab, (void **)&data, K_NO_WAIT)) { + shell_warn(ctx_shell, "Could not allocate LC3 data item"); + + return; + } + + if ((info->flags & BT_ISO_FLAGS_VALID) == 0) { + buf->len = 0U; /* Set length to 0 to mark it as invalid for PLC */ + } else if (buf->len != (octets_per_frame * chan_cnt * frame_blocks_per_sdu)) { + if (buf->len != 0U) { + shell_error( + ctx_shell, + "Expected %u frame blocks with %u channels of size %u, but " + "length is %u", + frame_blocks_per_sdu, chan_cnt, octets_per_frame, buf->len); + buf->len = 0U; /* Set length to 0 to mark it as invalid for PLC */ + } + } + + data->buf = net_buf_ref(buf); + data->sh_stream = sh_stream; + + k_fifo_put(&lc3_in_fifo, data); + } +#endif /* CONFIG_LIBLC3 */ } #endif /* CONFIG_BT_AUDIO_RX */ @@ -2421,69 +2625,47 @@ static void stream_enabled_cb(struct bt_bap_stream *stream) } #endif /* CONFIG_BT_BAP_UNICAST */ -static void stream_started_cb(struct bt_bap_stream *bap_stream) +#if defined(CONFIG_LIBLC3) +static uint8_t get_chan_cnt(enum bt_audio_location chan_allocation) { - struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); + uint8_t cnt = 0U; -#if defined(CONFIG_BT_AUDIO_TX) - sh_stream->connected_at_ticks = k_uptime_ticks(); -#if defined(CONFIG_LIBLC3) - atomic_set(&sh_stream->lc3_enqueue_cnt, PRIME_COUNT); - sh_stream->lc3_sdu_cnt = 0U; -#endif /* CONFIG_LIBLC3 */ -#endif /* CONFIG_BT_AUDIO_TX */ + if (chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) { + return 1; + } - printk("Stream %p started\n", bap_stream); + while (chan_allocation != 0) { + cnt += chan_allocation & 1U; + chan_allocation >>= 1; + } -#if defined(CONFIG_BT_AUDIO_RX) - sh_stream->empty_sdu_pkts = 0U; - sh_stream->lost_pkts = 0U; - sh_stream->err_pkts = 0U; - sh_stream->dup_psn = 0U; - sh_stream->rx_cnt = 0U; - sh_stream->dup_ts = 0U; -#endif + return cnt; } +#endif /* CONFIG_LIBLC3 */ -static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +static void stream_started_cb(struct bt_bap_stream *bap_stream) { - printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream); -#if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX) - clear_lc3_sine_data(stream); -#endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX*/ + printk("Stream %p started\n", bap_stream); -#if defined(CONFIG_BT_BAP_BROADCAST_SINK) - struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); +#if defined(CONFIG_LIBLC3) + const struct bt_audio_codec_cfg *codec_cfg = bap_stream->codec_cfg; - if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) { - if (default_broadcast_sink.stream_cnt != 0) { - default_broadcast_sink.stream_cnt--; - } + if (codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { + struct bt_bap_ep_info info = {0}; + int ret; - if (default_broadcast_sink.stream_cnt == 0) { - /* All streams in the broadcast sink has been terminated */ - default_broadcast_sink.syncable = true; - memset(&default_broadcast_sink.received_base, 0, - sizeof(default_broadcast_sink.received_base)); - default_broadcast_sink.broadcast_id = 0; - default_broadcast_sink.syncable = false; + ret = bt_bap_ep_get_info(bap_stream->ep, &info); + if (ret != 0) { + shell_error(ctx_shell, "Failed to get EP info: %d", ret); } - } -#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ -} -#if defined(CONFIG_BT_BAP_UNICAST) -static void stream_configured_cb(struct bt_bap_stream *stream, - const struct bt_audio_codec_qos_pref *pref) -{ -#if defined(CONFIG_LIBLC3) - if (stream->codec_cfg->id == BT_HCI_CODING_FORMAT_LC3) { - struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); - int ret; + atomic_set(&sh_stream->lc3_enqueue_cnt, PRIME_COUNT); + sh_stream->lc3_sdu_cnt = 0U; - ret = bt_audio_codec_cfg_get_freq(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_freq(codec_cfg); + if (ret >= 0) { ret = bt_audio_codec_cfg_freq_to_freq_hz(ret); if (ret > 0) { @@ -2504,8 +2686,8 @@ static void stream_configured_cb(struct bt_bap_stream *stream, sh_stream->lc3_freq_hz = 0U; } - ret = bt_audio_codec_cfg_get_frame_dur(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg); + if (ret >= 0) { ret = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret); if (ret > 0) { sh_stream->lc3_frame_duration_us = (uint32_t)ret; @@ -2518,24 +2700,96 @@ static void stream_configured_cb(struct bt_bap_stream *stream, sh_stream->lc3_frame_duration_us = 0U; } - ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true); - if (ret > 0) { - sh_stream->lc3_frames_per_sdu = (uint8_t)ret; + ret = bt_audio_codec_cfg_get_chan_allocation(codec_cfg, + &sh_stream->lc3_chan_allocation); + if (ret == 0) { + sh_stream->lc3_chan_cnt = get_chan_cnt(sh_stream->lc3_chan_allocation); + } else { + shell_error(ctx_shell, "Could not get channel allocation: %d", ret); + sh_stream->lc3_chan_allocation = BT_AUDIO_LOCATION_MONO_AUDIO; + sh_stream->lc3_chan_cnt = 1U; + } + + ret = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true); + if (ret >= 0) { + sh_stream->lc3_frame_blocks_per_sdu = (uint8_t)ret; } else { shell_error(ctx_shell, "Could not get frame blocks per SDU: %d", ret); - sh_stream->lc3_frames_per_sdu = 0U; + sh_stream->lc3_frame_blocks_per_sdu = 0U; } - ret = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg); - if (ret > 0) { + ret = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg); + if (ret >= 0) { sh_stream->lc3_octets_per_frame = (uint16_t)ret; } else { shell_error(ctx_shell, "Could not get octets per frame: %d", ret); sh_stream->lc3_octets_per_frame = 0U; } + +#if defined(CONFIG_BT_AUDIO_RX) + if (info.can_recv) { + if (sh_stream->lc3_decoder == NULL) { + const int err = init_lc3_decoder(sh_stream); + + if (err != 0) { + shell_error(ctx_shell, "Failed to init the LC3 decoder: %d", + err); + + return; + } + } + + sh_stream->decoded_cnt = 0U; +#endif /* CONFIG_BT_AUDIO_RX */ + } } #endif /* CONFIG_LIBLC3 */ +#if defined(CONFIG_BT_AUDIO_TX) + sh_stream->connected_at_ticks = k_uptime_ticks(); +#endif /* CONFIG_BT_AUDIO_TX */ + +#if defined(CONFIG_BT_AUDIO_RX) + sh_stream->empty_sdu_pkts = 0U; + sh_stream->lost_pkts = 0U; + sh_stream->err_pkts = 0U; + sh_stream->dup_psn = 0U; + sh_stream->rx_cnt = 0U; + sh_stream->dup_ts = 0U; +#endif +} + +static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason) +{ + printk("Stream %p stopped with reason 0x%02X\n", stream, reason); + +#if defined(CONFIG_LIBLC3) + lc3_clear_stream(shell_stream_from_bap_stream(stream)); +#endif /* CONFIG_LIBLC3 */ + +#if defined(CONFIG_BT_BAP_BROADCAST_SINK) + struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream); + + if (IS_ARRAY_ELEMENT(broadcast_sink_streams, sh_stream)) { + if (default_broadcast_sink.stream_cnt != 0) { + default_broadcast_sink.stream_cnt--; + } + + if (default_broadcast_sink.stream_cnt == 0) { + /* All streams in the broadcast sink has been terminated */ + memset(&default_broadcast_sink.received_base, 0, + sizeof(default_broadcast_sink.received_base)); + default_broadcast_sink.broadcast_id = 0; + default_broadcast_sink.syncable = false; + } + } +#endif /* CONFIG_BT_BAP_BROADCAST_SINK */ +} + +#if defined(CONFIG_BT_BAP_UNICAST) +static void stream_configured_cb(struct bt_bap_stream *stream, + const struct bt_audio_codec_qos_pref *pref) +{ shell_print(ctx_shell, "Stream %p configured\n", stream); } @@ -2580,10 +2834,9 @@ static void stream_released_cb(struct bt_bap_stream *stream) } #endif /* CONFIG_BT_BAP_UNICAST_CLIENT */ -#if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_TX) - /* stop sending */ - clear_lc3_sine_data(stream); -#endif /* CONFIG_LIBLC3 && defined(CONFIG_BT_AUDIO_TX) */ +#if defined(CONFIG_LIBLC3) + lc3_clear_stream(shell_stream_from_bap_stream(stream)); +#endif /* CONFIG_LIBLC3 */ } #endif /* CONFIG_BT_BAP_UNICAST */ @@ -3160,6 +3413,18 @@ static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) } #endif /* CONFIG_BT_BAP_BROADCAST_SOURCE */ +#if defined(CONFIG_LIBLC3) && defined(CONFIG_BT_AUDIO_RX) + static K_KERNEL_STACK_DEFINE(lc3_decoder_thread_stack, 4096); + /* make it slightly lower priority than the RX thread */ + int lc3_decoder_thread_prio = K_PRIO_COOP(CONFIG_BT_RX_PRIO + 1); + static struct k_thread lc3_decoder_thread; + + k_thread_create(&lc3_decoder_thread, lc3_decoder_thread_stack, + K_KERNEL_STACK_SIZEOF(lc3_decoder_thread_stack), lc3_decoder_thread_func, + NULL, NULL, NULL, lc3_decoder_thread_prio, 0, K_NO_WAIT); + k_thread_name_set(&lc3_decoder_thread, "LC3 Decode"); +#endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_RX */ + initialized = true; return 0;