apps: add Auracast USB sample with LC3 codec
This adds sample that acts as USB sound device. Audio signal is coded
using LC3 and broadacasted using Auracast package.
diff --git a/apps/auracast_usb/include/tusb_config.h b/apps/auracast_usb/include/tusb_config.h
new file mode 100644
index 0000000..053ed76
--- /dev/null
+++ b/apps/auracast_usb/include/tusb_config.h
@@ -0,0 +1,445 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#include "syscfg/syscfg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * COMMON CONFIGURATION
+ */
+
+#include <tusb_hw.h>
+
+/* defined by compiler flags for flexibility */
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
+
+#define CFG_TUSB_OS OPT_OS_MYNEWT
+#define CFG_TUSB_DEBUG 1
+
+#define CFG_TUD_EP_MAX 9
+
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
+#endif
+
+/**
+ * DEVICE CONFIGURATION
+ */
+#define CFG_TUD_ENDPOINT0_SIZE MYNEWT_VAL(USBD_EP0_SIZE)
+
+/* ------------- CLASS ------------- */
+#define CFG_TUD_CDC MYNEWT_VAL(USBD_CDC)
+#define CFG_TUD_HID MYNEWT_VAL(USBD_HID)
+#define CFG_TUD_MSC 0
+#define CFG_TUD_MIDI 0
+#define CFG_TUD_VENDOR 0
+#define CFG_TUD_USBTMC 0
+#define CFG_TUD_DFU_RT 0
+#define CFG_TUD_ECM_RNDIS 0
+#define CFG_TUD_BTH MYNEWT_VAL(USBD_BTH)
+#define CFG_TUD_AUDIO_IN MYNEWT_VAL(USBD_AUDIO_IN)
+#define CFG_TUD_AUDIO_OUT MYNEWT_VAL(USBD_AUDIO_OUT)
+#define CFG_TUD_AUDIO_IN_OUT MYNEWT_VAL(USBD_AUDIO_IN_OUT)
+#define CFG_TUD_AUDIO (MYNEWT_VAL(USBD_AUDIO_IN) || MYNEWT_VAL(USBD_AUDIO_OUT) || \
+ MYNEWT_VAL(USBD_AUDIO_IN_OUT))
+
+/* Audio format type */
+#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I
+#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_I
+
+/* Audio format type I specifications */
+#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
+#define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM
+#define CFG_TUD_AUDIO_N_CHANNELS_TX 2
+#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2
+#define CFG_TUD_AUDIO_N_CHANNELS_RX MYNEWT_VAL(USB_AUDIO_OUT_CHANNELS)
+#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2
+#define CFG_TUD_AUDIO_RX_ITEMSIZE 2
+#define CFG_TUD_AUDIO_SAMPLE_RATE MYNEWT_VAL(USB_AUDIO_OUT_SAMPLE_RATE)
+#define SAMPLES_PER_PACKET ((((CFG_TUD_AUDIO_SAMPLE_RATE) -1) / 1000) + 1)
+
+/* EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) */
+#define CFG_TUD_AUDIO_EPSIZE_IN (CFG_TUD_AUDIO_IN * SAMPLES_PER_PACKET * \
+ (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) *(CFG_TUD_AUDIO_N_CHANNELS_TX)) /* 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels */
+#define CFG_TUD_AUDIO_TX_FIFO_COUNT (CFG_TUD_AUDIO_IN * 1)
+#define CFG_TUD_AUDIO_TX_FIFO_SIZE (CFG_TUD_AUDIO_IN ? ((CFG_TUD_AUDIO_EPSIZE_IN)) : 0)
+
+/* EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) */
+#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1
+#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0
+#define CFG_TUD_AUDIO_EPSIZE_OUT (CFG_TUD_AUDIO_OUT * \
+ ((SAMPLES_PER_PACKET + 1) * \
+ (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) *(CFG_TUD_AUDIO_N_CHANNELS_RX))) /* N Samples (N kHz) x 2 Bytes/Sample x n Channels */
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EPSIZE_OUT
+#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (CFG_TUD_AUDIO_EPSIZE_OUT * 40)
+#define CFG_TUD_AUDIO_RX_FIFO_COUNT (CFG_TUD_AUDIO_OUT * 1)
+#define CFG_TUD_AUDIO_RX_FIFO_SIZE (CFG_TUD_AUDIO_OUT ? (3 * \
+ (CFG_TUD_AUDIO_EPSIZE_OUT / \
+ CFG_TUD_AUDIO_RX_FIFO_COUNT)) : 0)
+
+/* Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) */
+#define CFG_TUD_AUDIO_N_AS_INT 1
+
+/* Size of control request buffer */
+#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64
+
+/* Minimal number for alternative interfaces that is recognized by Windows as Bluetooth radio controller */
+#define CFG_TUD_BTH_ISO_ALT_COUNT 2
+
+/* CDC FIFO size of TX and RX */
+#define CFG_TUD_CDC_RX_BUFSIZE 64
+#define CFG_TUD_CDC_TX_BUFSIZE 64
+
+/* HID buffer size Should be sufficient to hold ID (if any) + Data */
+#define CFG_TUD_HID_BUFSIZE 16
+
+#define TUD_AUDIO_SPEAKER_MONO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \
+ + TUD_AUDIO_DESC_STD_AC_LEN \
+ + TUD_AUDIO_DESC_CS_AC_LEN \
+ + TUD_AUDIO_DESC_CLK_SRC_LEN \
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN \
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \
+ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN \
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN)
+
+#define TUD_AUDIO_SPEAKER_MONO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \
+ /* Standard Interface Association Descriptor (IAD) */ \
+ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \
+ /* Standard AC Interface Descriptor(4.7.1) */ \
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \
+ /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, \
+ /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
+ /* Clock Source Descriptor(4.7.2.1) */ \
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \
+ /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Input Terminal Descriptor(4.7.2.4) */ \
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \
+ /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, \
+ /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \
+ /* Output Terminal Descriptor(4.7.2.5) */ \
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \
+ /*_assocTerm*/ 0x00, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \
+ /*_stridx*/ 0x00), \
+ /* Feature Unit Descriptor(4.7.2.8) */ \
+ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, \
+ /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << \
+ AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | \
+ AUDIO_CTRL_RW << \
+ AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), \
+ /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << \
+ AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << \
+ AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000) \
+
+/* XXXXX
+ * 3 iso endpoint alternative for 16,32,48 kHz does not work on windows, works on Linux, on MAC reported freq is 48kHz and mac sends data for 16kHz
+ * MAC does not change clock selection like Linux does
+ */
+
+#define TUD_AUDIO_SPEAKER3_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize1, \
+ _epsize2, _epsize3) \
+ /* Standard Interface Association Descriptor (IAD) */ \
+ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \
+ /* Standard AC Interface Descriptor(4.7.1) */ \
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \
+ /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \
+ /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
+ /* Clock Source Descriptor(4.7.2.1) */ \
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \
+ /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Input Terminal Descriptor(4.7.2.4) */ \
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \
+ /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_idxchannelnames*/ 0x00, \
+ /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \
+ /* Output Terminal Descriptor(4.7.2.5) */ \
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \
+ /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ \
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize1, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000), \
+ \
+ /* Interface 1, Alternate 2 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x02, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize2, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000), \
+ \
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x03, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize3, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000) \
+
+#define TUD_AUDIO_SPK3_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \
+ + TUD_AUDIO_DESC_STD_AC_LEN \
+ + TUD_AUDIO_DESC_CS_AC_LEN \
+ + TUD_AUDIO_DESC_CLK_SRC_LEN \
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN \
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \
+ + 0 * TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + (TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN \
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) * 3)
+
+
+#define TUD_AUDIO_SPEAKER_DESCRIPTOR_FLOAT(_itfnum, _stridx, _epout, _epsize) \
+ /* Standard Interface Association Descriptor (IAD) */ \
+ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \
+ /* Standard AC Interface Descriptor(4.7.1) */ \
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \
+ /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \
+ /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
+ /* Clock Source Descriptor(4.7.2.1) */ \
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \
+ /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Input Terminal Descriptor(4.7.2.4) */ \
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \
+ /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_idxchannelnames*/ 0x00, \
+ /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \
+ /* Output Terminal Descriptor(4.7.2.5) */ \
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \
+ /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT, /*_nchannelsphysical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(4, 32), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000) \
+
+#define TUD_AUDIO_SPEAKER_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \
+ + TUD_AUDIO_DESC_STD_AC_LEN \
+ + TUD_AUDIO_DESC_CS_AC_LEN \
+ + TUD_AUDIO_DESC_CLK_SRC_LEN \
+ + TUD_AUDIO_DESC_INPUT_TERM_LEN \
+ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \
+ + 0 * TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \
+ + TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + (TUD_AUDIO_DESC_STD_AS_INT_LEN \
+ + TUD_AUDIO_DESC_CS_AS_INT_LEN \
+ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \
+ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \
+ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) * 1)
+
+#define TUD_AUDIO_SPEAKER_STEREO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \
+ /* Standard Interface Association Descriptor (IAD) */ \
+ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \
+ /* Standard AC Interface Descriptor(4.7.1) */ \
+ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \
+ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \
+ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \
+ /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \
+ TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \
+ /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \
+ /* Clock Source Descriptor(4.7.2.1) */ \
+ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \
+ /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Input Terminal Descriptor(4.7.2.4) */ \
+ TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \
+ /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_idxchannelnames*/ 0x00, \
+ /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \
+ /* Output Terminal Descriptor(4.7.2.5) */ \
+ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \
+ /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \
+ /*_stridx*/ 0x00), \
+ /* Standard AS Interface Descriptor(4.9.1) */ \
+ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \
+ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \
+ /*_stridx*/ 0x00), \
+ /* Class-Specific AS Interface Descriptor(4.9.2) */ \
+ TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \
+ /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \
+ /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \
+ /*_stridx*/ 0x00), \
+ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \
+ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \
+ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \
+ TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \
+ /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \
+ TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \
+ /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \
+ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \
+ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \
+ /*_ctrl*/ AUDIO_CTRL_NONE, \
+ /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \
+ /*_lockdelay*/ 0x0000) \
+
+#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN ( \
+ (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \
+ (TUD_AUDIO_SPEAKER_MONO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \
+ (0 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \
+ (TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \
+ (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \
+ (TUD_AUDIO_SPEAKER_STEREO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 2 ? 1 : 0)))
+#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1
+#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */
diff --git a/apps/auracast_usb/include/usb_audio.h b/apps/auracast_usb/include/usb_audio.h
new file mode 100644
index 0000000..ea93b9f
--- /dev/null
+++ b/apps/auracast_usb/include/usb_audio.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef H_USB_AUDIO_
+#define H_USB_AUDIO_
+
+#include <stdint.h>
+
+typedef void (* usb_audio_sample_rate_cb_t)(uint32_t);
+
+/* Set default sample rate, should only be used before USB is initialized */
+void usb_desc_sample_rate_set(uint32_t sample_rate);
+
+#endif /* H_USB_AUDIO_ */
diff --git a/apps/auracast_usb/pkg.yml b/apps/auracast_usb/pkg.yml
new file mode 100644
index 0000000..96c56f2
--- /dev/null
+++ b/apps/auracast_usb/pkg.yml
@@ -0,0 +1,46 @@
+# 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: "krzysztof.kopyscinski@codecoup.pl"
+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
diff --git a/apps/auracast_usb/src/app_priv.h b/apps/auracast_usb/src/app_priv.h
new file mode 100644
index 0000000..87a901a
--- /dev/null
+++ b/apps/auracast_usb/src/app_priv.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef H_APP_PRIV_
+#define H_APP_PRIV_
+
+#include <syscfg/syscfg.h>
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define AUDIO_CHANNELS MYNEWT_VAL(AURACAST_CHAN_NUM)
+#define AUDIO_SAMPLE_SIZE sizeof(int16_t)
+#define AUDIO_PCM_SAMPLE_RATE MYNEWT_VAL(USB_AUDIO_OUT_SAMPLE_RATE)
+
+#define LC3_FRAME_DURATION (MYNEWT_VAL(LC3_FRAME_DURATION))
+#define LC3_SAMPLING_FREQ (MYNEWT_VAL(LC3_SAMPLING_FREQ))
+#define LC3_BITRATE (MYNEWT_VAL(LC3_BITRATE))
+#define LC3_FPDT (LC3_SAMPLING_FREQ * 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];
+#endif /* H_APP_PRIV_ */
diff --git a/apps/auracast_usb/src/audio_usb.c b/apps/auracast_usb/src/audio_usb.c
new file mode 100644
index 0000000..c63f688
--- /dev/null
+++ b/apps/auracast_usb/src/audio_usb.c
@@ -0,0 +1,278 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+#include <syscfg/syscfg.h>
+#include <os/os.h>
+#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>
+#include <nrf_clock.h>
+
+#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,
+};
+
+static uint32_t frame_bytes_lc3;
+static uint16_t big_sdu;
+
+static int16_t out_buf[AUDIO_BUF_SIZE];
+/* Reserve twice the size of input, so we'll always have space for resampler output */
+static uint8_t encoded_frame[155];
+static int out_idx = 0;
+#if MYNEWT_VAL(ISO_HCI_FEEDBACK)
+static int samples_idx = 0;
+static int16_t samples_read[AUDIO_BUF_SIZE];
+/* 155 is maximum value Octets Per Codec Frame described in Table 3.5 of BAP specification */
+static float samples_read_float[AUDIO_BUF_SIZE];
+static float resampled_float[AUDIO_BUF_SIZE];
+double resampler_in_rate = AUDIO_PCM_SAMPLE_RATE;
+double resampler_out_rate = LC3_SAMPLING_FREQ;
+double resampler_ratio;
+SRC_STATE *resampler_state;
+static struct ble_gap_event_listener feedback_listener;
+#endif
+static uint32_t pkt_counter = 0;
+
+
+#if MYNEWT_VAL(ISO_HCI_FEEDBACK)
+static int
+ble_hs_gap_event_handler(struct ble_gap_event *event, void *arg)
+{
+ struct ble_hci_vs_subev_iso_hci_feedback *feedback_pkt;
+ double adjust = 0;
+
+ if (event->type == BLE_GAP_EVENT_UNHANDLED_HCI_EVENT &&
+ event->unhandled_hci.is_le_meta == false &&
+ event->unhandled_hci.is_vs == true) {
+ const struct ble_hci_ev_vs *ev = event->unhandled_hci.ev;
+
+ if (ev->id == BLE_HCI_VS_SUBEV_ISO_HCI_FEEDBACK) {
+ feedback_pkt = (struct ble_hci_vs_subev_iso_hci_feedback *) ev->data;
+ assert(feedback_pkt->count == MYNEWT_VAL(BLE_ISO_MAX_BIGS));
+ /* There is only one BIG in this sample */
+ if (feedback_pkt->feedback[0].diff > 0) {
+ adjust += 10;
+ } else if (feedback_pkt->feedback[0].diff < 0) {
+ adjust -= 10;
+ }
+ resampler_ratio = (resampler_out_rate + adjust) / resampler_in_rate;
+ }
+ }
+
+ return 0;
+}
+
+static void
+resample(void)
+{
+ static int resampled_len;
+ int samples_consumed;
+ int samples_left;
+ SRC_DATA sd;
+ int resample_avail = ARRAY_SIZE(out_buf) - out_idx;
+ int rc;
+
+ src_short_to_float_array(samples_read, samples_read_float, samples_idx);
+
+ sd.data_in = samples_read_float;
+ sd.data_out = resampled_float;
+ sd.input_frames = samples_idx / AUDIO_CHANNELS;
+ sd.output_frames = resample_avail / AUDIO_CHANNELS;
+ sd.end_of_input = 0;
+ sd.input_frames_used = 0;
+ sd.output_frames_gen = 0;
+ sd.src_ratio = resampler_ratio;
+
+ rc = src_process(resampler_state, &sd);
+ assert(rc == 0);
+
+ resampled_len = sd.output_frames_gen * AUDIO_CHANNELS;
+
+ assert(resampled_len <= resample_avail);
+
+ src_float_to_short_array(resampled_float,
+ &out_buf[out_idx],
+ resampled_len);
+
+ out_idx += resampled_len;
+
+ samples_consumed = sd.input_frames_used * AUDIO_CHANNELS;
+ samples_left = samples_idx - samples_consumed;
+ memmove(samples_read, &samples_read[samples_consumed], samples_left);
+ samples_idx -= samples_consumed;
+}
+#endif
+
+static void
+usb_data_func(struct os_event *ev)
+{
+ int ch_idx;
+ unsigned int num_bytes;
+ unsigned int num_samples;
+ unsigned int num_frames;
+ int read;
+ int skip;
+
+ if (!g_usb_enabled) {
+ tud_audio_clear_ep_out_ff();
+ return;
+ }
+
+ while ((num_bytes = tud_audio_available()) > 0) {
+ num_samples = num_bytes / AUDIO_SAMPLE_SIZE;
+ num_frames = num_samples / AUDIO_CHANNELS;
+ num_bytes = num_frames * AUDIO_SAMPLE_SIZE * AUDIO_CHANNELS;
+
+#if MYNEWT_VAL(ISO_HCI_FEEDBACK)
+ assert(samples_idx + num_samples < ARRAY_SIZE(samples_read));
+ read = tud_audio_read(&samples_read[samples_idx], num_bytes);
+ samples_idx += num_samples;
+ resample();
+#else
+ assert(out_idx + num_samples < ARRAY_SIZE(out_buf));
+ read = tud_audio_read(&out_buf[out_idx], num_bytes);
+ out_idx += num_samples;
+#endif
+ assert(read == num_bytes);
+
+ assert((out_idx & 0x80000000) == 0);
+ if (out_idx / AUDIO_CHANNELS >= LC3_FPDT) {
+ pkt_counter++;
+ skip = 0;
+
+ for (ch_idx = 0; ch_idx < AUDIO_CHANNELS; ch_idx++) {
+ if (chans[ch_idx].handle == 0) {
+ skip = 1;
+ continue;
+ }
+ }
+
+ if (!skip) {
+ memset(encoded_frame, 0, sizeof(encoded_frame));
+ lc3_encode(chans[0].encoder, LC3_PCM_FORMAT_S16, out_buf + 0,
+ AUDIO_CHANNELS, (int) frame_bytes_lc3,
+ encoded_frame);
+ if (AUDIO_CHANNELS == 2) {
+ if (MYNEWT_VAL(BIG_NUM_BIS) == 1) {
+ lc3_encode(chans[0].encoder, LC3_PCM_FORMAT_S16,
+ out_buf + 1, AUDIO_CHANNELS,
+ (int) frame_bytes_lc3, encoded_frame + big_sdu / 2);
+ ble_iso_tx(chans[0].handle, encoded_frame, big_sdu);
+ } else {
+ ble_iso_tx(chans[0].handle, encoded_frame, big_sdu);
+ memset(encoded_frame, 0, sizeof(encoded_frame));
+ lc3_encode(chans[1].encoder, LC3_PCM_FORMAT_S16, out_buf + 1,
+ AUDIO_CHANNELS, (int) frame_bytes_lc3,
+ encoded_frame);
+ ble_iso_tx(chans[1].handle, encoded_frame, big_sdu);
+ }
+ } else {
+ ble_iso_tx(chans[0].handle, encoded_frame, big_sdu);
+ }
+
+ if (out_idx / AUDIO_CHANNELS >= LC3_FPDT) {
+ out_idx -= LC3_FPDT * AUDIO_CHANNELS;
+ memmove(out_buf, &out_buf[LC3_FPDT * AUDIO_CHANNELS],
+ out_idx * AUDIO_SAMPLE_SIZE);
+ } else {
+ out_idx = 0;
+ }
+ }
+ }
+ }
+}
+
+bool
+tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received,
+ uint8_t func_id, uint8_t ep_out,
+ uint8_t cur_alt_setting)
+{
+ (void)rhport;
+ (void)n_bytes_received;
+ (void)func_id;
+ (void)ep_out;
+ (void)cur_alt_setting;
+
+ if (!usb_data_ev.ev_queued) {
+ os_eventq_put(os_eventq_dflt_get(), &usb_data_ev);
+ }
+
+ return true;
+}
+
+void
+audio_usb_init(void)
+{
+ /* Need to reference those explicitly, so they are always pulled by linker
+ * instead of weak symbols in tinyusb.
+ */
+ (void)tud_audio_rx_done_post_read_cb;
+
+ usb_desc_sample_rate_set(AUDIO_PCM_SAMPLE_RATE);
+
+ assert(LC3_FPDT == lc3_frame_samples(LC3_FRAME_DURATION,
+ LC3_SAMPLING_FREQ));
+
+ unsigned esize = lc3_encoder_size(LC3_FRAME_DURATION,
+ LC3_SAMPLING_FREQ);
+ for (int i = 0; i < AUDIO_CHANNELS; i++) {
+ chans[i].encoder = calloc(1, esize);
+ lc3_setup_encoder(LC3_FRAME_DURATION, LC3_SAMPLING_FREQ,
+ 0, chans[i].encoder);
+ }
+
+ g_usb_enabled = 1;
+
+ frame_bytes_lc3 = lc3_frame_bytes(LC3_FRAME_DURATION, LC3_BITRATE);
+ big_sdu = frame_bytes_lc3 *
+ (1 + ((AUDIO_CHANNELS == 2) && (BIG_NUM_BIS == 1)));
+
+#if MYNEWT_VAL(ISO_HCI_FEEDBACK)
+ int rc;
+
+ assert(resampler_state == NULL);
+ resampler_state = src_new(SRC_ZERO_ORDER_HOLD, AUDIO_CHANNELS, NULL);
+ assert(resampler_state != NULL);
+
+ rc = ble_gap_event_listener_register(&feedback_listener,
+ ble_hs_gap_event_handler, NULL);
+ assert(rc == 0);
+
+ resampler_ratio = resampler_out_rate / resampler_in_rate;
+#endif
+}
diff --git a/apps/auracast_usb/src/main.c b/apps/auracast_usb/src/main.c
new file mode 100644
index 0000000..fcf4fd3
--- /dev/null
+++ b/apps/auracast_usb/src/main.c
@@ -0,0 +1,325 @@
+/*
+ * 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
+#define BROADCAST_SDU_INTVL MYNEWT_VAL(LC3_FRAME_DURATION)
+#if (MYNEWT_VAL(LC3_BITRATE) == 24000)
+#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_24000_HZ
+#elif (MYNEWT_VAL(LC3_BITRATE) == 48000)
+#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_48000_HZ
+#elif (MYNEWT_VAL(LC3_BITRATE) == 96000)
+#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_96000_HZ
+#else
+BUILD_ASSERT(0, "Only 24kHz and 48kHz supported");
+#endif
+#define BROADCAST_MAX_SDU (BROADCAST_SDU_INTVL * \
+ MYNEWT_VAL(LC3_BITRATE) / \
+ (1000 * 1000 * 8) * \
+ 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,
+ BROADCAST_MAX_SDU, );
+ 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,
+ BROADCAST_MAX_SDU, );
+#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,
+ BROADCAST_MAX_SDU * 2, );
+
+ 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 = MYNEWT_VAL(LC3_FRAME_DURATION),
+ .max_sdu = BROADCAST_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;
+}
diff --git a/apps/auracast_usb/src/usb_desc.c b/apps/auracast_usb/src/usb_desc.c
new file mode 100644
index 0000000..681ad7c
--- /dev/null
+++ b/apps/auracast_usb/src/usb_desc.c
@@ -0,0 +1,395 @@
+/*
+ * 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 <assert.h>
+#include <syscfg/syscfg.h>
+#include <bsp/bsp.h>
+#include <string.h>
+#include <tusb.h>
+#include <device/usbd.h>
+#include <class/audio/audio.h>
+#include <os/util.h>
+#include <usb_audio.h>
+
+#define USBD_PRODUCT_RELEASE_NUMBER MYNEWT_VAL(USBD_PRODUCT_RELEASE_NUMBER)
+
+#ifndef CONFIG_NUM
+#define CONFIG_NUM 1
+#endif
+
+typedef enum {
+ USB_STRING_DESCRIPTOR_LANG = 0,
+ USB_STRING_DESCRIPTOR_MANUFACTURER = 1,
+ USB_STRING_DESCRIPTOR_PRODUCT = 2,
+ USB_STRING_DESCRIPTOR_INTERFACE = 3,
+ USB_STRING_DESCRIPTOR_CDC = 4,
+ USB_STRING_DESCRIPTOR_SERIAL = 16,
+ USB_STRING_DESCRIPTOR_MICROSOFT_OS = 0xEE,
+} usb_string_descriptor_ix_t;
+
+#define CDC_IF_STR_IX (MYNEWT_VAL(USBD_CDC_DESCRIPTOR_STRING) == NULL ? 0 : 4)
+
+const tusb_desc_device_t desc_device = {
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+
+ .bDeviceClass = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+
+ .idVendor = MYNEWT_VAL(USBD_VID),
+ .idProduct = MYNEWT_VAL(USBD_PID),
+ .bcdDevice = USBD_PRODUCT_RELEASE_NUMBER,
+
+ .iManufacturer = USB_STRING_DESCRIPTOR_MANUFACTURER,
+ .iProduct = USB_STRING_DESCRIPTOR_PRODUCT,
+ .iSerialNumber = USB_STRING_DESCRIPTOR_SERIAL,
+
+ .bNumConfigurations = 0x01
+};
+
+/*
+ * Invoked when received GET DEVICE DESCRIPTOR
+ * Application return pointer to descriptor
+ */
+const uint8_t *
+tud_descriptor_device_cb(void)
+{
+ return (const uint8_t *)&desc_device;
+}
+
+#if MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_APP) || MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840)
+#define ISO_EP 8
+#else
+#error MCU not supported
+#endif
+
+/*
+ * Configuration Descriptor
+ */
+
+enum {
+#if CFG_TUD_BTH
+ ITF_NUM_BTH,
+#if CFG_TUD_BTH_ISO_ALT_COUNT > 0
+ ITF_NUM_BTH_VOICE,
+#endif
+#endif
+
+#if CFG_TUD_CDC
+ ITF_NUM_CDC,
+ ITF_NUM_CDC_DATA,
+#endif
+
+#if CFG_TUD_MSC
+ ITF_NUM_MSC,
+#endif
+
+#if CFG_TUD_HID
+ ITF_NUM_HID,
+#endif
+
+#if CFG_TUD_AUDIO_IN
+ ITF_NUM_AUDIO_AC,
+ ITF_NUM_AUDIO_AS_IN,
+#elif CFG_TUD_AUDIO_OUT
+ ITF_NUM_AUDIO_AC,
+ ITF_NUM_AUDIO_AS_OUT,
+#elif CFG_TUD_AUDIO_IN_OUT
+ ITF_NUM_AUDIO_AC,
+ ITF_NUM_AUDIO_AS_IN,
+ ITF_NUM_AUDIO_AS_OUT,
+#endif
+
+ ITF_NUM_TOTAL
+};
+
+#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \
+ CFG_TUD_CDC * TUD_CDC_DESC_LEN + \
+ CFG_TUD_MSC * TUD_MSC_DESC_LEN + \
+ CFG_TUD_HID * TUD_HID_DESC_LEN + \
+ CFG_TUD_BTH * TUD_BTH_DESC_LEN + \
+ CFG_TUD_AUDIO_IN * TUD_AUDIO_MIC_ONE_CH_DESC_LEN + \
+ (1 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \
+ (TUD_AUDIO_SPEAKER_MONO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \
+ (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \
+ (TUD_AUDIO_SPEAKER_STEREO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 2 ? 1 : 0)) + \
+ 0)
+
+const uint8_t desc_configuration[] = {
+ TUD_CONFIG_DESCRIPTOR(CONFIG_NUM, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
+ MYNEWT_VAL(USBD_CONFIGURATION_MAX_POWER)),
+
+#if CFG_TUD_BTH
+ TUD_BTH_DESCRIPTOR(ITF_NUM_BTH, BTH_IF_STR_IX, USBD_BTH_EVENT_EP, USBD_BTH_EVENT_EP_SIZE,
+ USBD_BTH_EVENT_EP_INTERVAL, USBD_BTH_DATA_IN_EP, USBD_BTH_DATA_OUT_EP, USBD_BTH_DATA_EP_SIZE,
+ 0, 9, 17, 25, 33, 49),
+#endif
+
+
+#if CFG_TUD_CDC
+ TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, CDC_IF_STR_IX, USBD_CDC_NOTIFY_EP, USBD_CDC_NOTIFY_EP_SIZE,
+ USBD_CDC_DATA_OUT_EP, USBD_CDC_DATA_IN_EP, USBD_CDC_DATA_EP_SIZE),
+#endif
+
+#if CFG_TUD_MSC
+ /* TODO: MSC not handled yet */
+ TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, MSC_IF_STR_IX, EPNUM_MSC_OUT, EPNUM_MSC_IN,
+ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64),
+#endif
+
+#if CFG_TUD_HID
+ TUD_HID_DESCRIPTOR(ITF_NUM_HID, HID_IF_STR_IX, HID_PROTOCOL_NONE, sizeof(desc_hid_report),
+ USBD_HID_REPORT_EP, USBD_HID_REPORT_EP_SIZE, USBD_HID_REPORT_EP_INTERVAL),
+#endif
+
+#if CFG_TUD_AUDIO_IN_OUT
+#elif CFG_TUD_AUDIO_IN
+ TUD_AUDIO_MIC2_DESCRIPTOR(ITF_NUM_AUDIO_AC_IN, 0, 2, 16, 0x80 | ISO_EP, 192),
+#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 2
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP == 1
+ TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX,
+ 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT, 0x80 | ISO_EP, 1),
+#else
+ TUD_AUDIO_SPEAKER_STEREO_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX,
+ 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT),
+#endif
+#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 1
+ #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+ TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, 2, 16, ISO_EP, 100, 0x80 | ISO_EP),
+#else
+ TUD_AUDIO_SPEAKER_MONO_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX,
+ 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT),
+#endif
+#endif
+};
+
+/**
+ * Invoked when received GET CONFIGURATION DESCRIPTOR
+ * Application return pointer to descriptor
+ * Descriptor contents must exist long enough for transfer to complete
+ */
+const uint8_t *
+tud_descriptor_configuration_cb(uint8_t index)
+{
+ (void)index;
+
+ return desc_configuration;
+}
+
+static uint16_t desc_string[MYNEWT_VAL(USBD_STRING_DESCRIPTOR_MAX_LENGTH) + 1];
+
+#if CFG_TUD_AUDIO
+
+#if CFG_TUD_AUDIO_IN
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_MIC2_DESC_LEN};
+#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 1
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN};
+#else
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_MONO_DESC_LEN};
+#endif
+#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 2
+#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN};
+#else
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_STEREO_DESC_LEN};
+#endif
+#endif
+
+static uint32_t g_sample_rate = CFG_TUD_AUDIO_SAMPLE_RATE;
+static usb_audio_sample_rate_cb_t sample_rate_cb;
+
+/* Invoked when audio class specific set request received for an entity */
+bool
+tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+ uint32_t new_sample_rate;
+
+ (void) rhport;
+ audio_control_request_t *request = (audio_control_request_t *) p_request;
+
+ if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_VOLUME &&
+ request->bRequest == AUDIO_CS_REQ_CUR) {
+ /* Ignore value but accept request */
+ return true;
+ } else if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ &&
+ request->bRequest == AUDIO_CS_REQ_CUR) {
+ /* Ignore value but accept request */
+ new_sample_rate = ((audio_control_cur_4_t *)(pBuff))->bCur;
+ if (new_sample_rate != g_sample_rate) {
+ g_sample_rate = new_sample_rate;
+ if (sample_rate_cb) {
+ sample_rate_cb(g_sample_rate);
+ }
+ }
+ return true;
+ } else {
+ __BKPT(1);
+ }
+ return false;
+}
+
+bool
+tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+ (void) rhport;
+ audio_control_request_t *request = (audio_control_request_t *) p_request;
+ if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) {
+ if (request->bRequest == AUDIO_CS_REQ_CUR) {
+ audio_control_cur_4_t curf = {g_sample_rate};
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &curf, sizeof(curf));
+ } else if (request->bRequest == AUDIO_CS_REQ_RANGE) {
+#if 1
+ audio_control_range_4_n_t(1) rangef = {
+ .wNumSubRanges = 1,
+ .subrange[0] = {g_sample_rate, g_sample_rate, 0},
+ };
+#else
+ audio_control_range_4_n_t(2) rangef = {
+ .wNumSubRanges = 2,
+ .subrange[0] = {16000, 16000, 0},
+ .subrange[1] = {48000, 48000, 0},
+ };
+#endif
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &rangef, sizeof(rangef));
+ }
+ } else if (request->bEntityID == 5 && request->bControlSelector == AUDIO_CX_CTRL_CONTROL) {
+ if (request->bRequest == AUDIO_CS_REQ_CUR) {
+ audio_control_cur_1_t cur_clk = {1};
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_clk, sizeof(cur_clk));
+ }
+ } else if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID &&
+ request->bRequest == AUDIO_CS_REQ_CUR) {
+ audio_control_cur_1_t cur_valid = {.bCur = 1};
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_valid, sizeof(cur_valid));
+ } else if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_MUTE &&
+ request->bRequest == AUDIO_CS_REQ_CUR) {
+ audio_control_cur_1_t mute = {.bCur = 0};
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute, sizeof(mute));
+ } else if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_VOLUME) {
+ if (request->bRequest == AUDIO_CS_REQ_RANGE) {
+ audio_control_range_2_n_t(1) range_vol = {
+ .wNumSubRanges = 1,
+ .subrange[0] = {0, 1000, 10}
+ };
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &range_vol, sizeof(range_vol));
+ } else if (request->bRequest == AUDIO_CS_REQ_CUR) {
+ audio_control_cur_2_t cur_vol = {.bCur = 1280};
+ return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_vol, sizeof(cur_vol));
+ }
+ } else {
+ __BKPT(1);
+ }
+ return false;
+}
+
+#endif
+
+/* Function converts ASCII string to USB descriptor format */
+static uint16_t *
+string_to_usb_desc_string(const char *str, uint16_t *desc, uint8_t desc_size)
+{
+ int i;
+ int char_num = strlen(str);
+
+ assert(char_num < desc_size);
+ if (char_num >= desc_size) {
+ char_num = desc_size - 1;
+ }
+
+ /* Encode length in first byte, type in second byte */
+ desc[0] = tu_htole16(tu_u16(TUSB_DESC_STRING, 2 * (char_num + 1)));
+
+ /* Copy characters 8bit to 16 bits */
+ for (i = 0; i < char_num; ++i) {
+ desc[1 + i] = tu_htole16(str[i]);
+ }
+
+ return desc;
+}
+
+/* LANGID string descriptors */
+static const uint16_t usbd_lang_id[2] = {
+ (TUSB_DESC_STRING << 8) + 4, /* Size of this descriptor */
+ tu_htole16(MYNEWT_VAL(USBD_LANGID))
+};
+
+static struct {
+ uint16_t major;
+ uint16_t minor;
+ uint16_t revision;
+ uint32_t build;
+} img_version = {
+ 1, 0, 0, 1
+};
+
+static char serial_number[11];
+
+static uint16_t *
+serial_to_usb_desc_string(uint16_t *desc, size_t size)
+{
+ if (serial_number[0] == 0) {
+ uint64_t serial = MYNEWT_VAL(USBD_SERIAL_ID);
+
+ snprintf(serial_number, 11, "%010" PRIu64, serial);
+ }
+
+ return string_to_usb_desc_string(serial_number, desc, size);
+}
+
+/*
+ * Invoked when received GET STRING DESCRIPTOR request
+ * Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+ */
+const uint16_t *
+tud_descriptor_string_cb(uint8_t index, uint16_t langid)
+{
+ const uint16_t *ret = NULL;
+ char interface[100];
+
+#if MYNEWT_VAL(USBD_WINDOWS_COMP_ID)
+ if (index == USB_STRING_DESCRIPTOR_MICROSOFT_OS) {
+ ret = (const uint16_t *)microsoft_os_string_descriptor;
+ }
+#endif
+ if (index == USB_STRING_DESCRIPTOR_LANG) {
+ ret = usbd_lang_id;
+ } else if (index == USB_STRING_DESCRIPTOR_SERIAL) {
+ ret = serial_to_usb_desc_string(desc_string, ARRAY_SIZE(desc_string));
+ } else if (index == USB_STRING_DESCRIPTOR_MANUFACTURER) {
+ ret = string_to_usb_desc_string(MYNEWT_VAL(USBD_VENDOR_STRING), desc_string, ARRAY_SIZE(desc_string));
+ } else if (index == USB_STRING_DESCRIPTOR_PRODUCT) {
+ ret = string_to_usb_desc_string(MYNEWT_VAL(USBD_PRODUCT_STRING), desc_string, ARRAY_SIZE(desc_string));
+ } else if (index == USB_STRING_DESCRIPTOR_INTERFACE) {
+ snprintf(interface, sizeof(interface), "%s, (%u.%u.%u.%lu)", MYNEWT_VAL(USBD_PRODUCT_STRING),
+ img_version.major, img_version.minor, img_version.revision, img_version.build);
+ ret = string_to_usb_desc_string(interface, desc_string, ARRAY_SIZE(desc_string));
+ }
+ return ret;
+}
+
+void
+usb_desc_sample_rate_set(uint32_t sample_rate)
+{
+ g_sample_rate = sample_rate;
+}
diff --git a/apps/auracast_usb/syscfg.usb.yml b/apps/auracast_usb/syscfg.usb.yml
new file mode 100644
index 0000000..d9967b5
--- /dev/null
+++ b/apps/auracast_usb/syscfg.usb.yml
@@ -0,0 +1,174 @@
+# 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.TINYUSB:
+ USBD_STRING_DESCRIPTOR_MAX_LENGTH:
+ description: Maximum length of string descriptor in characters
+ value: 31
+ USBD_EP0_SIZE:
+ description: >
+ Endpoint 0 size
+ value: 64
+ USBD_SERIAL_ID:
+ description: Serial ID
+ value: 1
+ restrictions:
+ - $notnull
+ USBD_VID:
+ description: Vendor ID
+ value:
+ restrictions:
+ - $notnull
+ USBD_PID:
+ description: Product ID
+ value:
+ restrictions:
+ - $notnull
+ USBD_PRODUCT_RELEASE_NUMBER:
+ description: Product release number needed for USB descriptor
+ value: 0x100
+ USBD_CONFIGURATION_MAX_POWER:
+ description: >
+ Maximum power consumption of the USB device from the bus in this specific
+ configuration when the device is fully operational. Expressed in 2 mA units
+ (i.e., 50 = 100 mA).
+ value: 100
+ USBD_LANGID:
+ description: Language ID as specified by usb.org
+ value: 0x0409
+ USBD_VENDOR_STRING:
+ description: Manufacturer identification string
+ value: '"Apache Software Foundation"'
+ USBD_PRODUCT_STRING:
+ description: Device friendly name
+ value: '"NimBLE Auracast"'
+ USBD_CDC:
+ description: Enable CDC device
+ value: 0
+ USBD_CDC_CONSOLE:
+ description: Enable CDC device function for console in TinyUSB stack.
+ value:
+ USBD_HID:
+ description: Enable HID device
+ value: 0
+ USBD_MSC:
+ description: Enable MSC device
+ value: 0
+ USBD_BTH:
+ description: Enable BT HCI device
+ value: 0
+ USBD_AUDIO:
+ description: Enable Audio device
+ value: 0
+ USBD_AUDIO_IN:
+ description: Enable Audio device
+ value: 0
+ USBD_AUDIO_OUT:
+ description: Enable Audio device
+ value: 1
+ USBD_AUDIO_IN_OUT:
+ description: Enable Audio device
+ value: 0
+ USB_AUDIO_OUT_CHANNELS:
+ description: Number of audio channels on USB stream
+ value: MYNEWT_VAL(AURACAST_CHAN_NUM)
+ USB_AUDIO_OUT_SAMPLE_RATE:
+ description: USB sample rate
+ value: 48000
+
+ USBD_CDC_DATA_OUT_EP:
+ description: CDC data out endpoint number
+ value:
+ USBD_CDC_DATA_IN_EP:
+ description: CDC data out endpoint number
+ value:
+ USBD_CDC_DATA_EP_SIZE:
+ description: CDC data endpoint size
+ value:
+ USBD_CDC_NOTIFY_EP:
+ description: CDC notify endpoint number
+ value:
+ USBD_CDC_NOTIFY_EP_SIZE:
+ description: CDC notify endpoint size
+ value:
+
+ USBD_CDC_DESCRIPTOR_STRING:
+ description: String for CDC interface
+ value: NULL
+
+ USBD_MSC_DESCRIPTOR_STRING:
+ description: String for MSC interface
+ value: NULL
+
+ USBD_HID_DESCRIPTOR_STRING:
+ description: String for HID interface
+ value: NULL
+
+ USBD_BTH_DESCRIPTOR_STRING:
+ description: String for BT descriptor
+ value: NULL
+
+ USBD_HID_REPORT_EP:
+ description: HID report endpoint number
+ value:
+ USBD_HID_REPORT_EP_SIZE:
+ description: HID report endpoint size
+ value:
+ USBD_HID_REPORT_EP_INTERVAL:
+ description: HID report endpoint interval
+ value:
+
+ USBD_HID_REPORT_ID_KEYBOARD:
+ description: HID keyboard report ID
+ value:
+ USBD_HID_CAPS_LOCK_LED_PIN:
+ description: Caps Lock LED
+ value: -1
+ USBD_HID_CAPS_LOCK_LED_ON_VALUE:
+ description: Value to set to pin to turn led on
+ value: 0
+ USBD_HID_NUM_LOCK_LED_PIN:
+ description: Num Lock LED
+ value: -1
+ USBD_HID_NUM_LOCK_LED_ON_VALUE:
+ description: Value to set to pin to turn led on
+ value: 0
+ USBD_HID_REPORT_ID_MOUSE:
+ description: HID keyboard report ID
+ value:
+
+ USBD_BTH_EVENT_EP:
+ description: BTH event endpoint number
+ value:
+ USBD_BTH_EVENT_EP_SIZE:
+ description: BTH event endpoint size
+ value:
+ USBD_BTH_EVENT_EP_INTERVAL:
+ description: BTH event endpoint interval
+ value:
+ USBD_BTH_DATA_IN_EP:
+ description: BTH data in endpoint number
+ value:
+ USBD_BTH_DATA_OUT_EP:
+ description: BTH data out endpoint number
+ value:
+ USBD_BTH_DATA_EP_SIZE:
+ description: BTH data endpoints size
+ value:
+
+syscfg.restrictions:
+ - '!USBD_STD_DESCRIPTORS'
diff --git a/apps/auracast_usb/syscfg.yml b/apps/auracast_usb/syscfg.yml
new file mode 100644
index 0000000..1cad13b
--- /dev/null
+++ b/apps/auracast_usb/syscfg.yml
@@ -0,0 +1,132 @@
+# 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: 1
+
+ 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: 24000
+ LC3_BITRATE:
+ description: LC3 bitrate
+ value: 24000
+
+ BIG_PHY:
+ description:
+ value: 3
+ 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
+
+ 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"
\ No newline at end of file