mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-09-30 12:37:22 +00:00
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:
committed by
Krzysztof Kopyściński
parent
2e20f99575
commit
0d047ce25f
@@ -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_ */
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user