samples: Bluetooth: Few fixups for USB data for broadcast audio sink
This commit does several but minor changes to the USB handling of the broadcast audio sink, such as improving logging, removing a few unncessary pieces of code and some minor performance improvements. It removes some uses of the ring buffers, which effectively clears up around 30KB of RAM, while also reducing how much memory is being copied, improving performance. Some of this removes the existing code for partial support for stereo, but that code did not work in the first place. Proper stereo support will be added in a later commit. Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
parent
d2aaa65c14
commit
0051731a41
2 changed files with 115 additions and 150 deletions
|
@ -7,6 +7,8 @@ CONFIG_BT_PERIPHERAL=y
|
||||||
CONFIG_BT_BAP_BROADCAST_SINK=y
|
CONFIG_BT_BAP_BROADCAST_SINK=y
|
||||||
CONFIG_BT_BAP_SCAN_DELEGATOR=y
|
CONFIG_BT_BAP_SCAN_DELEGATOR=y
|
||||||
CONFIG_BT_ISO_MAX_CHAN=2
|
CONFIG_BT_ISO_MAX_CHAN=2
|
||||||
|
# Allocate 2 RX buffers per channel
|
||||||
|
CONFIG_BT_ISO_RX_BUF_COUNT=4
|
||||||
CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2
|
CONFIG_BT_BAP_BROADCAST_SNK_SUBGROUP_COUNT=2
|
||||||
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2
|
CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT=2
|
||||||
CONFIG_BT_BAP_BASS_MAX_SUBGROUPS=2
|
CONFIG_BT_BAP_BASS_MAX_SUBGROUPS=2
|
||||||
|
|
|
@ -29,37 +29,39 @@ BUILD_ASSERT(IS_ENABLED(CONFIG_SCAN_SELF) || IS_ENABLED(CONFIG_SCAN_OFFLOAD),
|
||||||
#define SEM_TIMEOUT K_SECONDS(60)
|
#define SEM_TIMEOUT K_SECONDS(60)
|
||||||
#define BROADCAST_ASSISTANT_TIMEOUT K_SECONDS(120) /* 2 minutes */
|
#define BROADCAST_ASSISTANT_TIMEOUT K_SECONDS(120) /* 2 minutes */
|
||||||
|
|
||||||
|
#define LOG_INTERVAL 1000U
|
||||||
|
|
||||||
#if defined(CONFIG_SCAN_SELF)
|
#if defined(CONFIG_SCAN_SELF)
|
||||||
#define ADV_TIMEOUT K_SECONDS(CONFIG_SCAN_DELAY)
|
#define ADV_TIMEOUT K_SECONDS(CONFIG_SCAN_DELAY)
|
||||||
#else /* !CONFIG_SCAN_SELF */
|
#else /* !CONFIG_SCAN_SELF */
|
||||||
#define ADV_TIMEOUT K_FOREVER
|
#define ADV_TIMEOUT K_FOREVER
|
||||||
#endif /* CONFIG_SCAN_SELF */
|
#endif /* CONFIG_SCAN_SELF */
|
||||||
|
|
||||||
#define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1)
|
#define INVALID_BROADCAST_ID (BT_AUDIO_BROADCAST_ID_MAX + 1)
|
||||||
#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */
|
#define SYNC_RETRY_COUNT 6 /* similar to retries for connections */
|
||||||
#define PA_SYNC_SKIP 5
|
#define PA_SYNC_SKIP 5
|
||||||
#define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1
|
#define NAME_LEN sizeof(CONFIG_TARGET_BROADCAST_NAME) + 1
|
||||||
|
#define BROADCAST_DATA_ELEMENT_SIZE sizeof(int16_t)
|
||||||
|
|
||||||
#if defined(CONFIG_LIBLC3)
|
#if defined(CONFIG_LIBLC3)
|
||||||
#define MAX_SAMPLE_RATE 48000U
|
#define LC3_MAX_SAMPLE_RATE 48000U
|
||||||
#define MAX_FRAME_DURATION_US 10000U
|
#define LC3_MAX_FRAME_DURATION_US 10000U
|
||||||
#define MAX_NUM_SAMPLES_MONO ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC)
|
#define LC3_MAX_NUM_SAMPLES_MONO ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE) \
|
||||||
#define MAX_NUM_SAMPLES_STEREO (MAX_NUM_SAMPLES_MONO * 2)
|
/ USEC_PER_SEC)
|
||||||
|
#define LC3_MAX_NUM_SAMPLES_STEREO (LC3_MAX_NUM_SAMPLES_MONO * 2)
|
||||||
|
|
||||||
#define LC3_ENCODER_STACK_SIZE 4096
|
#define LC3_ENCODER_STACK_SIZE 4096
|
||||||
#define LC3_ENCODER_PRIORITY 5
|
#define LC3_ENCODER_PRIORITY 5
|
||||||
#endif /* defined(CONFIG_LIBLC3) */
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
||||||
|
#define USB_ENQUEUE_COUNT 10U
|
||||||
#define USB_SAMPLE_RATE 48000U
|
#define USB_SAMPLE_RATE 48000U
|
||||||
#define USB_FRAME_DURATION_US 1000U
|
#define USB_FRAME_DURATION_US 1000U
|
||||||
#define USB_TX_BUF_NUM 10U
|
#define USB_MONO_SAMPLE_SIZE \
|
||||||
#define BROADCAST_DATA_ELEMENT_SIZE sizeof(int16_t)
|
((USB_FRAME_DURATION_US * USB_SAMPLE_RATE * BROADCAST_DATA_ELEMENT_SIZE) / USEC_PER_SEC)
|
||||||
#define BROADCAST_MONO_SAMPLE_SIZE (MAX_NUM_SAMPLES_MONO * BROADCAST_DATA_ELEMENT_SIZE)
|
#define USB_STEREO_SAMPLE_SIZE (USB_MONO_SAMPLE_SIZE * 2)
|
||||||
#define BROADCAST_STEREO_SAMPLE_SIZE (BROADCAST_MONO_SAMPLE_SIZE * BROADCAST_DATA_ELEMENT_SIZE)
|
#define USB_RING_BUF_SIZE (5 * LC3_MAX_NUM_SAMPLES_STEREO) /* 5 SDUs*/
|
||||||
#define USB_STEREO_SAMPLE_SIZE ((USB_FRAME_DURATION_US * USB_SAMPLE_RATE * \
|
|
||||||
BROADCAST_DATA_ELEMENT_SIZE * 2) / USEC_PER_SEC)
|
|
||||||
#define AUDIO_RING_BUF_SIZE 10000U
|
|
||||||
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
||||||
|
|
||||||
static K_SEM_DEFINE(sem_connected, 0U, 1U);
|
static K_SEM_DEFINE(sem_connected, 0U, 1U);
|
||||||
|
@ -84,7 +86,6 @@ static struct bt_le_per_adv_sync *pa_sync;
|
||||||
static uint32_t broadcaster_broadcast_id;
|
static uint32_t broadcaster_broadcast_id;
|
||||||
static struct broadcast_sink_stream {
|
static struct broadcast_sink_stream {
|
||||||
struct bt_bap_stream stream;
|
struct bt_bap_stream stream;
|
||||||
bool has_data;
|
|
||||||
size_t recv_cnt;
|
size_t recv_cnt;
|
||||||
size_t loss_cnt;
|
size_t loss_cnt;
|
||||||
size_t error_cnt;
|
size_t error_cnt;
|
||||||
|
@ -97,12 +98,8 @@ static struct broadcast_sink_stream {
|
||||||
lc3_decoder_t lc3_decoder;
|
lc3_decoder_t lc3_decoder;
|
||||||
lc3_decoder_mem_48k_t lc3_decoder_mem;
|
lc3_decoder_mem_48k_t lc3_decoder_mem;
|
||||||
#endif /* defined(CONFIG_LIBLC3) */
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
|
||||||
struct ring_buf audio_ring_buf;
|
|
||||||
uint8_t _ring_buffer[AUDIO_RING_BUF_SIZE];
|
|
||||||
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
|
||||||
|
|
||||||
} streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
} streams[CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT];
|
||||||
|
|
||||||
static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)];
|
static struct bt_bap_stream *streams_p[ARRAY_SIZE(streams)];
|
||||||
static struct bt_conn *broadcast_assistant_conn;
|
static struct bt_conn *broadcast_assistant_conn;
|
||||||
static struct bt_le_ext_adv *ext_adv;
|
static struct bt_le_ext_adv *ext_adv;
|
||||||
|
@ -126,22 +123,19 @@ uint64_t total_rx_iso_packet_count; /* This value is exposed to test code */
|
||||||
static int stop_adv(void);
|
static int stop_adv(void);
|
||||||
|
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
||||||
static int16_t usb_audio_data[MAX_NUM_SAMPLES_STEREO] = {0};
|
RING_BUF_DECLARE(usb_ring_buf, USB_RING_BUF_SIZE);
|
||||||
static int16_t usb_audio_data_stereo[MAX_NUM_SAMPLES_STEREO] = {0};
|
NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_ENQUEUE_COUNT, USB_STEREO_SAMPLE_SIZE, 0, net_buf_destroy);
|
||||||
|
|
||||||
RING_BUF_DECLARE(ring_buf_usb, AUDIO_RING_BUF_SIZE);
|
static void mix_mono_to_stereo(int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
|
||||||
NET_BUF_POOL_DEFINE(usb_tx_buf_pool, USB_TX_BUF_NUM, BROADCAST_STEREO_SAMPLE_SIZE, 0,
|
static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
|
||||||
net_buf_destroy);
|
|
||||||
|
|
||||||
static void mix_mono_to_stereo(enum bt_audio_location channels);
|
|
||||||
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
||||||
|
|
||||||
#if defined(CONFIG_LIBLC3)
|
#if defined(CONFIG_LIBLC3)
|
||||||
static int16_t audio_buf[MAX_NUM_SAMPLES_MONO];
|
|
||||||
static int frames_per_sdu;
|
static int frames_per_sdu;
|
||||||
static K_SEM_DEFINE(lc3_decoder_sem, 0, 1);
|
static K_SEM_DEFINE(lc3_decoder_sem, 0, 1);
|
||||||
|
|
||||||
static void do_lc3_decode(struct broadcast_sink_stream *sink_stream);
|
static bool do_lc3_decode(struct broadcast_sink_stream *sink_stream,
|
||||||
|
int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO]);
|
||||||
static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3);
|
static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3);
|
||||||
K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread,
|
K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread,
|
||||||
NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1);
|
NULL, NULL, NULL, LC3_ENCODER_PRIORITY, 0, -1);
|
||||||
|
@ -150,102 +144,87 @@ K_THREAD_DEFINE(decoder_tid, LC3_ENCODER_STACK_SIZE, lc3_decoder_thread,
|
||||||
static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3)
|
static void lc3_decoder_thread(void *arg1, void *arg2, void *arg3)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
|
static int16_t lc3_audio_buf[LC3_MAX_NUM_SAMPLES_STEREO];
|
||||||
|
|
||||||
k_sem_take(&lc3_decoder_sem, K_FOREVER);
|
k_sem_take(&lc3_decoder_sem, K_FOREVER);
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
||||||
int err = 0;
|
|
||||||
enum bt_audio_location channels;
|
/* For now we only handle one BIS, so always only decode the first element
|
||||||
|
* in streams.
|
||||||
|
*/
|
||||||
struct broadcast_sink_stream *stream_for_usb = &streams[0];
|
struct broadcast_sink_stream *stream_for_usb = &streams[0];
|
||||||
|
|
||||||
/* For now we only handle one BIS, so always only decode the first element in
|
/* Not enough space to store data */
|
||||||
* streams.
|
if (ring_buf_space_get(&usb_ring_buf) < sizeof(lc3_audio_buf)) {
|
||||||
*/
|
|
||||||
do_lc3_decode(&streams[0]);
|
|
||||||
|
|
||||||
err = bt_audio_codec_cfg_get_chan_allocation(stream_for_usb->stream.codec_cfg,
|
|
||||||
&channels);
|
|
||||||
if (err != 0) {
|
|
||||||
printk("Could not get channel allocation (err=%d)\n", err);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the ring buffer usage is larger than zero, then there is data to process */
|
/* lc3_audio_buf will be filled with the last decoded value, so e.g. if the stream
|
||||||
if (ring_buf_space_get(&stream_for_usb->audio_ring_buf)) {
|
* contains both left and right, the lc3_audio_buf will always contain right.
|
||||||
mix_mono_to_stereo(channels);
|
*/
|
||||||
|
if (do_lc3_decode(stream_for_usb, lc3_audio_buf)) {
|
||||||
|
mix_mono_to_stereo(lc3_audio_buf);
|
||||||
|
add_to_usb_ring_buf(lc3_audio_buf);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
|
for (size_t i = 0; i < ARRAY_SIZE(streams); i++) {
|
||||||
if (streams[i].has_data) {
|
(void)do_lc3_decode(&streams[i], lc3_audio_buf);
|
||||||
do_lc3_decode(&streams[i]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* #if defined(CONFIG_USB_DEVICE_AUDIO) */
|
#endif /* #if defined(CONFIG_USB_DEVICE_AUDIO) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_lc3_decode(struct broadcast_sink_stream *sink_stream)
|
/** Decode LC3 data on a stream and returns true if successful */
|
||||||
|
static bool do_lc3_decode(struct broadcast_sink_stream *sink_stream,
|
||||||
|
int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
|
||||||
{
|
{
|
||||||
int err = 0;
|
uint16_t octets_per_frame;
|
||||||
int offset = 0;
|
struct net_buf *buf;
|
||||||
uint8_t *buf_data;
|
|
||||||
struct net_buf *ptr_net_buf;
|
|
||||||
int octets_per_frame;
|
|
||||||
|
|
||||||
k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER);
|
k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER);
|
||||||
|
|
||||||
sink_stream->has_data = false;
|
|
||||||
|
|
||||||
if (sink_stream->in_buf == NULL) {
|
if (sink_stream->in_buf == NULL) {
|
||||||
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
return;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_net_buf = net_buf_ref(sink_stream->in_buf);
|
buf = net_buf_ref(sink_stream->in_buf);
|
||||||
net_buf_unref(sink_stream->in_buf);
|
net_buf_unref(sink_stream->in_buf);
|
||||||
sink_stream->in_buf = NULL;
|
sink_stream->in_buf = NULL;
|
||||||
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
|
|
||||||
buf_data = ptr_net_buf->data;
|
octets_per_frame = buf->len / frames_per_sdu;
|
||||||
octets_per_frame = ptr_net_buf->len / frames_per_sdu;
|
if (buf->len != (octets_per_frame * frames_per_sdu)) {
|
||||||
|
printk("Expected %u frames of size %u, but length is %u\n", frames_per_sdu,
|
||||||
|
octets_per_frame, buf->len);
|
||||||
|
|
||||||
|
net_buf_unref(buf);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < frames_per_sdu; i++) {
|
for (int i = 0; i < frames_per_sdu; i++) {
|
||||||
err = lc3_decode(sink_stream->lc3_decoder, buf_data + offset, octets_per_frame,
|
const void *data = net_buf_pull_mem(buf, octets_per_frame);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = lc3_decode(sink_stream->lc3_decoder, data, octets_per_frame,
|
||||||
LC3_PCM_FORMAT_S16, audio_buf, 1);
|
LC3_PCM_FORMAT_S16, audio_buf, 1);
|
||||||
|
|
||||||
if (err == 1) {
|
if (err == 1) {
|
||||||
printk(" decoder performed PLC\n");
|
printk(" decoder performed PLC\n");
|
||||||
} else if (err < 0) {
|
} else if (err < 0) {
|
||||||
printk(" decoder failed - wrong parameters? (err = %d)\n", err);
|
printk(" decoder failed - wrong parameters? (err = %d)\n", err);
|
||||||
|
|
||||||
|
net_buf_unref(buf);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += octets_per_frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
net_buf_unref(ptr_net_buf);
|
net_buf_unref(buf);
|
||||||
|
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
return true;
|
||||||
uint32_t rbret;
|
|
||||||
|
|
||||||
if (ring_buf_space_get(&sink_stream->audio_ring_buf) == 0) {
|
|
||||||
/* Since the data in the buffer is old by now, and we add enough data for many
|
|
||||||
* request to consume at a time, just erase what is already in the buffer.
|
|
||||||
*/
|
|
||||||
ring_buf_reset(&sink_stream->audio_ring_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put in ring-buffer to be consumed */
|
|
||||||
rbret = ring_buf_put(&sink_stream->audio_ring_buf, (uint8_t *)audio_buf,
|
|
||||||
BROADCAST_MONO_SAMPLE_SIZE);
|
|
||||||
if (rbret != BROADCAST_MONO_SAMPLE_SIZE) {
|
|
||||||
static int rb_add_failures;
|
|
||||||
|
|
||||||
rb_add_failures++;
|
|
||||||
if (rb_add_failures % 1000 == 0) {
|
|
||||||
printk("Failure to add to ring buffer %d, %u\n", rb_add_failures, rbret);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif /*#if defined(CONFIG_USB_DEVICE_AUDIO)*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lc3_enable(struct broadcast_sink_stream *sink_stream)
|
static int lc3_enable(struct broadcast_sink_stream *sink_stream)
|
||||||
|
@ -295,94 +274,81 @@ static int lc3_enable(struct broadcast_sink_stream *sink_stream)
|
||||||
#endif /* defined(CONFIG_LIBLC3) */
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
||||||
static uint8_t get_channel_index(const enum bt_audio_location allocated_channels,
|
/* Duplicate the audio from one channel and put it in both channels */
|
||||||
const enum bt_audio_location channel)
|
static void mix_mono_to_stereo(int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
|
||||||
{
|
{
|
||||||
/* If we are looking for the right channel, and left channel is present, then the index is
|
/* Interleave the channel sample inline
|
||||||
* 1. For all other combinations the index has to be 0, since it would mean that it is the
|
* Take the first LC3_MAX_NUM_SAMPLES_MONO samples from audio_buf and mix it to
|
||||||
* lowest possible bit enumeration
|
* interleaved stereo, so that 012345 becomes 001122334455
|
||||||
*/
|
*/
|
||||||
if (channel == BT_AUDIO_LOCATION_FRONT_RIGHT &&
|
for (int i = LC3_MAX_NUM_SAMPLES_MONO - 1; i >= 0; i--) {
|
||||||
allocated_channels & BT_AUDIO_LOCATION_FRONT_LEFT) {
|
const int16_t sample = audio_buf[i];
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
audio_buf[i * 2] = sample;
|
||||||
|
audio_buf[i * 2 + 1] = sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Duplicate the audio from one channel and put it in both channels */
|
/* Move the LC3 data to the USB ring buffer */
|
||||||
static void mix_mono_to_stereo(enum bt_audio_location channels)
|
static void add_to_usb_ring_buf(const int16_t audio_buf[LC3_MAX_NUM_SAMPLES_STEREO])
|
||||||
{
|
{
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint8_t cidx;
|
|
||||||
|
|
||||||
size = ring_buf_get(&streams[0].audio_ring_buf, (uint8_t *)usb_audio_data,
|
size = ring_buf_put(&usb_ring_buf, (uint8_t *)audio_buf,
|
||||||
MAX_NUM_SAMPLES_STEREO);
|
LC3_MAX_NUM_SAMPLES_STEREO * sizeof(int16_t));
|
||||||
if (size != MAX_NUM_SAMPLES_STEREO) {
|
if (size != LC3_MAX_NUM_SAMPLES_STEREO) {
|
||||||
memset(&((uint8_t *)usb_audio_data)[size], 0, sizeof(usb_audio_data) - size);
|
|
||||||
}
|
|
||||||
|
|
||||||
cidx = get_channel_index(channels, CONFIG_TARGET_BROADCAST_CHANNEL);
|
|
||||||
|
|
||||||
/* Interleave the channel sample */
|
|
||||||
for (size_t i = 0U; i < MAX_NUM_SAMPLES_MONO; i++) {
|
|
||||||
usb_audio_data_stereo[i * 2] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i];
|
|
||||||
usb_audio_data_stereo[i * 2 + 1] = usb_audio_data[MAX_NUM_SAMPLES_MONO * cidx + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
size = ring_buf_put(&ring_buf_usb, (uint8_t *)usb_audio_data_stereo,
|
|
||||||
BROADCAST_STEREO_SAMPLE_SIZE);
|
|
||||||
if (size != BROADCAST_STEREO_SAMPLE_SIZE) {
|
|
||||||
static int rb_put_failures;
|
static int rb_put_failures;
|
||||||
|
|
||||||
rb_put_failures++;
|
rb_put_failures++;
|
||||||
if (rb_put_failures == 1000) {
|
if (rb_put_failures == LOG_INTERVAL) {
|
||||||
printk("%s: Failure to add to ring buffer %d, %u\n", __func__,
|
printk("%s: Failure to add to usb_ring_buf %d, %u\n", __func__,
|
||||||
rb_put_failures, size);
|
rb_put_failures, size);
|
||||||
rb_put_failures = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USB consumer callback, called every 1ms, consumes data from ring-buffer */
|
/* USB consumer callback, called every 1ms, consumes data from ring-buffer */
|
||||||
static void data_request(const struct device *dev)
|
static void usb_data_request_cb(const struct device *dev)
|
||||||
{
|
{
|
||||||
|
uint8_t usb_audio_data[USB_STEREO_SAMPLE_SIZE] = {0};
|
||||||
static struct net_buf *pcm_buf;
|
static struct net_buf *pcm_buf;
|
||||||
int err;
|
static size_t cnt;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
void *out;
|
int err;
|
||||||
int16_t usb_audio_data[USB_STEREO_SAMPLE_SIZE] = {0};
|
|
||||||
|
|
||||||
size = ring_buf_get(&ring_buf_usb, (uint8_t *)usb_audio_data, USB_STEREO_SAMPLE_SIZE);
|
size = ring_buf_get(&usb_ring_buf, (uint8_t *)usb_audio_data, sizeof(usb_audio_data));
|
||||||
if (size != USB_STEREO_SAMPLE_SIZE) {
|
if (size == 0) {
|
||||||
memset(&((uint8_t *)usb_audio_data)[size], 0, USB_STEREO_SAMPLE_SIZE);
|
/* size is 0, noop */
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
/* Size lower than USB_STEREO_SAMPLE_SIZE is OK as usb_audio_data is 0-initialized */
|
||||||
|
|
||||||
pcm_buf = net_buf_alloc(&usb_tx_buf_pool, K_NO_WAIT);
|
pcm_buf = net_buf_alloc(&usb_tx_buf_pool, K_NO_WAIT);
|
||||||
if (pcm_buf == NULL) {
|
if (pcm_buf == NULL) {
|
||||||
printk("Couldnt allocate pcm_buf\n");
|
printk("Could not allocate pcm_buf\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = net_buf_add(pcm_buf, USB_STEREO_SAMPLE_SIZE);
|
net_buf_add_mem(pcm_buf, usb_audio_data, sizeof(usb_audio_data));
|
||||||
memcpy(out, usb_audio_data, USB_STEREO_SAMPLE_SIZE);
|
|
||||||
|
if (cnt % LOG_INTERVAL == 0) {
|
||||||
|
printk("Sending USB audio (count = %zu)\n", cnt);
|
||||||
|
}
|
||||||
|
|
||||||
err = usb_audio_send(dev, pcm_buf, USB_STEREO_SAMPLE_SIZE);
|
err = usb_audio_send(dev, pcm_buf, USB_STEREO_SAMPLE_SIZE);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
printk("Failed to send USB audio: %d\n", err);
|
||||||
net_buf_unref(pcm_buf);
|
net_buf_unref(pcm_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void data_written(const struct device *dev, struct net_buf *buf, size_t size)
|
static void usb_data_written_cb(const struct device *dev, struct net_buf *buf, size_t size)
|
||||||
{
|
{
|
||||||
/* Unreference the buffer now that the USB is done with it */
|
/* Unreference the buffer now that the USB is done with it */
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_audio_ops ops = {
|
|
||||||
.data_request_cb = data_request,
|
|
||||||
.data_written_cb = data_written,
|
|
||||||
};
|
|
||||||
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
#endif /* defined(CONFIG_USB_DEVICE_AUDIO) */
|
||||||
|
|
||||||
static void stream_started_cb(struct bt_bap_stream *stream)
|
static void stream_started_cb(struct bt_bap_stream *stream)
|
||||||
|
@ -455,14 +421,13 @@ static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_rec
|
||||||
|
|
||||||
sink_stream->in_buf = net_buf_ref(buf);
|
sink_stream->in_buf = net_buf_ref(buf);
|
||||||
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
sink_stream->has_data = true;
|
|
||||||
k_sem_give(&lc3_decoder_sem);
|
k_sem_give(&lc3_decoder_sem);
|
||||||
#endif /* defined(CONFIG_LIBLC3) */
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
total_rx_iso_packet_count++;
|
total_rx_iso_packet_count++;
|
||||||
sink_stream->recv_cnt++;
|
sink_stream->recv_cnt++;
|
||||||
if ((sink_stream->recv_cnt % 1000U) == 0U) {
|
if ((sink_stream->recv_cnt % LOG_INTERVAL) == 0U) {
|
||||||
printk("Stream %p: received %u total ISO packets: Valid %u | Error %u | Loss %u\n",
|
printk("Stream %p: received %u total ISO packets: Valid %u | Error %u | Loss %u\n",
|
||||||
&sink_stream->stream, sink_stream->recv_cnt, sink_stream->valid_cnt,
|
&sink_stream->stream, sink_stream->recv_cnt, sink_stream->valid_cnt,
|
||||||
sink_stream->error_cnt, sink_stream->loss_cnt);
|
sink_stream->error_cnt, sink_stream->loss_cnt);
|
||||||
|
@ -496,8 +461,8 @@ static bool find_valid_bis_cb(const struct bt_bap_base_subgroup_bis *bis,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((CONFIG_TARGET_BROADCAST_CHANNEL) == BT_AUDIO_LOCATION_MONO_AUDIO &&
|
if ((CONFIG_TARGET_BROADCAST_CHANNEL == BT_AUDIO_LOCATION_MONO_AUDIO &&
|
||||||
chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) ||
|
chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO) ||
|
||||||
chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) {
|
chan_allocation & CONFIG_TARGET_BROADCAST_CHANNEL) {
|
||||||
*bis_index = bis->index;
|
*bis_index = bis->index;
|
||||||
|
|
||||||
|
@ -990,22 +955,20 @@ static int init(void)
|
||||||
|
|
||||||
/* Initialize ring buffers and USB */
|
/* Initialize ring buffers and USB */
|
||||||
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
#if defined(CONFIG_USB_DEVICE_AUDIO)
|
||||||
int ret;
|
|
||||||
const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0));
|
const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0));
|
||||||
|
static const struct usb_audio_ops usb_ops = {
|
||||||
for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_SNK_STREAM_COUNT; i++) {
|
.data_request_cb = usb_data_request_cb,
|
||||||
ring_buf_init(&streams[i].audio_ring_buf, AUDIO_RING_BUF_SIZE,
|
.data_written_cb = usb_data_written_cb,
|
||||||
streams[i]._ring_buffer);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (!device_is_ready(hs_dev)) {
|
if (!device_is_ready(hs_dev)) {
|
||||||
printk("Cannot get USB Headset Device\n");
|
printk("Cannot get USB Headset Device\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_audio_register(hs_dev, &ops);
|
usb_audio_register(hs_dev, &usb_ops);
|
||||||
ret = usb_enable(NULL);
|
err = usb_enable(NULL);
|
||||||
if (ret != 0) {
|
if (err != 0) {
|
||||||
printk("Failed to enable USB\n");
|
printk("Failed to enable USB\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue