apps: Merge auracast and auracast_usb applications

This adds new AUDIO_USB syscfg option to disable the USB audio support
in auracast_usb application.
This fixes code duplication, so that auracast_usb has been renamed
to auracast, where previous auracast application has been removed.
This commit is contained in:
Mariusz Skamra
2024-11-29 10:09:18 +01:00
committed by Szymon Janc
parent a04e52e610
commit 5a94d71784
12 changed files with 328 additions and 669 deletions
+9
View File
@@ -32,8 +32,17 @@ pkg.deps:
- nimble/host/store/config
- nimble/host/audio/services/auracast
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/config"
- "@apache-mynewt-core/sys/console"
- "@apache-mynewt-core/sys/log"
- "@apache-mynewt-core/sys/stats"
- "@apache-mynewt-core/sys/sysinit"
- "@apache-mynewt-core/sys/id"
pkg.deps.AUDIO_USB:
- ext/liblc3
- ext/libsamplerate
- "@apache-mynewt-core/hw/usb/tinyusb"
pkg.init:
audio_init: 402
@@ -21,6 +21,7 @@
#define H_APP_PRIV_
#include <syscfg/syscfg.h>
#include <stdint.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -40,10 +41,5 @@
#define LC3_FPDT (AUDIO_PCM_SAMPLE_RATE * LC3_FRAME_DURATION / 1000000)
#define BIG_NUM_BIS (MIN(AUDIO_CHANNELS, MYNEWT_VAL(BIG_NUM_BIS)))
struct chan {
void *encoder;
uint16_t handle;
};
extern struct chan chans[AUDIO_CHANNELS];
void audio_chan_set_conn_handle(uint8_t chan_idx, uint16_t conn_handle);
#endif /* H_APP_PRIV_ */
@@ -18,13 +18,26 @@
*/
#include <assert.h>
#include <os/os.h>
#include <stdint.h>
#include <string.h>
#include <syscfg/syscfg.h>
#include <os/os.h>
#include "console/console.h"
#include "host/ble_hs.h"
#include "host/ble_iso.h"
#include "app_priv.h"
struct chan {
void *encoder;
uint16_t handle;
} chans[AUDIO_CHANNELS];
#if MYNEWT_VAL(AUDIO_USB)
#include <common/tusb_fifo.h>
#include <class/audio/audio_device.h>
#include <usb_audio.h>
#include "console/console.h"
#include <lc3.h>
#include <samplerate.h>
@@ -33,16 +46,12 @@
#include "host/ble_gap.h"
#include "os/os_cputime.h"
#include "app_priv.h"
#define AUDIO_BUF_SIZE 1024
static uint8_t g_usb_enabled;
static void usb_data_func(struct os_event *ev);
struct chan chans[AUDIO_CHANNELS];
static struct os_event usb_data_ev = {
.ev_cb = usb_data_func,
};
@@ -239,7 +248,7 @@ tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received,
return true;
}
void
static void
audio_usb_init(void)
{
/* Need to reference those explicitly, so they are always pulled by linker
@@ -280,3 +289,90 @@ audio_usb_init(void)
resampler_ratio = resampler_out_rate / resampler_in_rate;
#endif
}
#else
#include "audio_data.h"
#define BROADCAST_MAX_SDU 120
static int audio_data_offset;
static struct os_callout audio_broadcast_callout;
static void
audio_broadcast_event_cb(struct os_event *ev)
{
assert(ev != NULL);
uint32_t ev_start_time = os_cputime_ticks_to_usecs(os_cputime_get32());
#if MYNEWT_VAL(AURACAST_CHAN_NUM) > 1
if (audio_data_offset + BROADCAST_MAX_SDU >= sizeof(audio_data)) {
audio_data_offset = 0;
}
if (chans[0].handle != BLE_HS_CONN_HANDLE_NONE) {
ble_iso_tx(chans[0].handle, (void *) (audio_data + audio_data_offset),
BROADCAST_MAX_SDU);
}
if (chans[1].handle != BLE_HS_CONN_HANDLE_NONE) {
ble_iso_tx(chans[1].handle, (void *) (audio_data + audio_data_offset),
BROADCAST_MAX_SDU);
}
#else
if (audio_data_offset + 2 * BROADCAST_MAX_SDU >= sizeof(audio_data)) {
audio_data_offset = 0;
}
uint8_t lr_payload[BROADCAST_MAX_SDU * 2];
memcpy(lr_payload, audio_data + audio_data_offset, BROADCAST_MAX_SDU);
memcpy(lr_payload + BROADCAST_MAX_SDU, audio_data + audio_data_offset,
BROADCAST_MAX_SDU);
if (chans[0].handle != BLE_HS_CONN_HANDLE_NONE) {
ble_iso_tx(chans[0].handle, (void *) (lr_payload),
BROADCAST_MAX_SDU * 2);
}
#endif
audio_data_offset += BROADCAST_MAX_SDU;
/** Use cputime to time LC3_FRAME_DURATION, as these ticks are more
* accurate than os_time ones. This assures that we do not push
* LC3 data to ISO before interval, which could lead to
* controller running out of buffers. This is only needed because
* we already have coded data in an array - in real world application
* we usually wait for new audio to arrive, and lose time to code it too.
*/
while (os_cputime_ticks_to_usecs(os_cputime_get32()) - ev_start_time <
(MYNEWT_VAL(LC3_FRAME_DURATION)));
os_callout_reset(&audio_broadcast_callout, 0);
}
static void
audio_dummy_init(void)
{
os_callout_init(&audio_broadcast_callout, os_eventq_dflt_get(),
audio_broadcast_event_cb, NULL);
os_callout_reset(&audio_broadcast_callout, 0);
}
#endif /* AUDIO_USB */
void
audio_init(void)
{
for (size_t i = 0; i < ARRAY_SIZE(chans); i++) {
chans[i].handle = BLE_HS_CONN_HANDLE_NONE;
}
#if MYNEWT_VAL(AUDIO_USB)
audio_usb_init();
#else
audio_dummy_init();
#endif /* AUDIO_USB */
}
void
audio_chan_set_conn_handle(uint8_t chan_idx, uint16_t conn_handle)
{
assert(chan_idx < ARRAY_SIZE(chans));
chans[chan_idx].handle = conn_handle;
}
+124 -135
View File
@@ -28,13 +28,35 @@
#include "hal/hal_gpio.h"
#include "bsp/bsp.h"
#include "audio_data.h"
#include "app_priv.h"
#define BROADCAST_SID 1
#define BROADCAST_MAX_SDU 120
#define BROADCAST_SDU_INTVL 10000
#if (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 8000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_8000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 16000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_16000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 24000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_24000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 32000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_32000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 48000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_48000_HZ
#else
BUILD_ASSERT(0, "Sample frequency not supported");
#endif
/* Note: values need to be adjusted if sampling frequency is 44100 (currently
* not supported by app) or SDU interval is different from LC3 frame
* length
*/
#define OCTETS_PER_CODEC_FRAME (MYNEWT_VAL(LC3_BITRATE) / \
8 * MYNEWT_VAL(LC3_FRAME_DURATION) / \
1000000)
#define BIG_SDU_INTERVAL (MYNEWT_VAL(LC3_FRAME_DURATION))
#define BIG_MAX_SDU (OCTETS_PER_CODEC_FRAME * \
MYNEWT_VAL(AURACAST_CHAN_NUM) / \
MYNEWT_VAL(BIG_NUM_BIS))
#define BROADCASTER_INTERRUPT_TASK_PRIO 4
#define BROADCASTER_INTERRUPT_TASK_STACK_SZ 512
@@ -45,160 +67,83 @@ static struct ble_audio_base auracast_base;
static struct ble_audio_big_subgroup big_subgroup;
static os_membuf_t bis_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BROADCASTER_CHAN_NUM),
OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS),
sizeof(struct ble_audio_bis))
];
static struct os_mempool bis_pool;
static os_membuf_t codec_spec_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 19)
OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS) * 2, 19)
];
static struct os_mempool codec_spec_pool;
static uint16_t bis_handles[MYNEWT_VAL(BROADCASTER_CHAN_NUM)];
/* The timer callout */
static struct os_callout audio_broadcast_callout;
static int audio_data_offset;
static uint8_t auracast_adv_instance;
#if MYNEWT_VAL(BROADCASTER_STOP_BUTTON) >= 0
static struct os_task auracast_interrupt_task_str;
static struct os_eventq auracast_interrupt_eventq;
static os_stack_t auracast_interrupt_task_stack[BROADCASTER_INTERRUPT_TASK_STACK_SZ];
static void
auracast_interrupt_task(void *arg)
{
while (1) {
os_eventq_run(&auracast_interrupt_eventq);
}
}
static void
broadcast_stop_ev_cb(struct os_event *ev)
{
ble_svc_auracast_stop(auracast_adv_instance);
ble_svc_auracast_terminate(auracast_adv_instance);
}
static struct os_event broadcast_stop_ev = {
.ev_cb = broadcast_stop_ev_cb,
};
static void
auracast_gpio_irq(void *arg)
{
os_eventq_put(&auracast_interrupt_eventq, &broadcast_stop_ev);
}
#endif /* MYNEWT_VAL(BROADCASTER_STOP_BUTTON) >= 0 */
static void
audio_broadcast_event_cb(struct os_event *ev)
{
assert(ev != NULL);
uint32_t ev_start_time = os_cputime_ticks_to_usecs(os_cputime_get32());
#if MYNEWT_VAL(BROADCASTER_CHAN_NUM) > 1
if (audio_data_offset + BROADCAST_MAX_SDU >= sizeof(audio_data)) {
audio_data_offset = 0;
}
ble_iso_tx(bis_handles[0], (void *)(audio_data + audio_data_offset),
BROADCAST_MAX_SDU);
ble_iso_tx(bis_handles[1], (void *)(audio_data + audio_data_offset),
BROADCAST_MAX_SDU);
#else
if (audio_data_offset + 2 * BROADCAST_MAX_SDU >= sizeof(audio_data)) {
audio_data_offset = 0;
}
uint8_t lr_payload[BROADCAST_MAX_SDU * 2];
memcpy(lr_payload, audio_data + audio_data_offset, BROADCAST_MAX_SDU);
memcpy(lr_payload + BROADCAST_MAX_SDU, audio_data + audio_data_offset,
BROADCAST_MAX_SDU);
ble_iso_tx(bis_handles[0], (void *)(lr_payload),
BROADCAST_MAX_SDU * 2);
#endif
audio_data_offset += BROADCAST_MAX_SDU;
/** Use cputime to time BROADCAST_SDU_INTVL, as these ticks are more
* accurate than os_time ones. This assures that we do not push
* LC3 data to ISO before interval, which could lead to
* controller running out of buffers. This is only needed because
* we already have coded data in an array - in real world application
* we usually wait for new audio to arrive, and lose time to code it too.
*/
while (os_cputime_ticks_to_usecs(os_cputime_get32()) - ev_start_time <
(BROADCAST_SDU_INTVL));
os_callout_reset(&audio_broadcast_callout, 0);
}
static int
broadcast_audio()
{
os_callout_reset(&audio_broadcast_callout, 0);
return 0;
}
static void
auracast_init()
auracast_init(void)
{
int rc;
os_callout_init(&audio_broadcast_callout, os_eventq_dflt_get(),
audio_broadcast_event_cb, NULL);
assert(MYNEWT_VAL(AURACAST_CHAN_NUM) > 0);
assert(MYNEWT_VAL(BROADCASTER_CHAN_NUM) > 0);
rc = os_mempool_init(&bis_pool, MYNEWT_VAL(BROADCASTER_CHAN_NUM),
rc = os_mempool_init(&bis_pool, MYNEWT_VAL(BIG_NUM_BIS),
sizeof(struct ble_audio_bis), bis_mem,
"bis_pool");
assert(rc == 0);
rc = os_mempool_init(&codec_spec_pool,
MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 19,
MYNEWT_VAL(BIG_NUM_BIS) * 2, 19,
codec_spec_mem, "codec_spec_pool");
assert(rc == 0);
}
static int
base_create()
base_create(void)
{
#if MYNEWT_VAL(BROADCASTER_CHAN_NUM) > 1
#if MYNEWT_VAL(BIG_NUM_BIS) > 1
struct ble_audio_bis *bis_left;
struct ble_audio_bis *bis_right;
uint8_t codec_spec_config_left_chan[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
BLE_AUDIO_LOCATION_FRONT_LEFT,
BROADCAST_MAX_SDU, );
OCTETS_PER_CODEC_FRAME, );
uint8_t codec_spec_config_right_chan[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
BLE_AUDIO_LOCATION_FRONT_RIGHT,
BROADCAST_MAX_SDU, );
OCTETS_PER_CODEC_FRAME, );
#else
uint16_t chan_loc = BLE_AUDIO_LOCATION_FRONT_LEFT |
BLE_AUDIO_LOCATION_FRONT_RIGHT;
uint8_t codec_spec_config[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
chan_loc,
BROADCAST_MAX_SDU * 2, );
OCTETS_PER_CODEC_FRAME, );
struct ble_audio_bis *bis;
#endif
auracast_base.broadcast_id = 0x42;
if (MYNEWT_VAL(BROADCAST_ID) != 0) {
auracast_base.broadcast_id = MYNEWT_VAL(BROADCAST_ID);
} else {
ble_hs_hci_rand(&auracast_base.broadcast_id, 3);
}
auracast_base.presentation_delay = 20000;
big_subgroup.bis_cnt = MYNEWT_VAL(BROADCASTER_CHAN_NUM);
big_subgroup.bis_cnt = MYNEWT_VAL(BIG_NUM_BIS);
/** LC3 */
big_subgroup.codec_id.format = 0x06;
big_subgroup.codec_spec_config_len = 0;
#if MYNEWT_VAL(BROADCASTER_CHAN_NUM) > 1
#if MYNEWT_VAL(BIG_NUM_BIS) > 1
bis_left = os_memblock_get(&bis_pool);
if (!bis_left) {
return BLE_HS_ENOMEM;
@@ -248,6 +193,7 @@ static int
auracast_destroy_fn(struct ble_audio_base *base, void *args)
{
struct ble_audio_bis *bis;
int i;
STAILQ_FOREACH(bis, &big_subgroup.bises, next) {
os_memblock_put(&codec_spec_pool, bis->codec_spec_config);
@@ -256,6 +202,10 @@ auracast_destroy_fn(struct ble_audio_base *base, void *args)
memset(&big_subgroup, 0, sizeof(big_subgroup));
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
audio_chan_set_conn_handle(i, BLE_HS_CONN_HANDLE_NONE);
}
return 0;
}
@@ -268,13 +218,18 @@ iso_event(struct ble_iso_event *event, void *arg)
case BLE_ISO_EVENT_BIG_CREATE_COMPLETE:
console_printf("BIG created\n");
if (event->big_created.desc.num_bis >
MYNEWT_VAL(BROADCASTER_CHAN_NUM)) {
MYNEWT_VAL(AURACAST_CHAN_NUM)) {
return BLE_HS_EINVAL;
}
for (i = 0; i < MYNEWT_VAL(BROADCASTER_CHAN_NUM); i++) {
bis_handles[i] = event->big_created.desc.conn_handle[i];
if (MYNEWT_VAL(AURACAST_CHAN_NUM) == event->big_created.desc.num_bis) {
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
audio_chan_set_conn_handle(i, event->big_created.desc.conn_handle[i]);
}
} else {
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
audio_chan_set_conn_handle(i, event->big_created.desc.conn_handle[0]);
}
}
broadcast_audio();
return 0;
case BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE:
console_printf("BIG terminated\n");
@@ -285,32 +240,32 @@ iso_event(struct ble_iso_event *event, void *arg)
}
static int
auracast_create()
auracast_create(void)
{
const char *program_info = "NimBLE Auracast Test";
static struct ble_iso_big_params big_params = {
.sdu_interval = BROADCAST_SDU_INTVL,
.max_sdu = MYNEWT_VAL(BROADCASTER_CHAN_NUM) > 1 ?
BROADCAST_MAX_SDU : BROADCAST_MAX_SDU * 2,
.max_transport_latency = BROADCAST_SDU_INTVL / 1000,
.rtn = 0,
.phy = BLE_HCI_LE_PHY_2M,
.packing = 0,
.framing = 0,
.encryption = 0,
.sdu_interval = BIG_SDU_INTERVAL,
.max_sdu = BIG_MAX_SDU,
.max_transport_latency = MYNEWT_VAL(LC3_FRAME_DURATION) / 1000,
.rtn = MYNEWT_VAL(BIG_RTN),
.phy = MYNEWT_VAL(BIG_PHY),
.packing = MYNEWT_VAL(BIG_PACKING),
.framing = MYNEWT_VAL(BIG_FRAMING),
.encryption = MYNEWT_VAL(BIG_ENCRYPTION),
.broadcast_code = MYNEWT_VAL(BROADCAST_CODE),
};
struct ble_svc_auracast_create_params create_params = {
.base = &auracast_base,
.big_params = &big_params,
.name = MYNEWT_VAL(BROADCASTER_BROADCAST_NAME),
.name = MYNEWT_VAL(BROADCAST_NAME),
.program_info = program_info,
.own_addr_type = id_addr_type,
.secondary_phy = BLE_HCI_LE_PHY_2M,
.sid = BROADCAST_SID,
.frame_duration = 10000,
.sampling_frequency = 48000,
.bitrate = 48000,
.frame_duration = MYNEWT_VAL(LC3_FRAME_DURATION),
.sampling_frequency = MYNEWT_VAL(LC3_SAMPLING_FREQ),
.bitrate = MYNEWT_VAL(LC3_BITRATE),
};
return ble_svc_auracast_create(&create_params,
@@ -321,7 +276,7 @@ auracast_create()
}
static int
auracast_start()
auracast_start(void)
{
return ble_svc_auracast_start(auracast_adv_instance, iso_event, NULL);
}
@@ -351,10 +306,44 @@ on_sync(void)
rc = auracast_start();
assert(rc == 0);
broadcast_audio();
}
#if MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0
#include "hal/hal_gpio.h"
#include "bsp/bsp.h"
#define AURACAST_INTERRUPT_TASK_PRIO 4
#define AURACAST_INTERRUPT_TASK_STACK_SZ 512
static struct os_task auracast_interrupt_task_str;
static struct os_eventq auracast_interrupt_eventq;
static os_stack_t auracast_interrupt_task_stack[AURACAST_INTERRUPT_TASK_STACK_SZ];
static void
auracast_interrupt_task(void *arg)
{
while (1) {
os_eventq_run(&auracast_interrupt_eventq);
}
}
static void
broadcast_stop_ev_cb(struct os_event *ev)
{
ble_svc_auracast_stop(auracast_adv_instance);
ble_svc_auracast_terminate(auracast_adv_instance);
}
static struct os_event broadcast_stop_ev = {
.ev_cb = broadcast_stop_ev_cb,
};
static void
auracast_gpio_irq(void *arg)
{
os_eventq_put(&auracast_interrupt_eventq, &broadcast_stop_ev);
}
#endif /* MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 */
/*
* main
*
@@ -374,18 +363,18 @@ mynewt_main(int argc, char **argv)
/* Set sync callback */
ble_hs_cfg.sync_cb = on_sync;
#if MYNEWT_VAL(BROADCASTER_STOP_BUTTON) >= 0
#if MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0
os_eventq_init(&auracast_interrupt_eventq);
os_task_init(&auracast_interrupt_task_str, "auracast_interrupt_task",
auracast_interrupt_task, NULL,
BROADCASTER_INTERRUPT_TASK_PRIO, OS_WAIT_FOREVER,
AURACAST_INTERRUPT_TASK_PRIO, OS_WAIT_FOREVER,
auracast_interrupt_task_stack,
BROADCASTER_INTERRUPT_TASK_STACK_SZ);
AURACAST_INTERRUPT_TASK_STACK_SZ);
hal_gpio_irq_init(MYNEWT_VAL(BROADCASTER_STOP_BUTTON), auracast_gpio_irq,
hal_gpio_irq_init(MYNEWT_VAL(AURACAST_STOP_BUTTON), auracast_gpio_irq,
NULL, HAL_GPIO_TRIG_RISING, HAL_GPIO_PULL_UP);
hal_gpio_irq_enable(MYNEWT_VAL(BROADCASTER_STOP_BUTTON));
#endif /* MYNEWT_VAL(BROADCASTER_STOP_BUTTON) >= 0 */
hal_gpio_irq_enable(MYNEWT_VAL(AURACAST_STOP_BUTTON));
#endif /* MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 */
/* As the last thing, process events from default event queue */
while (1) {
@@ -17,8 +17,10 @@
* under the License.
*/
#include <assert.h>
#include <syscfg/syscfg.h>
#if MYNEWT_VAL(AUDIO_USB)
#include <assert.h>
#include <bsp/bsp.h>
#include <string.h>
#include <tusb.h>
@@ -393,3 +395,4 @@ usb_desc_sample_rate_set(uint32_t sample_rate)
{
g_sample_rate = sample_rate;
}
#endif /* AUDIO_USB */
+86 -4
View File
@@ -16,14 +16,65 @@
# under the License.
syscfg.defs:
BROADCASTER_CHAN_NUM: 2
BROADCASTER_BROADCAST_NAME: '"NimBLE Auracast"'
BROADCASTER_STOP_BUTTON:
AUDIO_USB:
description: Enable USB audio output device driver.
value: 1
restrictions:
# For now, LC3 encoded audio data, with 48kHz sample rate is supported only.
- '(LC3_SAMPLING_FREQ == 48000) if 0'
- '(LC3_FRAME_DURATION == 10000) is 0'
ISO_HCI_FEEDBACK:
description: Enable HCI feedback for resampler. This reduces jitter between USB and ISO.
value: 0
AURACAST_CHAN_NUM: 2
AURACAST_STOP_BUTTON:
description: >
Button number for Broadcast Stop action.
Button number for Auracast Stop action.
Negative value if disabled.
value: BUTTON_3
BROADCAST_ID:
description: Broadcast ID value, will use random number if 0
value: 0x000000
BROADCAST_NAME:
description: Broadcast name
value: '"NimBLE Auracast"'
BROADCAST_CODE:
description: Broadcast code used for encrpytion
value: '"listen2nimble"'
LC3_FRAME_DURATION:
description: LC3 frame duration
value: 10000
LC3_SAMPLING_FREQ:
description: LC3 sampling frequency
value: 48000
LC3_BITRATE:
description: LC3 bitrate
value: 96000
BIG_PHY:
description:
value: 2
BIG_NUM_BIS:
description: Max number of BISes used
value: 2
BIG_RTN:
description: BIG RTN (number of retransmissions)
value: 0
BIG_PACKING:
description: Arrangement of BIS subevents (0 = sequential, 1 = interleaved)
value: 0
BIG_FRAMING:
description:
value: 0
BIG_ENCRYPTION:
description: BIS encryption
value: 0
syscfg.vals:
CONSOLE_IMPLEMENTATION: full
LOG_IMPLEMENTATION: full
@@ -65,3 +116,34 @@ syscfg.vals:
BLE_ISO_MAX_BISES: 2
BLE_AUDIO: 1
MCU_HFCLK_DIV: 1
HARDFLOAT: 1
syscfg.vals.AUDIO_USB:
# TinyUSB
USBD_VID: 0xFFFF
USBD_PID: 0x0001
USBD_VENDOR_STRING: '"Apache Software Foundation"'
USBD_PRODUCT_STRING: '"NimBLE Auracast"'
USBD_AUDIO_OUT: 1
USBD_STACK_SIZE: 500
USBD_STD_DESCRIPTORS: 0
USB_AUDIO_OUT_CHANNELS: MYNEWT_VAL(AURACAST_CHAN_NUM)
# Resampler
LIBSAMPLERATE_ENABLE_SINC_BEST_CONVERTER: 0
LIBSAMPLERATE_ENABLE_SINC_MEDIUM_CONVERTER: 0
LIBSAMPLERATE_ENABLE_SINC_FAST_CONVERTER: 1
LIBSAMPLERATE_LIBSAMPLER_NDEBUG: 1
syscfg.vals.ISO_HCI_FEEDBACK:
BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS: 1000
BLE_HS_GAP_UNHANDLED_HCI_EVENT: 1
syscfg.vals.BSP_NRF52:
BLE_PHY_NRF52_HEADERMASK_WORKAROUND: 1
$import:
- "@apache-mynewt-nimble/apps/auracast/syscfg.usb.yml"
-46
View File
@@ -1,46 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
pkg.name: apps/auracast_usb
pkg.type: app
pkg.description: Auracast sample application.
pkg.author: "Krzysztof Kopyściński"
pkg.email: "[email protected]"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/sys/config"
- nimble/host
- nimble/host/util
- nimble/host/services/gap
- nimble/host/store/config
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/console"
- "@apache-mynewt-core/sys/log"
- "@apache-mynewt-core/sys/stats"
- "@apache-mynewt-core/sys/sysinit"
- "@apache-mynewt-core/sys/id"
- "@apache-mynewt-core/hw/usb/tinyusb"
- "@apache-mynewt-nimble/nimble/host/audio/services/auracast"
- "@apache-mynewt-nimble/ext/liblc3"
- "@apache-mynewt-nimble/ext/libsamplerate"
pkg.init:
audio_usb_init: 402
-336
View File
@@ -1,336 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "console/console.h"
#include "config/config.h"
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/auracast/ble_svc_auracast.h"
#include "hal/hal_gpio.h"
#include "bsp/bsp.h"
#include "app_priv.h"
#define BROADCAST_SID 1
#if (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 8000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_8000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 16000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_16000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 24000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_24000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 32000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_32000_HZ
#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 48000)
#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_48000_HZ
#else
BUILD_ASSERT(0, "Sample frequency not supported");
#endif
/* Note: values need to be adjusted if sampling frequency is 44100 (currently
* not supported by app) or SDU interval is different from LC3 frame
* length
*/
#define OCTETS_PER_CODEC_FRAME (MYNEWT_VAL(LC3_BITRATE) / \
8 * MYNEWT_VAL(LC3_FRAME_DURATION) / \
1000000)
#define BIG_SDU_INTERVAL (MYNEWT_VAL(LC3_FRAME_DURATION))
#define BIG_MAX_SDU (OCTETS_PER_CODEC_FRAME * \
MYNEWT_VAL(AURACAST_CHAN_NUM) / \
MYNEWT_VAL(BIG_NUM_BIS))
#define BROADCASTER_INTERRUPT_TASK_PRIO 4
#define BROADCASTER_INTERRUPT_TASK_STACK_SZ 512
static uint8_t id_addr_type;
static struct ble_audio_base auracast_base;
static struct ble_audio_big_subgroup big_subgroup;
static os_membuf_t bis_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS),
sizeof(struct ble_audio_bis))
];
static struct os_mempool bis_pool;
static os_membuf_t codec_spec_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS) * 2, 19)
];
static struct os_mempool codec_spec_pool;
static uint8_t auracast_adv_instance;
static void
auracast_init(void)
{
int rc;
assert(MYNEWT_VAL(AURACAST_CHAN_NUM) > 0);
rc = os_mempool_init(&bis_pool, MYNEWT_VAL(BIG_NUM_BIS),
sizeof(struct ble_audio_bis), bis_mem,
"bis_pool");
assert(rc == 0);
rc = os_mempool_init(&codec_spec_pool,
MYNEWT_VAL(BIG_NUM_BIS) * 2, 19,
codec_spec_mem, "codec_spec_pool");
assert(rc == 0);
}
static int
base_create(void)
{
#if MYNEWT_VAL(BIG_NUM_BIS) > 1
struct ble_audio_bis *bis_left;
struct ble_audio_bis *bis_right;
uint8_t codec_spec_config_left_chan[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
BLE_AUDIO_LOCATION_FRONT_LEFT,
OCTETS_PER_CODEC_FRAME, );
uint8_t codec_spec_config_right_chan[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
BLE_AUDIO_LOCATION_FRONT_RIGHT,
OCTETS_PER_CODEC_FRAME, );
#else
uint16_t chan_loc = BLE_AUDIO_LOCATION_FRONT_LEFT |
BLE_AUDIO_LOCATION_FRONT_RIGHT;
uint8_t codec_spec_config[] =
BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE,
MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ?
BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS :
BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS,
chan_loc,
OCTETS_PER_CODEC_FRAME, );
struct ble_audio_bis *bis;
#endif
if (MYNEWT_VAL(BROADCAST_ID) != 0) {
auracast_base.broadcast_id = MYNEWT_VAL(BROADCAST_ID);
} else {
ble_hs_hci_rand(&auracast_base.broadcast_id, 3);
}
auracast_base.presentation_delay = 20000;
big_subgroup.bis_cnt = MYNEWT_VAL(BIG_NUM_BIS);
/** LC3 */
big_subgroup.codec_id.format = 0x06;
big_subgroup.codec_spec_config_len = 0;
#if MYNEWT_VAL(BIG_NUM_BIS) > 1
bis_left = os_memblock_get(&bis_pool);
if (!bis_left) {
return BLE_HS_ENOMEM;
}
bis_left->codec_spec_config = os_memblock_get(&codec_spec_pool);
memcpy(bis_left->codec_spec_config,
codec_spec_config_left_chan,
sizeof(codec_spec_config_left_chan));
bis_left->codec_spec_config_len = sizeof(codec_spec_config_left_chan);
bis_left->idx = 1;
bis_right = os_memblock_get(&bis_pool);
if (!bis_right) {
return BLE_HS_ENOMEM;
}
bis_right->codec_spec_config = os_memblock_get(&codec_spec_pool);
memcpy(bis_right->codec_spec_config,
codec_spec_config_right_chan,
sizeof(codec_spec_config_right_chan));
bis_right->codec_spec_config_len = sizeof(codec_spec_config_right_chan);
bis_right->idx = 2;
STAILQ_INSERT_HEAD(&big_subgroup.bises, bis_left, next);
STAILQ_INSERT_TAIL(&big_subgroup.bises, bis_right, next);
#else
bis = os_memblock_get(&bis_pool);
if (!bis) {
return BLE_HS_ENOMEM;
}
bis->codec_spec_config = os_memblock_get(&codec_spec_pool);
memcpy(bis->codec_spec_config,
codec_spec_config,
sizeof(codec_spec_config));
bis->codec_spec_config_len = sizeof(codec_spec_config);
STAILQ_INSERT_HEAD(&big_subgroup.bises, bis, next);
#endif
STAILQ_INSERT_HEAD(&auracast_base.subs, &big_subgroup, next);
auracast_base.num_subgroups++;
return 0;
}
static int
auracast_destroy_fn(struct ble_audio_base *base, void *args)
{
struct ble_audio_bis *bis;
int i;
STAILQ_FOREACH(bis, &big_subgroup.bises, next) {
os_memblock_put(&codec_spec_pool, bis->codec_spec_config);
os_memblock_put(&bis_pool, bis);
}
memset(&big_subgroup, 0, sizeof(big_subgroup));
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
chans[i].handle = 0;
}
return 0;
}
static int
iso_event(struct ble_iso_event *event, void *arg)
{
int i;
switch (event->type) {
case BLE_ISO_EVENT_BIG_CREATE_COMPLETE:
console_printf("BIG created\n");
if (event->big_created.desc.num_bis >
MYNEWT_VAL(AURACAST_CHAN_NUM)) {
return BLE_HS_EINVAL;
}
if (MYNEWT_VAL(AURACAST_CHAN_NUM) == event->big_created.desc.num_bis) {
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
chans[i].handle = event->big_created.desc.conn_handle[i];
}
} else {
for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) {
chans[i].handle = event->big_created.desc.conn_handle[0];
}
}
return 0;
case BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE:
console_printf("BIG terminated\n");
return 0;
default:
return BLE_HS_ENOTSUP;
}
}
static int
auracast_create(void)
{
const char *program_info = "NimBLE Auracast Test";
static struct ble_iso_big_params big_params = {
.sdu_interval = BIG_SDU_INTERVAL,
.max_sdu = BIG_MAX_SDU,
.max_transport_latency = MYNEWT_VAL(LC3_FRAME_DURATION) / 1000,
.rtn = MYNEWT_VAL(BIG_RTN),
.phy = MYNEWT_VAL(BIG_PHY),
.packing = MYNEWT_VAL(BIG_PACKING),
.framing = MYNEWT_VAL(BIG_FRAMING),
.encryption = MYNEWT_VAL(BIG_ENCRYPTION),
.broadcast_code = MYNEWT_VAL(BROADCAST_CODE),
};
struct ble_svc_auracast_create_params create_params = {
.base = &auracast_base,
.big_params = &big_params,
.name = MYNEWT_VAL(BROADCAST_NAME),
.program_info = program_info,
.own_addr_type = id_addr_type,
.secondary_phy = BLE_HCI_LE_PHY_2M,
.sid = BROADCAST_SID,
.frame_duration = MYNEWT_VAL(LC3_FRAME_DURATION),
.sampling_frequency = MYNEWT_VAL(LC3_SAMPLING_FREQ),
.bitrate = MYNEWT_VAL(LC3_BITRATE),
};
return ble_svc_auracast_create(&create_params,
&auracast_adv_instance,
auracast_destroy_fn,
NULL,
NULL);
}
static int
auracast_start(void)
{
return ble_svc_auracast_start(auracast_adv_instance, iso_event, NULL);
}
static void
on_sync(void)
{
int rc;
console_printf("Bluetooth initialized\n");
/* Make sure we have proper identity address set (public preferred) */
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* configure global address */
rc = ble_hs_id_infer_auto(0, &id_addr_type);
assert(rc == 0);
auracast_init();
rc = base_create();
assert(rc == 0);
rc = auracast_create();
assert(rc == 0);
rc = auracast_start();
assert(rc == 0);
}
/*
* main
*
* The main task for the project. This function initializes the packages,
* then starts serving events from default event queue.
*
* @return int NOTE: this function should never return!
*/
int
mynewt_main(int argc, char **argv)
{
/* Initialize OS */
sysinit();
console_printf("LE Audio Broadcast sample application\n");
/* Set sync callback */
ble_hs_cfg.sync_cb = on_sync;
/* As the last thing, process events from default event queue */
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
return 0;
}
-134
View File
@@ -1,134 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
syscfg.defs:
ISO_HCI_FEEDBACK:
description: Enable HCI feedback for resampler. This reduces jitter between USB and ISO.
value: 0
AURACAST_CHAN_NUM: 2
BROADCAST_ID:
description: Broadcast ID value, will use random number if 0
value: 0x000000
BROADCAST_NAME:
description: Broadcast name
value: '"NimBLE Auracast"'
BROADCAST_CODE:
description: Broadcast code used for encrpytion
value: '"listen2nimble"'
LC3_FRAME_DURATION:
description: LC3 frame duration
value: 10000
LC3_SAMPLING_FREQ:
description: LC3 sampling frequency
value: 48000
LC3_BITRATE:
description: LC3 bitrate
value: 96000
BIG_PHY:
description:
value: 2
BIG_NUM_BIS:
description: Max number of BISes used
value: 2
BIG_RTN:
description: BIG RTN (number of retransmissions)
value: 0
BIG_PACKING:
description: Arrangement of BIS subevents (0 = sequential, 1 = interleaved)
value: 0
BIG_FRAMING:
description:
value: 0
BIG_ENCRYPTION:
description: BIS encryption
value: 0
syscfg.vals:
CONSOLE_IMPLEMENTATION: full
LOG_IMPLEMENTATION: full
STATS_IMPLEMENTATION: full
# Disable not used GAP roles (we only do non-connectable
# advertising here)
BLE_ROLE_BROADCASTER: 1
BLE_ROLE_CENTRAL: 0
BLE_ROLE_OBSERVER: 0
BLE_ROLE_PERIPHERAL: 0
# Enable Extended Advertising
BLE_EXT_ADV: 1
# Enable Periodic Advertising
BLE_PERIODIC_ADV: 1
# Max advertising data size
BLE_EXT_ADV_MAX_SIZE: 261
# Number of multi-advertising instances. Note that due
# to historical reasonds total number of advertising
# instances is BLE_MULTI_ADV_INSTANCES + 1 as instance
# 0 is always available
BLE_MULTI_ADV_INSTANCES: 1
# Controller uses msys pool for storing advertising data and scan responses.
# Since we advertise a lot of data (~6k in total) at the same time we need
# to increase block count.
MSYS_1_BLOCK_COUNT: 32
BLE_PHY_2M: 1
BLE_VERSION: 54
BLE_ISO: 1
BLE_ISO_BROADCAST_SOURCE: 1
BLE_ISO_MAX_BIGS: 1
BLE_ISO_MAX_BISES: 2
BLE_AUDIO: 1
USBD_VID: 0xFFFF
USBD_PID: 0x0001
USBD_VENDOR_STRING: '"Apache Software Foundation"'
USBD_PRODUCT_STRING: '"NimBLE Auracast"'
USBD_AUDIO_OUT: 1
USB_AUDIO_OUT_CHANNELS: MYNEWT_VAL(AURACAST_CHAN_NUM)
# resampler + encoder
LIBSAMPLERATE_ENABLE_SINC_BEST_CONVERTER: 0
LIBSAMPLERATE_ENABLE_SINC_MEDIUM_CONVERTER: 0
LIBSAMPLERATE_ENABLE_SINC_FAST_CONVERTER: 1
LIBSAMPLERATE_LIBSAMPLER_NDEBUG: 1
MCU_HFCLK_DIV: 1
HARDFLOAT: 1
syscfg.vals.TINYUSB:
USBD_STACK_SIZE: 500
USBD_STD_DESCRIPTORS: 0
syscfg.vals.ISO_HCI_FEEDBACK:
BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS: 1000
BLE_HS_GAP_UNHANDLED_HCI_EVENT: 1
syscfg.vals.BSP_NRF52:
BLE_PHY_NRF52_HEADERMASK_WORKAROUND: 1
$import:
- "@apache-mynewt-nimble/apps/auracast_usb/syscfg.usb.yml"