Bluetooth: BAP: Shell: Add support for multiple TX streams

Add support for transmitting on multiple streams, e.g.
with the simple `send` command or with the sine generator.

This extends the start and stop sine to take a "all"
paramter to start sending on all streams.

This also fixes an issue with the seq_num when multiple
streams are transmitting, since the timing may get delayed
which then delays the seq_num which are then scheduled too late.
The fix here is to only use the timer for the inital sequence
number when starting to send the sine way, and then increment it
per TX.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-07-03 21:41:38 +02:00 committed by Fabio Baltieri
commit 983864e4d8
2 changed files with 279 additions and 140 deletions

View file

@ -59,9 +59,23 @@ struct shell_stream {
struct bt_audio_codec_cfg codec_cfg;
struct bt_audio_codec_qos qos;
#if defined(CONFIG_BT_AUDIO_TX)
int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */
uint16_t last_allocated_seq_num; /* The last packet sequence number allocated */
int64_t connected_at_ticks; /* The uptime tick measured when stream was connected */
uint16_t seq_num;
struct k_work_delayable audio_send_work;
bool tx_active;
#if defined(CONFIG_LIBLC3)
atomic_t lc3_enqueue_cnt;
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 lost_pkts;
size_t err_pkts;
size_t dup_psn;
size_t rx_cnt;
size_t dup_ts;
#endif /* CONFIG_BT_AUDIO_RX */
};
struct broadcast_source {

View file

@ -140,14 +140,20 @@ const struct named_lc3_preset *default_source_preset = &lc3_unicast_presets[3];
static const struct named_lc3_preset *default_broadcast_source_preset = &lc3_broadcast_presets[3];
static bool initialized;
#if defined(CONFIG_BT_AUDIO_TX)
static struct bt_bap_stream *txing_stream;
static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream)
static struct shell_stream *shell_stream_from_bap_stream(struct bt_bap_stream *bap_stream)
{
struct bt_cap_stream *cap_stream =
CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream);
return sh_stream;
}
#if defined(CONFIG_BT_AUDIO_TX)
static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream)
{
struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
const uint32_t interval_us = bap_stream->qos->interval;
int64_t uptime_ticks;
int64_t delta_ticks;
@ -162,20 +168,6 @@ static uint16_t get_next_seq_num(struct bt_bap_stream *bap_stream)
/* Calculate the sequence number by dividing the stream uptime by the SDU interval */
seq_num = (uint16_t)(delta_us / interval_us);
/* In the case that we call this multiple times, we need to account for any sequence numbers
* already allocated and send to the controller. Ensuring that the next PSN is 1 higher than
* the last we allocated (assuming that we it was actually sent to the controller).
*
* The additional condition that checks that the difference is smaller than a specific value
* is used to handle the case where seq_num has wrapped.
*/
if (seq_num <= sh_stream->last_allocated_seq_num &&
sh_stream->last_allocated_seq_num - seq_num < 100) {
seq_num = sh_stream->last_allocated_seq_num + 1;
}
sh_stream->last_allocated_seq_num = seq_num;
return seq_num;
}
#endif /* CONFIG_BT_AUDIO_TX */
@ -185,7 +177,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, PRIME_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
#include "lc3.h"
@ -200,22 +193,18 @@ NET_BUF_POOL_FIXED_DEFINE(sine_tx_pool, PRIME_COUNT, BT_ISO_SDU_BUF_SIZE(CONFIG_
static int16_t audio_buf[MAX_NUM_SAMPLES];
static lc3_encoder_t lc3_encoder;
static lc3_encoder_mem_48k_t lc3_encoder_mem;
static int freq_hz;
static int frame_duration_us;
static int frame_duration_100us;
static int frames_per_sdu;
static int octets_per_frame;
static int32_t lc3_sdu_cnt;
static int lc3_freq_hz;
static int lc3_frame_duration_us;
static int lc3_frame_duration_100us;
static int lc3_frames_per_sdu;
static int lc3_octets_per_frame;
static void lc3_audio_send_data(struct k_work *work);
static K_WORK_DELAYABLE_DEFINE(audio_send_work, lc3_audio_send_data);
static void clear_lc3_sine_data(void)
static void clear_lc3_sine_data(struct bt_bap_stream *bap_stream)
{
lc3_sdu_cnt = 0;
txing_stream = NULL;
struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
(void)k_work_cancel_delayable(&audio_send_work);
sh_stream->tx_active = false;
(void)k_work_cancel_delayable(&sh_stream->audio_send_work);
}
/**
@ -248,40 +237,39 @@ static void init_lc3(const struct bt_bap_stream *stream)
return;
}
freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg);
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg);
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true);
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg);
lc3_freq_hz = bt_audio_codec_cfg_get_freq(stream->codec_cfg);
lc3_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(stream->codec_cfg);
lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg);
lc3_frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(stream->codec_cfg, true);
lc3_octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(stream->codec_cfg);
if (freq_hz < 0) {
if (lc3_freq_hz < 0) {
printk("Error: Codec frequency not set, cannot start codec.");
return;
}
if (frame_duration_us < 0) {
if (lc3_frame_duration_us < 0) {
printk("Error: Frame duration not set, cannot start codec.");
return;
}
if (octets_per_frame < 0) {
if (lc3_octets_per_frame < 0) {
printk("Error: Octets per frame not set, cannot start codec.");
return;
}
frame_duration_100us = frame_duration_us / 100;
lc3_frame_duration_100us = lc3_frame_duration_us / 100;
/* Fill audio buffer with Sine wave only once and repeat encoding the same tone frame */
fill_audio_buf_sin(audio_buf, frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, freq_hz);
fill_audio_buf_sin(audio_buf, lc3_frame_duration_us, AUDIO_TONE_FREQUENCY_HZ, lc3_freq_hz);
num_samples = ((frame_duration_us * freq_hz) / USEC_PER_SEC);
num_samples = ((lc3_frame_duration_us * lc3_freq_hz) / USEC_PER_SEC);
for (size_t i = 0; i < num_samples; i++) {
printk("%zu: %6i\n", i, audio_buf[i]);
}
/* Create the encoder instance. This shall complete before stream_started() is called. */
lc3_encoder = lc3_setup_encoder(frame_duration_us, freq_hz,
0, /* No resampling */
lc3_encoder = lc3_setup_encoder(lc3_frame_duration_us, lc3_freq_hz, 0, /* No resampling */
&lc3_encoder_mem);
if (lc3_encoder == NULL) {
@ -291,35 +279,51 @@ static void init_lc3(const struct bt_bap_stream *stream)
static void lc3_audio_send_data(struct k_work *work)
{
const uint16_t tx_sdu_len = frames_per_sdu * octets_per_frame;
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 = &sh_stream->stream.bap_stream;
const uint16_t tx_sdu_len = lc3_frames_per_sdu * lc3_octets_per_frame;
struct net_buf *buf;
uint8_t *net_buffer;
off_t offset = 0;
uint16_t seq_num;
int err;
if (!sh_stream->tx_active) {
/* TX has been aborted */
return;
}
if (lc3_encoder == NULL) {
shell_error(ctx_shell, "LC3 encoder not setup, cannot encode data");
return;
}
if (txing_stream == NULL || txing_stream->qos == NULL) {
if (bap_stream == NULL || bap_stream->qos == NULL) {
shell_error(ctx_shell, "invalid stream, aborting");
return;
}
if (atomic_get(&sh_stream->lc3_enqueue_cnt) == 0U) {
shell_error(ctx_shell, "Stream %p enqueue count was 0", bap_stream);
/* Reschedule for next interval */
k_work_reschedule(k_work_delayable_from_work(work),
K_USEC(bap_stream->qos->interval));
return;
}
buf = net_buf_alloc(&sine_tx_pool, K_FOREVER);
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
net_buffer = net_buf_tail(buf);
buf->len += tx_sdu_len;
for (int i = 0; i < frames_per_sdu; i++) {
for (int i = 0; i < lc3_frames_per_sdu; i++) {
int lc3_ret;
lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, audio_buf, 1,
octets_per_frame, net_buffer + offset);
offset += octets_per_frame;
lc3_octets_per_frame, net_buffer + offset);
offset += lc3_octets_per_frame;
if (lc3_ret == -1) {
shell_error(ctx_shell, "LC3 encoder failed - wrong parameters?: %d",
@ -328,51 +332,54 @@ static void lc3_audio_send_data(struct k_work *work)
/* Reschedule for next interval */
k_work_reschedule(k_work_delayable_from_work(work),
K_USEC(txing_stream->qos->interval));
K_USEC(bap_stream->qos->interval));
return;
}
}
seq_num = get_next_seq_num(txing_stream);
err = bt_bap_stream_send(txing_stream, buf, seq_num, BT_ISO_TIMESTAMP_NONE);
err = bt_bap_stream_send(bap_stream, buf, sh_stream->seq_num, BT_ISO_TIMESTAMP_NONE);
if (err < 0) {
shell_error(ctx_shell, "Failed to send LC3 audio data (%d)", err);
net_buf_unref(buf);
/* Reschedule for next interval */
k_work_reschedule(k_work_delayable_from_work(work),
K_USEC(txing_stream->qos->interval));
K_USEC(bap_stream->qos->interval));
return;
}
if ((lc3_sdu_cnt % 100) == 0) {
shell_info(ctx_shell, "[%zu]: TX LC3: %zu (seq_num %u)", lc3_sdu_cnt, tx_sdu_len,
seq_num);
if ((sh_stream->lc3_sdu_cnt % 100) == 0) {
shell_info(ctx_shell, "[%zu]: stream %p : TX LC3: %zu (seq_num %u)",
sh_stream->lc3_sdu_cnt, bap_stream, tx_sdu_len, sh_stream->seq_num);
}
lc3_sdu_cnt++;
sh_stream->lc3_sdu_cnt++;
sh_stream->seq_num++;
atomic_dec(&sh_stream->lc3_enqueue_cnt);
/* If we have more buffers available, we reschedule the workqueue item immediately to
* trigger antother encode + TX, but without blocking this call for too long
*/
buf = net_buf_alloc(&sine_tx_pool, K_NO_WAIT);
if (buf != NULL) {
net_buf_unref(buf);
if (atomic_get(&sh_stream->lc3_enqueue_cnt) > 0) {
/* If we have more buffers available, we reschedule the workqueue item immediately
* to trigger another encode + TX, but without blocking this call for too long
*/
k_work_reschedule(k_work_delayable_from_work(work), K_NO_WAIT);
}
}
void sdu_sent_cb(struct bt_bap_stream *stream)
void sdu_sent_cb(struct bt_bap_stream *bap_stream)
{
struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
int err;
if (txing_stream == NULL || txing_stream->qos == NULL) {
atomic_inc(&sh_stream->lc3_enqueue_cnt);
if (!sh_stream->tx_active) {
/* TX has been aborted */
return;
}
err = k_work_schedule(&audio_send_work, K_NO_WAIT);
err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT);
if (err < 0) {
shell_error(ctx_shell, "Failed to schedule TX: %d", err);
shell_error(ctx_shell, "Failed to schedule TX for stream %p: %d", bap_stream, err);
}
}
#endif /* CONFIG_LIBLC3 && CONFIG_BT_AUDIO_TX */
@ -945,7 +952,6 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[])
enum bt_audio_location location = BT_AUDIO_LOCATION_PROHIBITED;
const struct named_lc3_preset *named_preset;
struct shell_stream *uni_stream;
struct bt_cap_stream *cap_stream;
struct bt_bap_stream *bap_stream;
struct bt_bap_ep *ep = NULL;
unsigned long index;
@ -1052,8 +1058,7 @@ static int cmd_config(const struct shell *sh, size_t argc, char *argv[])
}
}
cap_stream = CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
uni_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream);
uni_stream = shell_stream_from_bap_stream(bap_stream);
copy_unicast_stream_preset(uni_stream, named_preset);
/* If location has been modifed, we update the location in the codec configuration */
@ -1683,45 +1688,41 @@ static struct bt_bap_broadcast_sink_cb sink_cbs = {
#if defined(CONFIG_BT_AUDIO_RX)
static unsigned long recv_stats_interval = 100U;
static size_t lost_pkts;
static size_t err_pkts;
static size_t dup_psn;
static size_t rx_cnt;
static size_t dup_ts;
static void audio_recv(struct bt_bap_stream *stream,
const struct bt_iso_recv_info *info,
struct net_buf *buf)
{
static struct bt_iso_recv_info last_info;
struct shell_stream *sh_stream = shell_stream_from_bap_stream(stream);
rx_cnt++;
sh_stream->rx_cnt++;
if (info->ts == last_info.ts) {
dup_ts++;
if (info->ts == sh_stream->last_info.ts) {
sh_stream->dup_ts++;
}
if (info->seq_num == last_info.seq_num) {
dup_psn++;
if (info->seq_num == sh_stream->last_info.seq_num) {
sh_stream->dup_psn++;
}
if (info->flags & BT_ISO_FLAGS_ERROR) {
err_pkts++;
sh_stream->err_pkts++;
}
if (info->flags & BT_ISO_FLAGS_LOST) {
lost_pkts++;
sh_stream->lost_pkts++;
}
if ((rx_cnt % recv_stats_interval) == 0) {
if ((sh_stream->rx_cnt % recv_stats_interval) == 0) {
shell_print(ctx_shell,
"[%zu]: Incoming audio on stream %p len %u ts %u seq_num %u flags %u "
"(dup ts %zu; dup psn %zu, err_pkts %zu, lost_pkts %zu)",
rx_cnt, stream, buf->len, info->ts, info->seq_num, info->flags, dup_ts,
dup_psn, err_pkts, lost_pkts);
sh_stream->rx_cnt, stream, buf->len, info->ts, info->seq_num,
info->flags, sh_stream->dup_ts, sh_stream->dup_psn, sh_stream->err_pkts,
sh_stream->lost_pkts);
}
(void)memcpy(&last_info, info, sizeof(last_info));
(void)memcpy(&sh_stream->last_info, info, sizeof(sh_stream->last_info));
}
#endif /* CONFIG_BT_AUDIO_RX */
@ -1764,25 +1765,24 @@ static void stream_enabled_cb(struct bt_bap_stream *stream)
static void stream_started_cb(struct bt_bap_stream *bap_stream)
{
struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
#if defined(CONFIG_BT_AUDIO_TX)
struct bt_cap_stream *cap_stream =
CONTAINER_OF(bap_stream, struct bt_cap_stream, bap_stream);
struct shell_stream *sh_stream = CONTAINER_OF(cap_stream, struct shell_stream, stream);
sh_stream->connected_at_ticks = k_uptime_ticks();
/* Set to max value to support sending the first packet with PSN = 0*/
sh_stream->last_allocated_seq_num = UINT16_MAX;
#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 */
printk("Stream %p started\n", bap_stream);
#if defined(CONFIG_BT_AUDIO_RX)
lost_pkts = 0U;
err_pkts = 0U;
dup_psn = 0U;
rx_cnt = 0U;
dup_ts = 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
}
@ -1791,9 +1791,7 @@ 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)
if (stream == default_stream) {
clear_lc3_sine_data();
}
clear_lc3_sine_data(stream);
#endif /* CONFIG_LIBLC3 */
}
@ -1840,9 +1838,7 @@ static void stream_released_cb(struct bt_bap_stream *stream)
#if defined(CONFIG_LIBLC3)
/* stop sending */
if (stream == default_stream) {
clear_lc3_sine_data();
}
clear_lc3_sine_data(stream);
#endif /* CONFIG_LIBLC3 */
}
#endif /* CONFIG_BT_BAP_UNICAST */
@ -2394,12 +2390,6 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
return -ENOEXEC;
}
if (txing_stream != NULL) {
shell_error(sh, "A stream %p is already TXing", txing_stream);
return -ENOEXEC;
}
if (default_stream->qos == NULL) {
shell_error(sh, "NULL stream QoS");
@ -2424,7 +2414,7 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
net_buf_add_mem(buf, data, len);
ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(txing_stream),
ret = bt_bap_stream_send(default_stream, buf, get_next_seq_num(default_stream),
BT_ISO_TIMESTAMP_NONE);
if (ret < 0) {
shell_print(sh, "Unable to send: %d", -ret);
@ -2440,37 +2430,134 @@ static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
}
#if defined(CONFIG_LIBLC3)
static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
static bool stream_start_sine_verify(const struct bt_bap_stream *bap_stream)
{
int stream_frame_duration_us;
struct bt_bap_ep_info info;
int stream_freq_hz;
int err;
if (default_stream == NULL) {
shell_error(sh, "Invalid (NULL) stream");
return -ENOEXEC;
if (bap_stream == NULL || bap_stream->qos == NULL) {
return false;
}
if (txing_stream == NULL) {
txing_stream = default_stream;
} else {
shell_error(sh, "A stream %p is already TXing", txing_stream);
return -ENOEXEC;
err = bt_bap_ep_get_info(bap_stream->ep, &info);
if (err != 0) {
return false;
}
if (txing_stream->qos == NULL) {
shell_error(ctx_shell, "NULL stream QoS");
txing_stream = NULL;
return -ENOEXEC;
if (info.state != BT_BAP_EP_STATE_STREAMING) {
return false;
}
init_lc3(txing_stream);
stream_freq_hz = bt_audio_codec_cfg_get_freq(bap_stream->codec_cfg);
if (stream_freq_hz != lc3_freq_hz) {
return false;
}
err = k_work_schedule(&audio_send_work, K_NO_WAIT);
stream_frame_duration_us = bt_audio_codec_cfg_get_frame_duration_us(bap_stream->codec_cfg);
if (stream_frame_duration_us != lc3_frame_duration_us) {
return false;
}
return true;
}
static int stream_start_sine(struct bt_bap_stream *bap_stream)
{
struct shell_stream *sh_stream = shell_stream_from_bap_stream(bap_stream);
int err;
k_work_init_delayable(&sh_stream->audio_send_work, lc3_audio_send_data);
err = k_work_schedule(&sh_stream->audio_send_work, K_NO_WAIT);
if (err < 0) {
shell_error(ctx_shell, "Failed to schedule TX: %d", err);
return -ENOEXEC;
}
sh_stream->tx_active = true;
sh_stream->seq_num = get_next_seq_num(bap_stream);
return 0;
}
static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
{
bool start_all = false;
int err;
if (argc > 1) {
if (strcmp(argv[1], "all") == 0) {
start_all = true;
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
}
if (start_all) {
bool lc3_initialized = false;
for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream;
if (!lc3_initialized) {
init_lc3(bap_stream);
lc3_initialized = true;
}
if (!stream_start_sine_verify(bap_stream)) {
continue;
}
err = stream_start_sine(bap_stream);
if (err != 0) {
shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream,
err);
return err;
}
shell_print(sh, "Started transmitting on unicast stream %p", bap_stream);
}
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) {
struct bt_bap_stream *bap_stream =
&broadcast_source_streams[i].stream.bap_stream;
if (!lc3_initialized) {
init_lc3(bap_stream);
lc3_initialized = true;
}
if (!stream_start_sine_verify(bap_stream)) {
continue;
}
err = stream_start_sine(bap_stream);
if (err != 0) {
shell_error(sh, "Failed to start TX for stream %p: %d", bap_stream,
err);
return err;
}
shell_print(sh, "Started transmitting on broadcast stream %p", bap_stream);
}
} else {
if (stream_start_sine_verify(default_stream)) {
shell_error(sh, "Invalid stream %p", default_stream);
return -ENOEXEC;
}
init_lc3(default_stream);
err = stream_start_sine(default_stream);
if (err != 0) {
shell_error(sh, "Failed to start TX for stream %p: %d", default_stream,
err);
return err;
}
shell_print(sh, "Started transmitting on default_stream %p", default_stream);
}
return 0;
@ -2478,7 +2565,44 @@ static int cmd_start_sine(const struct shell *sh, size_t argc, char *argv[])
static int cmd_stop_sine(const struct shell *sh, size_t argc, char *argv[])
{
clear_lc3_sine_data();
bool stop_all = false;
if (argc > 1) {
if (strcmp(argv[1], "all") == 0) {
stop_all = true;
} else {
shell_help(sh);
return SHELL_CMD_HELP_PRINTED;
}
}
if (stop_all) {
for (size_t i = 0U; i < ARRAY_SIZE(unicast_streams); i++) {
struct bt_bap_stream *bap_stream = &unicast_streams[i].stream.bap_stream;
if (unicast_streams[i].tx_active) {
clear_lc3_sine_data(bap_stream);
shell_print(sh, "Stopped transmitting on stream %p", bap_stream);
}
}
for (size_t i = 0U; i < ARRAY_SIZE(broadcast_source_streams); i++) {
struct bt_bap_stream *bap_stream =
&broadcast_source_streams[i].stream.bap_stream;
if (unicast_streams[i].tx_active) {
clear_lc3_sine_data(bap_stream);
shell_print(sh, "Stopped transmitting on stream %p", bap_stream);
}
}
} else {
struct shell_stream *sh_stream = shell_stream_from_bap_stream(default_stream);
if (sh_stream->tx_active) {
clear_lc3_sine_data(default_stream);
shell_print(sh, "Stopped transmitting on stream %p", default_stream);
}
}
return 0;
}
@ -2583,9 +2707,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
#if defined(CONFIG_BT_AUDIO_TX)
SHELL_CMD_ARG(send, NULL, "Send to Audio Stream [data]", cmd_send, 1, 1),
#if defined(CONFIG_LIBLC3)
SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave", cmd_start_sine, 1,
0),
SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave", cmd_stop_sine, 1, 0),
SHELL_CMD_ARG(start_sine, NULL, "Start sending a LC3 encoded sine wave [all]",
cmd_start_sine, 1, 1),
SHELL_CMD_ARG(stop_sine, NULL, "Stop sending a LC3 encoded sine wave [all]", cmd_stop_sine,
1, 1),
#endif /* CONFIG_LIBLC3 */
#endif /* CONFIG_BT_AUDIO_TX */
#if defined(CONFIG_BT_AUDIO_RX)