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.
This commit is contained in:
Krzysztof Kopyściński
2024-04-15 11:50:18 +02:00
committed by Krzysztof Kopyściński
parent 2e20f99575
commit 0d047ce25f
9 changed files with 1870 additions and 0 deletions
+445
View File
@@ -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_ */
+30
View File
@@ -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_ */
+46
View File
@@ -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: "[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
+45
View File
@@ -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_ */
+278
View File
@@ -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
}
+325
View File
@@ -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;
}
+395
View File
@@ -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;
}
+174
View File
@@ -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'
+132
View File
@@ -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"