diff --git a/components/usb/usb_device_uac/Kconfig.uac b/components/usb/usb_device_uac/Kconfig.uac index 536626dac..93211228d 100644 --- a/components/usb/usb_device_uac/Kconfig.uac +++ b/components/usb/usb_device_uac/Kconfig.uac @@ -19,6 +19,20 @@ menu "USB Device UAC" config UAC_SAMPLE_RATE int "UAC sample rate" default 48000 + + choice UAC_SPK_SAMPLE_FORMAT + prompt "UAC SPK sample format" + default UAC_SPK_SAMPLE_FORMAT_PCM + help + SPK: Select in which data type samples shall be expected from USB host. + Currently supports PCM (16-bit signed integer) or IEEE Floating Point (32-bit). + + config UAC_SPK_SAMPLE_FORMAT_PCM + bool "PCM (16-bit)" + + config UAC_SPK_SAMPLE_FORMAT_FLOAT + bool "IEEE Floating Point (32-bit)" + endchoice config UAC_SPK_INTERVAL_MS int "UAC SPK interval(ms)" @@ -26,6 +40,21 @@ menu "USB Device UAC" help SPK: The first interval of reading data from UAC device, in ms. And make SPK FIFO to accommodate data of size n milliseconds. + choice UAC_MIC_SAMPLE_FORMAT + prompt "UAC MIC sample format" + default UAC_MIC_SAMPLE_FORMAT_PCM + help + MIC: Select in which data type samples are sent to USB host. + Currently supports PCM (16-bit signed integer) or IEEE Floating Point (32-bit). + Only affects data rate calculation and USB descriptor! Library user must ensure correct data format. + + config UAC_MIC_SAMPLE_FORMAT_PCM + bool "PCM (16-bit)" + + config UAC_MIC_SAMPLE_FORMAT_FLOAT + bool "IEEE Floating Point (32-bit)" + endchoice + config UAC_MIC_INTERVAL_MS int "UAC MIC interval(ms)" default 10 diff --git a/components/usb/usb_device_uac/tusb_uac/tusb_config_uac.h b/components/usb/usb_device_uac/tusb_uac/tusb_config_uac.h index e8306c386..dee2c9fd2 100644 --- a/components/usb/usb_device_uac/tusb_uac/tusb_config_uac.h +++ b/components/usb/usb_device_uac/tusb_uac/tusb_config_uac.h @@ -19,6 +19,14 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- +// Beware of confusion! + +// When using RX and TX it is out of the perspective of the device (us), +// so RX is the data received from the host (SPK) and TX is the data sent to the host (MIC). + +// But IN and OUT are the perspective of the host, +// so OUT is the data received from the host (SPK) and IN is the data sent to the host (MIC). + // Enable feedback EP #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 @@ -33,29 +41,43 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 1 #define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE DEFAULT_SAMPLE_RATE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX SPEAK_CHANNEL_NUM -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX MIC_CHANNEL_NUM +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX SPEAK_CHANNEL_NUM +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX MIC_CHANNEL_NUM +// Sample type +#if SPK_FORMAT_PCM // 16bit in 16bit slots -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2 -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX 16 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 2 #define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16 +#elif SPK_FORMAT_FLOAT +// 32bit in 32bit slots +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 4 +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 32 +#endif + +#if MIC_FORMAT_PCM +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 2 +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX 16 +#elif MIC_FORMAT_FLOAT +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX 4 +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX 32 +#endif // 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_IN 1 -// MIC -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN ((CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) + 4) +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN ((CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) + 4) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN * (MIC_INTERVAL_MS + 1) #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_IN // Maximum EP IN size for all AS alternate settings used +//------------ SPK (RX / OUT) -------------// + // 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 -// SPK +4 for audio feedback -#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT ((CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX) + 4) +// +4 for audio feedback +#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT ((CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE / 1000 * CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX) + 4) #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT * (SPK_INTERVAL_MS + 1) #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_FUNC_1_FORMAT_1_EP_SZ_OUT // Maximum EP IN size for all AS alternate settings used diff --git a/components/usb/usb_device_uac/tusb_uac/uac_config.h b/components/usb/usb_device_uac/tusb_uac/uac_config.h index 2e5f8ff4d..3fdd75ffe 100644 --- a/components/usb/usb_device_uac/tusb_uac/uac_config.h +++ b/components/usb/usb_device_uac/tusb_uac/uac_config.h @@ -17,6 +17,18 @@ extern "C" { #define SPK_INTERVAL_MS CONFIG_UAC_SPK_INTERVAL_MS /*!< READ INTERVAL in ms*/ #define MIC_INTERVAL_MS CONFIG_UAC_MIC_INTERVAL_MS /*!< WRITE INTERVAL in ms*/ +#if CONFIG_UAC_SPK_SAMPLE_FORMAT_PCM +#define SPK_FORMAT_PCM 1 +#elif CONFIG_UAC_SPK_SAMPLE_FORMAT_FLOAT +#define SPK_FORMAT_FLOAT 1 +#endif + +#if CONFIG_UAC_MIC_SAMPLE_FORMAT_PCM +#define MIC_FORMAT_PCM 1 +#elif CONFIG_UAC_MIC_SAMPLE_FORMAT_FLOAT +#define MIC_FORMAT_FLOAT 1 +#endif + #define IN_CTRL_CH_VALUE U32_TO_U8S_LE(AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS) #if SPEAK_CHANNEL_NUM == 1 diff --git a/components/usb/usb_device_uac/tusb_uac/uac_descriptors.h b/components/usb/usb_device_uac/tusb_uac/uac_descriptors.h index bb43aa1eb..929cb4d14 100644 --- a/components/usb/usb_device_uac/tusb_uac/uac_descriptors.h +++ b/components/usb/usb_device_uac/tusb_uac/uac_descriptors.h @@ -56,6 +56,18 @@ enum { #define UAC2_ENTITY_MIC_FEATURE_TERMINAL 0x12 #define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x13 +#if SPK_FORMAT_PCM +#define SPK_SAMPLE_FORMAT AUDIO_DATA_FORMAT_TYPE_I_PCM +#elif SPK_FORMAT_FLOAT +#define SPK_SAMPLE_FORMAT AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT +#endif + +#if MIC_FORMAT_PCM +#define MIC_SAMPLE_FORMAT AUDIO_DATA_FORMAT_TYPE_I_PCM +#elif MIC_FORMAT_FLOAT +#define MIC_SAMPLE_FORMAT AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT +#endif + #if SPEAK_CHANNEL_NUM && MIC_CHANNEL_NUM #define NUM_INTERFACES 3 #elif SPEAK_CHANNEL_NUM || MIC_CHANNEL_NUM @@ -175,7 +187,7 @@ enum { /* Interface 1, Alternate 1 - alternate interface for data streaming */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ _itfnum + 1, /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ _stridx + 1),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ SPEAK_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ SPK_SAMPLE_FORMAT, /*_nchannelsphysical*/ SPEAK_CHANNEL_NUM, /*_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(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ @@ -191,7 +203,7 @@ enum { /* Interface 2, Alternate 1 - alternate interface for data streaming */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ _itfnum + 2, /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx + 2),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ MIC_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_CENTER, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ MIC_SAMPLE_FORMAT, /*_nchannelsphysical*/ MIC_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_CENTER, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ @@ -226,7 +238,7 @@ enum { /* Interface 1, Alternate 1 - alternate interface for data streaming */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ _itfnum + 1, /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ _stridx + 1),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ MIC_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_CENTER, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ MIC_SAMPLE_FORMAT, /*_nchannelsphysical*/ MIC_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_CENTER, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ @@ -261,7 +273,7 @@ enum { /* Interface 1, Alternate 1 - alternate interface for data streaming */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ _itfnum + 1, /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ _stridx + 1),\ /* Class-Specific AS Interface Descriptor(4.9.2) */\ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ SPEAK_CHANNEL_NUM, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ SPK_SAMPLE_FORMAT, /*_nchannelsphysical*/ SPEAK_CHANNEL_NUM, /*_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(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ diff --git a/components/usb/usb_device_uac/usb_device_uac.c b/components/usb/usb_device_uac/usb_device_uac.c index 2e7f456e6..b1b581a25 100644 --- a/components/usb/usb_device_uac/usb_device_uac.c +++ b/components/usb/usb_device_uac/usb_device_uac.c @@ -312,7 +312,7 @@ bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX if (s_uac_device->spk_itf_num == itf && alt == 0) { TU_LOG2("Speaker interface closed"); s_uac_device->spk_data_size = 0; @@ -320,7 +320,7 @@ bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const } #endif -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX if (s_uac_device->mic_itf_num == itf && alt == 0) { TU_LOG2("Microphone interface closed"); s_uac_device->mic_data_size = 0; @@ -339,7 +339,7 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques TU_LOG2("Set interface %d alt %d\r\n", itf, alt); -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX if (s_uac_device->spk_itf_num == itf && alt != 0) { s_uac_device->spk_data_size = 0; s_uac_device->spk_resolution = spk_resolutions_per_format[alt - 1]; @@ -351,7 +351,7 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques } #endif -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX if (s_uac_device->mic_itf_num == itf && alt != 0) { s_uac_device->mic_data_size = 0; s_uac_device->mic_resolution = mic_resolutions_per_format[alt - 1]; @@ -431,7 +431,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u return true; } -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX static void usb_spk_task(void *pvParam) { while (1) { @@ -453,7 +453,7 @@ static void usb_spk_task(void *pvParam) } #endif -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX static void usb_mic_task(void *pvParam) { while (1) { @@ -505,8 +505,12 @@ esp_err_t uac_device_init(uac_device_config_t *config) s_uac_device->spk_itf_num = config->spk_itf_num; s_uac_device->mic_itf_num = config->mic_itf_num; #else +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX s_uac_device->spk_itf_num = ITF_NUM_AUDIO_STREAMING_SPK; +#endif +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX s_uac_device->mic_itf_num = ITF_NUM_AUDIO_STREAMING_MIC; +#endif #endif BaseType_t ret_val; @@ -522,13 +526,13 @@ esp_err_t uac_device_init(uac_device_config_t *config) ESP_RETURN_ON_FALSE(ret_val == pdPASS, ESP_FAIL, TAG, "Failed to create TinyUSB task"); } -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX ret_val = xTaskCreatePinnedToCore(usb_mic_task, "usb_mic_task", 4096, NULL, CONFIG_UAC_MIC_TASK_PRIORITY, &s_uac_device->mic_task_handle, CONFIG_UAC_MIC_TASK_CORE == -1 ? tskNO_AFFINITY : CONFIG_UAC_MIC_TASK_CORE); ESP_RETURN_ON_FALSE(ret_val == pdPASS, ESP_FAIL, TAG, "Failed to create usb_mic task"); #endif -#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX +#if CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX ret_val = xTaskCreatePinnedToCore(usb_spk_task, "usb_spk_task", 4096, NULL, CONFIG_UAC_SPK_TASK_PRIORITY, &s_uac_device->spk_task_handle, CONFIG_UAC_SPK_TASK_CORE == -1 ? tskNO_AFFINITY : CONFIG_UAC_SPK_TASK_CORE); ESP_RETURN_ON_FALSE(ret_val == pdPASS, ESP_FAIL, TAG, "Failed to create usb_spk task");