samples: Bluetooth: Add LC3 to broadcast audio samples
The broadcast audio samples (broadcast_audio_sink and broadcast_audio_source) are sending mock data, the apps are improved by using the LC3 module as the unicast audio samples do. Signed-off-by: Ping Wang <pinw@demant.com>
This commit is contained in:
parent
2dcb1280a5
commit
f0728ce0aa
5 changed files with 262 additions and 8 deletions
|
@ -0,0 +1,10 @@
|
||||||
|
# For LC3 the following configs are needed
|
||||||
|
CONFIG_FPU=y
|
||||||
|
CONFIG_LIBLC3=y
|
||||||
|
# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence
|
||||||
|
# inctease stack size for that thread.
|
||||||
|
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
|
||||||
|
# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that.
|
||||||
|
CONFIG_NEWLIB_LIBC=y
|
||||||
|
# Enable encryption.
|
||||||
|
CONFIG_BT_TINYCRYPT_ECC=y
|
|
@ -10,5 +10,7 @@ CONFIG_BT_ISO_MAX_CHAN=2
|
||||||
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_SCAN_DELEGATOR_MAX_SUBGROUPS=2
|
CONFIG_BT_BAP_SCAN_DELEGATOR_MAX_SUBGROUPS=2
|
||||||
|
CONFIG_BT_BUF_ACL_RX_SIZE=255
|
||||||
|
CONFIG_BT_BUF_ACL_TX_SIZE=251
|
||||||
|
|
||||||
CONFIG_BT_DEVICE_NAME="Broadcast Audio Sink"
|
CONFIG_BT_DEVICE_NAME="Broadcast Audio Sink"
|
||||||
|
|
|
@ -56,12 +56,17 @@ static struct broadcast_sink_stream {
|
||||||
size_t loss_cnt;
|
size_t loss_cnt;
|
||||||
size_t error_cnt;
|
size_t error_cnt;
|
||||||
size_t valid_cnt;
|
size_t valid_cnt;
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
struct net_buf *in_buf;
|
||||||
|
struct k_work_delayable lc3_decode_work;
|
||||||
|
/* Internal lock for protecting net_buf from multiple access */
|
||||||
|
struct k_mutex lc3_decoder_mutex;
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
} 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;
|
||||||
|
|
||||||
|
|
||||||
static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
|
static const struct bt_audio_codec_cap codec_cap = BT_AUDIO_CODEC_CAP_LC3(
|
||||||
BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ,
|
BT_AUDIO_CODEC_LC3_FREQ_16KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ,
|
||||||
BT_AUDIO_CODEC_LC3_DURATION_10, BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u,
|
BT_AUDIO_CODEC_LC3_DURATION_10, BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), 40u, 60u, 1u,
|
||||||
|
@ -76,6 +81,100 @@ static uint32_t requested_bis_sync;
|
||||||
static uint32_t bis_index_bitfield;
|
static uint32_t bis_index_bitfield;
|
||||||
static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE];
|
static uint8_t sink_broadcast_code[BT_AUDIO_BROADCAST_CODE_SIZE];
|
||||||
|
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
|
||||||
|
#include "lc3.h"
|
||||||
|
|
||||||
|
#define MAX_SAMPLE_RATE 16000
|
||||||
|
#define MAX_FRAME_DURATION_US 10000
|
||||||
|
#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC)
|
||||||
|
|
||||||
|
static int16_t audio_buf[MAX_NUM_SAMPLES];
|
||||||
|
static lc3_decoder_t lc3_decoder;
|
||||||
|
static lc3_decoder_mem_16k_t lc3_decoder_mem;
|
||||||
|
static int frames_per_sdu;
|
||||||
|
|
||||||
|
static int lc3_enable(const struct bt_audio_codec_cfg *codec_cfg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int freq_hz;
|
||||||
|
int frame_duration_us;
|
||||||
|
|
||||||
|
printk("Enable: stream with codec %p\n", codec_cfg);
|
||||||
|
|
||||||
|
ret = bt_audio_codec_cfg_get_freq(codec_cfg);
|
||||||
|
if (ret > 0) {
|
||||||
|
freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret);
|
||||||
|
} else {
|
||||||
|
printk("Error: Codec frequency not set, cannot start codec.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
|
||||||
|
if (ret > 0) {
|
||||||
|
frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
|
||||||
|
} else {
|
||||||
|
printk("Error: Frame duration not set, cannot start codec.");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
|
||||||
|
|
||||||
|
lc3_decoder = lc3_setup_decoder(frame_duration_us, freq_hz, 0, /* No resampling */
|
||||||
|
&lc3_decoder_mem);
|
||||||
|
|
||||||
|
if (lc3_decoder == NULL) {
|
||||||
|
printk("ERROR: Failed to setup LC3 decoder - wrong parameters?\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lc3_decode_handler(struct k_work *work)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
int offset = 0;
|
||||||
|
uint8_t *buf_data;
|
||||||
|
struct net_buf *ptr_net_buf;
|
||||||
|
int octets_per_frame;
|
||||||
|
struct broadcast_sink_stream *sink_stream = CONTAINER_OF(
|
||||||
|
k_work_delayable_from_work(work), struct broadcast_sink_stream, lc3_decode_work);
|
||||||
|
|
||||||
|
k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER);
|
||||||
|
|
||||||
|
if (sink_stream->in_buf == NULL) {
|
||||||
|
printk("buf data is NULL, nothing to be docoded\n");
|
||||||
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr_net_buf = net_buf_ref(sink_stream->in_buf);
|
||||||
|
net_buf_unref(sink_stream->in_buf);
|
||||||
|
sink_stream->in_buf = NULL;
|
||||||
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
|
|
||||||
|
buf_data = ptr_net_buf->data;
|
||||||
|
octets_per_frame = ptr_net_buf->len / frames_per_sdu;
|
||||||
|
|
||||||
|
for (int i = 0; i < frames_per_sdu; i++) {
|
||||||
|
err = lc3_decode(lc3_decoder, buf_data + offset, octets_per_frame,
|
||||||
|
LC3_PCM_FORMAT_S16, audio_buf, 1);
|
||||||
|
|
||||||
|
if (err == 1) {
|
||||||
|
printk(" decoder performed PLC\n");
|
||||||
|
} else if (err < 0) {
|
||||||
|
printk(" decoder failed - wrong parameters?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += octets_per_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_unref(ptr_net_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
static void stream_started_cb(struct bt_bap_stream *stream)
|
static void stream_started_cb(struct bt_bap_stream *stream)
|
||||||
{
|
{
|
||||||
struct broadcast_sink_stream *sink_stream =
|
struct broadcast_sink_stream *sink_stream =
|
||||||
|
@ -88,6 +187,9 @@ static void stream_started_cb(struct bt_bap_stream *stream)
|
||||||
sink_stream->valid_cnt = 0U;
|
sink_stream->valid_cnt = 0U;
|
||||||
sink_stream->error_cnt = 0U;
|
sink_stream->error_cnt = 0U;
|
||||||
|
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
k_work_init_delayable(&sink_stream->lc3_decode_work, lc3_decode_handler);
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
k_sem_give(&sem_bis_synced);
|
k_sem_give(&sem_bis_synced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +205,7 @@ static void stream_stopped_cb(struct bt_bap_stream *stream, uint8_t reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stream_recv_cb(struct bt_bap_stream *stream,
|
static void stream_recv_cb(struct bt_bap_stream *stream, const struct bt_iso_recv_info *info,
|
||||||
const struct bt_iso_recv_info *info,
|
|
||||||
struct net_buf *buf)
|
struct net_buf *buf)
|
||||||
{
|
{
|
||||||
struct broadcast_sink_stream *sink_stream =
|
struct broadcast_sink_stream *sink_stream =
|
||||||
|
@ -120,6 +221,17 @@ static void stream_recv_cb(struct bt_bap_stream *stream,
|
||||||
|
|
||||||
if (info->flags & BT_ISO_FLAGS_VALID) {
|
if (info->flags & BT_ISO_FLAGS_VALID) {
|
||||||
sink_stream->valid_cnt++;
|
sink_stream->valid_cnt++;
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
k_mutex_lock(&sink_stream->lc3_decoder_mutex, K_FOREVER);
|
||||||
|
if (sink_stream->in_buf != NULL) {
|
||||||
|
net_buf_unref(sink_stream->in_buf);
|
||||||
|
sink_stream->in_buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink_stream->in_buf = net_buf_ref(buf);
|
||||||
|
k_mutex_unlock(&sink_stream->lc3_decoder_mutex);
|
||||||
|
k_work_schedule(&sink_stream->lc3_decode_work, K_NO_WAIT);
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
sink_stream->recv_cnt++;
|
sink_stream->recv_cnt++;
|
||||||
|
@ -133,7 +245,7 @@ static void stream_recv_cb(struct bt_bap_stream *stream,
|
||||||
static struct bt_bap_stream_ops stream_ops = {
|
static struct bt_bap_stream_ops stream_ops = {
|
||||||
.started = stream_started_cb,
|
.started = stream_started_cb,
|
||||||
.stopped = stream_stopped_cb,
|
.stopped = stream_stopped_cb,
|
||||||
.recv = stream_recv_cb
|
.recv = stream_recv_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap_base *base)
|
||||||
|
@ -151,6 +263,7 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap
|
||||||
const size_t bis_count = base->subgroups[i].bis_count;
|
const size_t bis_count = base->subgroups[i].bis_count;
|
||||||
|
|
||||||
printk("Subgroup[%zu] has %zu streams\n", i, bis_count);
|
printk("Subgroup[%zu] has %zu streams\n", i, bis_count);
|
||||||
|
|
||||||
for (size_t j = 0U; j < bis_count; j++) {
|
for (size_t j = 0U; j < bis_count; j++) {
|
||||||
const uint8_t index = base->subgroups[i].bis_data[j].index;
|
const uint8_t index = base->subgroups[i].bis_data[j].index;
|
||||||
|
|
||||||
|
@ -158,6 +271,21 @@ static void base_recv_cb(struct bt_bap_broadcast_sink *sink, const struct bt_bap
|
||||||
|
|
||||||
base_bis_index_bitfield |= BIT(index);
|
base_bis_index_bitfield |= BIT(index);
|
||||||
}
|
}
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
int ret;
|
||||||
|
const struct bt_audio_codec_cfg *codec_cfg = &base->subgroups[i].codec_cfg;
|
||||||
|
|
||||||
|
if (codec_cfg->id != BT_HCI_CODING_FORMAT_LC3) {
|
||||||
|
printk("unsupported codec 0x%02x", codec_cfg->id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lc3_enable(codec_cfg);
|
||||||
|
if (ret < 0) {
|
||||||
|
printk("Error: cannot enable LC3 codec: %d", ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
bis_index_bitfield = base_bis_index_bitfield & bis_index_mask;
|
bis_index_bitfield = base_bis_index_bitfield & bis_index_mask;
|
||||||
|
@ -652,7 +780,6 @@ static int reset(void)
|
||||||
k_sem_reset(&sem_broadcast_code_received);
|
k_sem_reset(&sem_broadcast_code_received);
|
||||||
k_sem_reset(&sem_bis_sync_requested);
|
k_sem_reset(&sem_bis_sync_requested);
|
||||||
k_sem_reset(&sem_bis_synced);
|
k_sem_reset(&sem_bis_synced);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,6 +866,9 @@ int main(void)
|
||||||
|
|
||||||
for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) {
|
for (size_t i = 0U; i < ARRAY_SIZE(streams_p); i++) {
|
||||||
streams_p[i] = &streams[i].stream;
|
streams_p[i] = &streams[i].stream;
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
k_mutex_init(&streams[i].lc3_decoder_mutex);
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
# For LC3 the following configs are needed
|
||||||
|
CONFIG_FPU=y
|
||||||
|
CONFIG_LIBLC3=y
|
||||||
|
# When Host is fixed, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE can inherit the CONFIG_BT_ISO_TX_MTU value.
|
||||||
|
CONFIG_BT_ISO_TX_MTU=40
|
||||||
|
# The LC3 codec uses a large amount of stack. This app runs the codec in the work-queue, hence
|
||||||
|
# inctease stack size for that thread.
|
||||||
|
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
|
||||||
|
# LC3 lib requires floating point support in the c-lib NEWLIB is one way of getting that.
|
||||||
|
CONFIG_NEWLIB_LIBC=y
|
||||||
|
CONFIG_MAIN_STACK_SIZE=4096
|
||||||
|
CONFIG_BT_TINYCRYPT_ECC=y
|
|
@ -9,11 +9,24 @@
|
||||||
#include <zephyr/bluetooth/audio/bap.h>
|
#include <zephyr/bluetooth/audio/bap.h>
|
||||||
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
#include <zephyr/bluetooth/audio/bap_lc3_preset.h>
|
||||||
|
|
||||||
|
/* Zephyr Controller works best while Extended Advertising interval to be a multiple
|
||||||
|
* of the ISO Interval minus 10 ms (max. advertising random delay). This is
|
||||||
|
* required to place the AUX_ADV_IND PDUs in a non-overlapping interval with the
|
||||||
|
* Broadcast ISO radio events.
|
||||||
|
*
|
||||||
|
* I.e. for a 7.5 ms ISO interval use 90 ms minus 10 ms ==> 80 ms advertising
|
||||||
|
* interval.
|
||||||
|
* And, for 10 ms ISO interval, can use 90 ms minus 10 ms ==> 80 ms advertising
|
||||||
|
* interval.
|
||||||
|
*/
|
||||||
|
#define BT_LE_EXT_ADV_CUSTOM \
|
||||||
|
BT_LE_ADV_PARAM(BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME, 0x0080, 0x0080, NULL)
|
||||||
|
|
||||||
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
/* When BROADCAST_ENQUEUE_COUNT > 1 we can enqueue enough buffers to ensure that
|
||||||
* the controller is never idle
|
* the controller is never idle
|
||||||
*/
|
*/
|
||||||
#define BROADCAST_ENQUEUE_COUNT 2U
|
#define BROADCAST_ENQUEUE_COUNT 2U
|
||||||
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)
|
#define TOTAL_BUF_NEEDED (BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT)
|
||||||
|
|
||||||
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
|
BUILD_ASSERT(CONFIG_BT_ISO_TX_BUF_COUNT >= TOTAL_BUF_NEEDED,
|
||||||
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
|
"CONFIG_BT_ISO_TX_BUF_COUNT should be at least "
|
||||||
|
@ -32,7 +45,10 @@ NET_BUF_POOL_FIXED_DEFINE(tx_pool,
|
||||||
TOTAL_BUF_NEEDED,
|
TOTAL_BUF_NEEDED,
|
||||||
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU),
|
||||||
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
|
||||||
static uint8_t mock_data[CONFIG_BT_ISO_TX_MTU];
|
#define MAX_SAMPLE_RATE 16000
|
||||||
|
#define MAX_FRAME_DURATION_US 10000
|
||||||
|
#define MAX_NUM_SAMPLES ((MAX_FRAME_DURATION_US * MAX_SAMPLE_RATE) / USEC_PER_SEC)
|
||||||
|
static int16_t mock_data[MAX_NUM_SAMPLES];
|
||||||
static uint16_t seq_num;
|
static uint16_t seq_num;
|
||||||
static bool stopping;
|
static bool stopping;
|
||||||
|
|
||||||
|
@ -41,6 +57,65 @@ static K_SEM_DEFINE(sem_stopped, 0U, ARRAY_SIZE(streams));
|
||||||
|
|
||||||
#define BROADCAST_SOURCE_LIFETIME 120U /* seconds */
|
#define BROADCAST_SOURCE_LIFETIME 120U /* seconds */
|
||||||
|
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
|
||||||
|
#include "lc3.h"
|
||||||
|
|
||||||
|
static lc3_encoder_t lc3_encoder;
|
||||||
|
static lc3_encoder_mem_16k_t lc3_encoder_mem;
|
||||||
|
static int freq_hz;
|
||||||
|
static int frame_duration_us;
|
||||||
|
static int frames_per_sdu;
|
||||||
|
static int octets_per_frame;
|
||||||
|
|
||||||
|
static void init_lc3(void)
|
||||||
|
{
|
||||||
|
const struct bt_audio_codec_cfg *codec_cfg = &preset_16_2_1.codec_cfg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = bt_audio_codec_cfg_get_freq(codec_cfg);
|
||||||
|
if (ret > 0) {
|
||||||
|
freq_hz = bt_audio_codec_cfg_freq_to_freq_hz(ret);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bt_audio_codec_cfg_get_frame_dur(codec_cfg);
|
||||||
|
if (ret > 0) {
|
||||||
|
frame_duration_us = bt_audio_codec_cfg_frame_dur_to_frame_dur_us(ret);
|
||||||
|
} else {
|
||||||
|
printk("Error: Frame duration not set, cannot start codec.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
octets_per_frame = bt_audio_codec_cfg_get_octets_per_frame(codec_cfg);
|
||||||
|
frames_per_sdu = bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true);
|
||||||
|
|
||||||
|
if (freq_hz < 0) {
|
||||||
|
printk("Error: Codec frequency not set, cannot start codec.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_duration_us < 0) {
|
||||||
|
printk("Error: Frame duration not set, cannot start codec.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (octets_per_frame < 0) {
|
||||||
|
printk("Error: Octets per frame not set, cannot start codec.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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_mem);
|
||||||
|
|
||||||
|
if (lc3_encoder == NULL) {
|
||||||
|
printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
static void stream_started_cb(struct bt_bap_stream *stream)
|
static void stream_started_cb(struct bt_bap_stream *stream)
|
||||||
{
|
{
|
||||||
struct broadcast_source_stream *source_stream =
|
struct broadcast_source_stream *source_stream =
|
||||||
|
@ -75,7 +150,28 @@ static void stream_sent_cb(struct bt_bap_stream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
net_buf_reserve(buf, BT_ISO_CHAN_SEND_RESERVE);
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
int lc3_ret;
|
||||||
|
uint8_t lc3_encoder_buffer[preset_16_2_1.qos.sdu];
|
||||||
|
|
||||||
|
if (lc3_encoder == NULL) {
|
||||||
|
printk("LC3 encoder not setup, cannot encode data.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lc3_ret = lc3_encode(lc3_encoder, LC3_PCM_FORMAT_S16, mock_data, 1, octets_per_frame,
|
||||||
|
lc3_encoder_buffer);
|
||||||
|
|
||||||
|
if (lc3_ret == -1) {
|
||||||
|
printk("LC3 encoder failed - wrong parameters?: %d", lc3_ret);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_add_mem(buf, lc3_encoder_buffer, preset_16_2_1.qos.sdu);
|
||||||
|
#else
|
||||||
net_buf_add_mem(buf, mock_data, preset_16_2_1.qos.sdu);
|
net_buf_add_mem(buf, mock_data, preset_16_2_1.qos.sdu);
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
ret = bt_bap_stream_send(stream, buf, source_stream->seq_num++, BT_ISO_TIMESTAMP_NONE);
|
ret = bt_bap_stream_send(stream, buf, source_stream->seq_num++, BT_ISO_TIMESTAMP_NONE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* This will end broadcasting on this stream. */
|
/* This will end broadcasting on this stream. */
|
||||||
|
@ -157,6 +253,10 @@ int main(void)
|
||||||
mock_data[i] = i;
|
mock_data[i] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_LIBLC3)
|
||||||
|
init_lc3();
|
||||||
|
#endif /* defined(CONFIG_LIBLC3) */
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Broadcast Audio Streaming Endpoint advertising data */
|
/* Broadcast Audio Streaming Endpoint advertising data */
|
||||||
NET_BUF_SIMPLE_DEFINE(ad_buf,
|
NET_BUF_SIMPLE_DEFINE(ad_buf,
|
||||||
|
@ -167,7 +267,7 @@ int main(void)
|
||||||
uint32_t broadcast_id;
|
uint32_t broadcast_id;
|
||||||
|
|
||||||
/* Create a non-connectable non-scannable advertising set */
|
/* Create a non-connectable non-scannable advertising set */
|
||||||
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN_NAME, NULL, &adv);
|
err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CUSTOM, NULL, &adv);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
printk("Unable to create extended advertising set: %d\n",
|
printk("Unable to create extended advertising set: %d\n",
|
||||||
err);
|
err);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue