diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/class/audio/audio_host.c | 671 | ||||
| -rw-r--r-- | src/class/audio/audio_host.h | 163 |
2 files changed, 356 insertions, 478 deletions
diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c index 396f75987..c74a95d48 100644 --- a/src/class/audio/audio_host.c +++ b/src/class/audio/audio_host.c @@ -4,7 +4,7 @@ * * This file is part of the TinyUSB stack. */ - + /* * This driver implements a USB Audio Host (UAC 1.0) class driver. * It supports multiple Audio Streaming (AS) interfaces with independent format storage. @@ -28,107 +28,70 @@ #if (CFG_TUH_ENABLED && CFG_TUH_AUDIO) -#include "host/usbh.h" -#include "host/usbh_pvt.h" -#include "audio_host.h" + #include "host/usbh.h" + #include "host/usbh_pvt.h" + #include "audio_host.h" -// Level where CFG_TUSB_DEBUG must be at least for this driver is logged -#ifndef CFG_TUH_AUDIO_LOG_LEVEL - #define CFG_TUH_AUDIO_LOG_LEVEL CFG_TUH_LOG_LEVEL -#endif + // Level where CFG_TUSB_DEBUG must be at least for this driver is logged + #ifndef CFG_TUH_AUDIO_LOG_LEVEL + #define CFG_TUH_AUDIO_LOG_LEVEL CFG_TUH_LOG_LEVEL + #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_AUDIO_LOG_LEVEL, __VA_ARGS__) + #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_AUDIO_LOG_LEVEL, __VA_ARGS__) //--------------------------------------------------------------------+ // Weak stubs: invoked if no strong implementation is available //--------------------------------------------------------------------+ -TU_ATTR_WEAK void tuh_audio_descriptor_cb(uint8_t idx, const tuh_audio_descriptor_cb_t *desc_cb_data) { - (void) idx; - (void) desc_cb_data; -} -TU_ATTR_WEAK void tuh_audio_mount_cb(uint8_t idx, const tuh_audio_mount_cb_t *mount_cb_data) { - (void) idx; - (void) mount_cb_data; + +TU_ATTR_WEAK void tuh_audio_mount_cb(uint8_t idx) { + (void)idx; } TU_ATTR_WEAK void tuh_audio_umount_cb(uint8_t idx) { - (void) idx; + (void)idx; } TU_ATTR_WEAK void tuh_audio_rx_cb(uint8_t idx, uint8_t ep_addr, uint16_t xferred_bytes) { - (void) idx; - (void) ep_addr; - (void) xferred_bytes; + (void)idx; + (void)ep_addr; + (void)xferred_bytes; } TU_ATTR_WEAK void tuh_audio_tx_cb(uint8_t idx, uint8_t ep_addr, uint16_t xferred_bytes) { - (void) idx; - (void) ep_addr; - (void) xferred_bytes; + (void)idx; + (void)ep_addr; + (void)xferred_bytes; } //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -// Per-AS interface internal storage -typedef struct { - uint8_t interface_num; - uint8_t alt_setting; - uint8_t ep_addr; - uint16_t ep_size; - uint8_t ep_dir; - - uint8_t format_type; - uint8_t num_channels; - uint8_t sub_frame_size; - uint8_t bit_resolution; - uint8_t sam_freq_type; - uint32_t sam_freq[CFG_TUH_AUDIO_MAX_SAM_FREQ]; - uint32_t sam_freq_lower; - uint32_t sam_freq_upper; -} audioh_as_t; +// Per-interface storage typedef struct { - uint8_t daddr; - uint8_t bInterfaceNumber; // Audio Control interface number - uint8_t iInterface; - uint8_t itf_count; // number of interfaces (AC + AS) - - // Audio Streaming Interface - uint8_t as_interface_num; // Audio Streaming interface number - uint8_t alt_setting; // current alt setting + uint8_t daddr; // device address + uint8_t ac_itf_num; // Audio Control interface number + uint8_t itf_count; // number of interfaces (AC + AS) // Terminal info (from Audio Control Interface) - uint16_t input_terminal_type; // wTerminalType of Input Terminal - uint8_t input_terminal_id; // bTerminalID of Input Terminal - uint8_t input_terminal_channels; // bNrChannels of Input Terminal - uint16_t output_terminal_type; // wTerminalType of Output Terminal - uint8_t output_terminal_id; // bTerminalID of Output Terminal + uint16_t input_terminal_type; // wTerminalType of Input Terminal + uint8_t input_terminal_id; // bTerminalID of Input Terminal + uint8_t input_terminal_channels; // bNrChannels of Input Terminal + uint16_t output_terminal_type; // wTerminalType of Output Terminal + uint8_t output_terminal_id; // bTerminalID of Output Terminal // Feature Unit info - uint8_t feature_unit_id; // bUnitID of Feature Unit (0 = none) - uint8_t feature_unit_source_id; // bSourceID of Feature Unit - - // Isochronous IN endpoint - uint8_t ep_in; - uint16_t ep_in_size; - uint16_t ep_in_interval; - - // Isochronous OUT endpoint - uint8_t ep_out; - uint16_t ep_out_size; - uint16_t ep_out_interval; + uint8_t feature_unit_id; // bUnitID of Feature Unit (0 = none) + uint8_t feature_unit_source_id; // bSourceID of Feature Unit // Multiple AS interfaces support - uint8_t as_interfaces[CFG_TUH_AUDIO_MAX_AS]; - uint8_t as_alt_settings[CFG_TUH_AUDIO_MAX_AS]; uint8_t as_count; uint8_t as_set_idx; // Per-AS interface independent storage (new) - audioh_as_t as[CFG_TUH_AUDIO_MAX_AS]; + tuh_audio_as_info_t as[CFG_TUH_AUDIO_MAX_AS]; // Array of Audio Streaming interface info structures bool mounted; } audioh_interface_t; @@ -140,7 +103,7 @@ typedef struct { } audioh_epbuf_t; static audioh_interface_t _audioh_itf[CFG_TUH_AUDIO_MAX]; - static audioh_epbuf_t _audioh_epbuf[CFG_TUH_AUDIO_MAX]; +static audioh_epbuf_t _audioh_epbuf[CFG_TUH_AUDIO_MAX]; //--------------------------------------------------------------------+ // Helper //--------------------------------------------------------------------+ @@ -156,14 +119,28 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t find_new_audio_index(void) { static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for (uint8_t idx = 0; idx < CFG_TUH_AUDIO_MAX; idx++) { const audioh_interface_t *p_audio = &_audioh_itf[idx]; - if ((p_audio->daddr == daddr) && - (ep_addr == p_audio->ep_in || ep_addr == p_audio->ep_out)) { - return idx; + if (p_audio->daddr == daddr) { + for (uint8_t as_idx = 0; as_idx < p_audio->as_count; as_idx++) { + if (p_audio->as[as_idx].ep_addr == ep_addr) { + return idx; + } + } } } return TUSB_INDEX_INVALID_8; } +static uint8_t audioh_get_ep_addr_by_dir(const audioh_interface_t *p_audio, uint8_t dir) { + for (uint8_t as_idx = 0; as_idx < p_audio->as_count; as_idx++) { + const tuh_audio_as_info_t *as = &p_audio->as[as_idx]; + if (as->ep_addr != 0 && as->ep_dir == dir) { + return as->ep_addr; + } + } + + return 0; +} + //--------------------------------------------------------------------+ // USBH API //--------------------------------------------------------------------+ @@ -183,32 +160,22 @@ void audioh_close(uint8_t daddr) { TU_LOG_DRV(" AUDIO close addr = %u index = %u\r\n", daddr, idx); tuh_audio_umount_cb(idx); - p_audio->bInterfaceNumber = 0; - p_audio->as_interface_num = 0; - p_audio->alt_setting = 0; - p_audio->daddr = 0; - p_audio->mounted = false; - p_audio->ep_in = 0; - p_audio->ep_out = 0; - p_audio->as_count = 0; + p_audio->ac_itf_num = 0; + p_audio->daddr = 0; + p_audio->mounted = false; + p_audio->as_count = 0; p_audio->as_set_idx = 0; - tu_memclr(p_audio->as_interfaces, sizeof(p_audio->as_interfaces)); - tu_memclr(p_audio->as_alt_settings, sizeof(p_audio->as_alt_settings)); tu_memclr(p_audio->as, sizeof(p_audio->as)); } } } bool audioh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) result; - const uint8_t idx = get_idx_by_ep_addr(dev_addr, ep_addr); - TU_VERIFY(idx < CFG_TUH_AUDIO_MAX); - audioh_interface_t *p_audio = &_audioh_itf[idx]; - - if (ep_addr == p_audio->ep_in) { - tuh_audio_rx_cb(idx, ep_addr, (uint16_t) xferred_bytes); - } else if (ep_addr == p_audio->ep_out) { - tuh_audio_tx_cb(idx, ep_addr, (uint16_t) xferred_bytes); + (void)result; + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + tuh_audio_rx_cb(dev_addr, ep_addr, (uint16_t)xferred_bytes); + } else { + tuh_audio_tx_cb(dev_addr, ep_addr, (uint16_t)xferred_bytes); } return true; @@ -218,29 +185,24 @@ bool audioh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uin // Enumeration //--------------------------------------------------------------------+ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface_t *desc_itf, uint16_t max_len) { - (void) rhport; + (void)rhport; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass, 0); TU_VERIFY(AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass, 0); const uint8_t *desc_start = (const uint8_t *)desc_itf; - const uint8_t *p_desc = desc_start; - const uint8_t *desc_end = desc_start + max_len; + const uint8_t *p_desc = desc_start; + const uint8_t *desc_end = desc_start + max_len; const uint8_t idx = find_new_audio_index(); TU_VERIFY(idx < CFG_TUH_AUDIO_MAX, 0); audioh_interface_t *p_audio = &_audioh_itf[idx]; - p_audio->itf_count = 0; - - tuh_audio_descriptor_cb_t desc_cb = { 0 }; + p_audio->itf_count = 0; // Parse Audio Control Interface TU_LOG_DRV("AUDIO opening AC Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); - p_audio->bInterfaceNumber = desc_itf->bInterfaceNumber; - p_audio->iInterface = desc_itf->iInterface; - p_audio->itf_count = 1; - desc_cb.desc_ac_interface = desc_itf; - desc_cb.ac_interface_num = desc_itf->bInterfaceNumber; + p_audio->ac_itf_num = desc_itf->bInterfaceNumber; + p_audio->itf_count = 1; // Parse Audio Control interface descriptors (Input Terminal, Output Terminal, Feature Unit, etc.) p_desc = tu_desc_next(p_desc); @@ -248,26 +210,26 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE) { switch (tu_desc_subtype(p_desc)) { case AUDIO10_CS_AC_INTERFACE_INPUT_TERMINAL: { - audio10_desc_input_terminal_t const *desc_input_terminal = (audio10_desc_input_terminal_t const *)p_desc; - p_audio->input_terminal_type = tu_le16toh(desc_input_terminal->wTerminalType); - p_audio->input_terminal_id = desc_input_terminal->bTerminalID; - p_audio->input_terminal_channels = desc_input_terminal->bNrChannels; - TU_LOG_DRV(" Input Terminal: ID=%u, Type=0x%04x, Channels=%u\r\n", - desc_input_terminal->bTerminalID, tu_le16toh(desc_input_terminal->wTerminalType), desc_input_terminal->bNrChannels); + const audio10_desc_input_terminal_t *desc_input_terminal = (const audio10_desc_input_terminal_t *)p_desc; + p_audio->input_terminal_type = tu_le16toh(desc_input_terminal->wTerminalType); + p_audio->input_terminal_id = desc_input_terminal->bTerminalID; + p_audio->input_terminal_channels = desc_input_terminal->bNrChannels; + TU_LOG_DRV(" Input Terminal: ID=%u, Type=0x%04x, Channels=%u\r\n", desc_input_terminal->bTerminalID, + tu_le16toh(desc_input_terminal->wTerminalType), desc_input_terminal->bNrChannels); break; } case AUDIO10_CS_AC_INTERFACE_OUTPUT_TERMINAL: { - audio10_desc_output_terminal_t const *desc_output_terminal = (audio10_desc_output_terminal_t const *)p_desc; - p_audio->output_terminal_type = tu_le16toh(desc_output_terminal->wTerminalType); - p_audio->output_terminal_id = desc_output_terminal->bTerminalID; - TU_LOG_DRV(" Output Terminal: ID=%u, Type=0x%04x\r\n", - desc_output_terminal->bTerminalID, tu_le16toh(desc_output_terminal->wTerminalType)); + const audio10_desc_output_terminal_t *desc_output_terminal = (const audio10_desc_output_terminal_t *)p_desc; + p_audio->output_terminal_type = tu_le16toh(desc_output_terminal->wTerminalType); + p_audio->output_terminal_id = desc_output_terminal->bTerminalID; + TU_LOG_DRV(" Output Terminal: ID=%u, Type=0x%04x\r\n", desc_output_terminal->bTerminalID, + tu_le16toh(desc_output_terminal->wTerminalType)); break; } case AUDIO10_CS_AC_INTERFACE_FEATURE_UNIT: { - uint8_t const *desc_feature_unit = p_desc; - p_audio->feature_unit_id = desc_feature_unit[3]; // bUnitID - p_audio->feature_unit_source_id = desc_feature_unit[4]; // bSourceID + const uint8_t *desc_feature_unit = p_desc; + p_audio->feature_unit_id = desc_feature_unit[3]; // bUnitID + p_audio->feature_unit_source_id = desc_feature_unit[4]; // bSourceID TU_LOG_DRV(" Feature Unit: ID=%u, SourceID=%u\r\n", desc_feature_unit[3], desc_feature_unit[4]); break; } @@ -281,40 +243,31 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface // Parse all remaining descriptors in this configuration looking for Audio Streaming interfaces while (tu_desc_in_bounds(p_desc, desc_end)) { if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) { - tusb_desc_interface_t const *desc_interface = (tusb_desc_interface_t const *)p_desc; - // Stop at the first non-Audio interface so we don't claim the rest of the configuration - if (desc_interface->bInterfaceClass != TUSB_CLASS_AUDIO) break; - if (desc_interface->bInterfaceSubClass == AUDIO_SUBCLASS_STREAMING) { + const tusb_desc_interface_t *desc_interface = (const tusb_desc_interface_t *)p_desc; + // Stop at the first non-Audio interface so we don't claim the rest of the configuration + if (desc_interface->bInterfaceClass != TUSB_CLASS_AUDIO) { + break; + } + if (desc_interface->bInterfaceSubClass == AUDIO_SUBCLASS_STREAMING) { // Found Audio Streaming Interface - TU_LOG_DRV(" Found AS Interface %u (alt = %u)\r\n", desc_interface->bInterfaceNumber, desc_interface->bAlternateSetting); + TU_LOG_DRV(" Found AS Interface %u (alt = %u)\r\n", desc_interface->bInterfaceNumber, + desc_interface->bAlternateSetting); if (desc_interface->bAlternateSetting == 0) { // Interface descriptor with alt setting 0 (no endpoints) - // Add to AS interfaces array + // Add to AS entries if (p_audio->as_count < CFG_TUH_AUDIO_MAX_AS) { - p_audio->as_interface_num = desc_interface->bInterfaceNumber; - p_audio->as_interfaces[p_audio->as_count] = desc_interface->bInterfaceNumber; - desc_cb.desc_as_interface = desc_interface; - desc_cb.as_interface_num = desc_interface->bInterfaceNumber; - // Create new AS entry for per-interface storage p_audio->as[p_audio->as_count].interface_num = desc_interface->bInterfaceNumber; - p_audio->as[p_audio->as_count].alt_setting = 0; + p_audio->as[p_audio->as_count].alt_setting = 0; p_audio->as_count++; + } else { + TU_LOG_DRV(" Skip AS Interface %u: reach CFG_TUH_AUDIO_MAX_AS=%u\r\n", desc_interface->bInterfaceNumber, + CFG_TUH_AUDIO_MAX_AS); } } else if (desc_interface->bNumEndpoints > 0) { // Interface descriptor with alt setting > 0 (has endpoints) - // Find matching AS interface and set alt_setting + // Find matching AS entry and set alt_setting uint8_t as_entry_idx = CFG_TUH_AUDIO_MAX_AS; - for (uint8_t as_idx = 0; as_idx < p_audio->as_count; as_idx++) { - if (p_audio->as_interfaces[as_idx] == desc_interface->bInterfaceNumber) { - p_audio->alt_setting = desc_interface->bAlternateSetting; - p_audio->as_alt_settings[as_idx] = desc_interface->bAlternateSetting; - desc_cb.alt_setting = desc_interface->bAlternateSetting; - desc_cb.desc_as_interface_alt = desc_interface; - break; - } - } - // Find or create AS entry for per-interface storage for (uint8_t i = 0; i < p_audio->as_count; i++) { if (p_audio->as[i].interface_num == desc_interface->bInterfaceNumber) { as_entry_idx = i; @@ -322,7 +275,7 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface } } if (as_entry_idx >= CFG_TUH_AUDIO_MAX_AS && p_audio->as_count < CFG_TUH_AUDIO_MAX_AS) { - as_entry_idx = p_audio->as_count; + as_entry_idx = p_audio->as_count; p_audio->as[as_entry_idx].interface_num = desc_interface->bInterfaceNumber; p_audio->as_count++; } @@ -333,48 +286,49 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface // Parse the interface's descriptors p_desc = tu_desc_next(p_desc); // Temporary variables to hold format info until endpoint direction is known - uint8_t tmp_format_type = 0; - uint8_t tmp_num_channels = 0; - uint8_t tmp_sub_frame_size = 0; - uint8_t tmp_bit_resolution = 0; - uint8_t tmp_sam_freq_type = 0; + uint8_t tmp_format_type = 0; + uint8_t tmp_num_channels = 0; + uint8_t tmp_sub_frame_size = 0; + uint8_t tmp_bit_resolution = 0; + uint8_t tmp_sam_freq_type = 0; uint32_t tmp_sam_freq[CFG_TUH_AUDIO_MAX_SAM_FREQ] = {0}; - uint32_t tmp_sam_freq_lower = 0; - uint32_t tmp_sam_freq_upper = 0; + uint32_t tmp_sam_freq_lower = 0; + uint32_t tmp_sam_freq_upper = 0; while (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) != TUSB_DESC_INTERFACE) { switch (tu_desc_type(p_desc)) { case TUSB_DESC_CS_INTERFACE: { switch (tu_desc_subtype(p_desc)) { case AUDIO10_CS_AS_INTERFACE_AS_GENERAL: { TU_LOG_DRV(" AS General descriptor\r\n"); - desc_cb.desc_cs_as_general = p_desc; break; } case AUDIO10_CS_AS_INTERFACE_FORMAT_TYPE: { TU_LOG_DRV(" Format Type descriptor\r\n"); - desc_cb.desc_format_type = p_desc; + TU_ASSERT(p_desc[0] >= 8, 0); // Parse UAC 1.0 Format Type I descriptor fields into temporary variables - tmp_format_type = p_desc[3]; // bFormatType - tmp_num_channels = p_desc[4]; // bNrChannels - tmp_sub_frame_size = p_desc[5]; // bSubFrameSize - tmp_bit_resolution = p_desc[6]; // bBitResolution + tmp_format_type = p_desc[3]; // bFormatType + tmp_num_channels = p_desc[4]; // bNrChannels + tmp_sub_frame_size = p_desc[5]; // bSubFrameSize + tmp_bit_resolution = p_desc[6]; // bBitResolution // Parse sampling frequencies uint8_t bLength = p_desc[0]; if (bLength >= 8) { - tmp_sam_freq_type = p_desc[7]; // bSamFreqType + tmp_sam_freq_type = p_desc[7]; // bSamFreqType if (tmp_sam_freq_type == 0) { // Continuous range: tLowerSamFreq, tUpperSamFreq (3 bytes each) if (bLength >= 14) { - tmp_sam_freq_lower = ((uint32_t)p_desc[8] | ((uint32_t)p_desc[9] << 8) | ((uint32_t)p_desc[10] << 16)); - tmp_sam_freq_upper = ((uint32_t)p_desc[11] | ((uint32_t)p_desc[12] << 8) | ((uint32_t)p_desc[13] << 16)); + tmp_sam_freq_lower = + ((uint32_t)p_desc[8] | ((uint32_t)p_desc[9] << 8) | ((uint32_t)p_desc[10] << 16)); + tmp_sam_freq_upper = + ((uint32_t)p_desc[11] | ((uint32_t)p_desc[12] << 8) | ((uint32_t)p_desc[13] << 16)); } } else { // Discrete sampling frequencies - uint8_t max_freqs = tmp_sam_freq_type < CFG_TUH_AUDIO_MAX_SAM_FREQ ? tmp_sam_freq_type : CFG_TUH_AUDIO_MAX_SAM_FREQ; + uint8_t max_freqs = tmp_sam_freq_type < CFG_TUH_AUDIO_MAX_SAM_FREQ ? tmp_sam_freq_type + : CFG_TUH_AUDIO_MAX_SAM_FREQ; for (uint8_t i = 0; i < max_freqs && (8 + i * 3 + 2) < bLength; i++) { - tmp_sam_freq[i] = ((uint32_t)p_desc[8 + i * 3] | - ((uint32_t)p_desc[9 + i * 3] << 8) | + tmp_sam_freq[i] = ((uint32_t)p_desc[8 + i * 3] | ((uint32_t)p_desc[9 + i * 3] << 8) | ((uint32_t)p_desc[10 + i * 3] << 16)); } } @@ -391,21 +345,17 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface if (desc_endpoint->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { TU_LOG_DRV(" Isochronous EP %02x\r\n", desc_endpoint->bEndpointAddress); if (tu_edpt_dir(desc_endpoint->bEndpointAddress) == TUSB_DIR_IN) { - p_audio->ep_in = desc_endpoint->bEndpointAddress; - p_audio->ep_in_size = tu_edpt_packet_size(desc_endpoint); - p_audio->ep_in_interval = desc_endpoint->bInterval; - desc_cb.desc_ep_in = desc_endpoint; // Save to per-AS storage if (as_entry_idx < CFG_TUH_AUDIO_MAX_AS) { - audioh_as_t *as = &p_audio->as[as_entry_idx]; - as->ep_addr = desc_endpoint->bEndpointAddress; - as->ep_size = tu_edpt_packet_size(desc_endpoint); - as->ep_dir = TUSB_DIR_IN; - as->format_type = tmp_format_type; - as->num_channels = tmp_num_channels; + tuh_audio_as_info_t *as = &p_audio->as[as_entry_idx]; + as->ep_addr = desc_endpoint->bEndpointAddress; + as->ep_size = tu_edpt_packet_size(desc_endpoint); + as->ep_dir = TUSB_DIR_IN; + as->format_type = tmp_format_type; + as->num_channels = tmp_num_channels; as->sub_frame_size = tmp_sub_frame_size; as->bit_resolution = tmp_bit_resolution; - as->sam_freq_type = tmp_sam_freq_type; + as->sam_freq_type = tmp_sam_freq_type; as->sam_freq_lower = tmp_sam_freq_lower; as->sam_freq_upper = tmp_sam_freq_upper; for (uint8_t i = 0; i < CFG_TUH_AUDIO_MAX_SAM_FREQ; i++) { @@ -413,21 +363,17 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface } } } else { - p_audio->ep_out = desc_endpoint->bEndpointAddress; - p_audio->ep_out_size = tu_edpt_packet_size(desc_endpoint); - p_audio->ep_out_interval = desc_endpoint->bInterval; - desc_cb.desc_ep_out = desc_endpoint; // Save to per-AS storage if (as_entry_idx < CFG_TUH_AUDIO_MAX_AS) { - audioh_as_t *as = &p_audio->as[as_entry_idx]; - as->ep_addr = desc_endpoint->bEndpointAddress; - as->ep_size = tu_edpt_packet_size(desc_endpoint); - as->ep_dir = TUSB_DIR_OUT; - as->format_type = tmp_format_type; - as->num_channels = tmp_num_channels; + tuh_audio_as_info_t *as = &p_audio->as[as_entry_idx]; + as->ep_addr = desc_endpoint->bEndpointAddress; + as->ep_size = tu_edpt_packet_size(desc_endpoint); + as->ep_dir = TUSB_DIR_OUT; + as->format_type = tmp_format_type; + as->num_channels = tmp_num_channels; as->sub_frame_size = tmp_sub_frame_size; as->bit_resolution = tmp_bit_resolution; - as->sam_freq_type = tmp_sam_freq_type; + as->sam_freq_type = tmp_sam_freq_type; as->sam_freq_lower = tmp_sam_freq_lower; as->sam_freq_upper = tmp_sam_freq_upper; for (uint8_t i = 0; i < CFG_TUH_AUDIO_MAX_SAM_FREQ; i++) { @@ -449,7 +395,8 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface continue; } p_audio->itf_count++; - } else if (desc_interface->bInterfaceClass == TUSB_CLASS_AUDIO && desc_interface->bInterfaceSubClass == AUDIO_SUBCLASS_CONTROL) { + } else if (desc_interface->bInterfaceClass == TUSB_CLASS_AUDIO && + desc_interface->bInterfaceSubClass == AUDIO_SUBCLASS_CONTROL) { // Another Audio Control interface (shouldn't happen in normal UAC 1.0) p_audio->itf_count++; } @@ -458,23 +405,22 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface } p_audio->daddr = dev_addr; - tuh_audio_descriptor_cb(idx, &desc_cb); return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_start); } static void _audioh_mount(uint8_t dev_addr, uint8_t idx); -static void audioh_set_interface_complete(tuh_xfer_t* xfer) { - uint8_t idx = (uint8_t) xfer->user_data; +static void audioh_set_interface_complete(tuh_xfer_t *xfer) { + uint8_t idx = (uint8_t)xfer->user_data; audioh_interface_t *p_audio = &_audioh_itf[idx]; // Send SET_INTERFACE for next AS interface if any p_audio->as_set_idx++; if (p_audio->as_set_idx < p_audio->as_count) { uint8_t as_idx = p_audio->as_set_idx; - uint8_t itf = p_audio->as_interfaces[as_idx]; - uint8_t alt = p_audio->as_alt_settings[as_idx]; + uint8_t itf = p_audio->as[as_idx].interface_num; + uint8_t alt = p_audio->as[as_idx].alt_setting; if (alt > 0) { TU_LOG_DRV("AUDIO Set Interface %u Alt %u (addr = %u)\r\n", itf, alt, xfer->daddr); tuh_interface_set(xfer->daddr, itf, alt, audioh_set_interface_complete, idx); @@ -488,49 +434,12 @@ static void audioh_set_interface_complete(tuh_xfer_t* xfer) { static void _audioh_mount(uint8_t dev_addr, uint8_t idx) { audioh_interface_t *p_audio = &_audioh_itf[idx]; - p_audio->mounted = true; - - tuh_audio_mount_cb_t mount_cb_data = { - .daddr = dev_addr, - .bInterfaceNumber = p_audio->bInterfaceNumber, - .bAltSetting = p_audio->alt_setting, - .input_terminal_type = p_audio->input_terminal_type, - .input_terminal_id = p_audio->input_terminal_id, - .input_terminal_channels = p_audio->input_terminal_channels, - .output_terminal_type = p_audio->output_terminal_type, - .output_terminal_id = p_audio->output_terminal_id, - .feature_unit_id = p_audio->feature_unit_id, - .feature_unit_source_id = p_audio->feature_unit_source_id, - .ep_in = p_audio->ep_in, - .ep_out = p_audio->ep_out, - .ep_in_size = p_audio->ep_in_size, - .ep_out_size = p_audio->ep_out_size, - }; + p_audio->mounted = true; - // Fill per-AS interface info - mount_cb_data.as_count = p_audio->as_count; - for (uint8_t i = 0; i < p_audio->as_count && i < CFG_TUH_AUDIO_MAX_AS; i++) { - audioh_as_t *as = &p_audio->as[i]; - mount_cb_data.as_info[i].interface_num = as->interface_num; - mount_cb_data.as_info[i].alt_setting = as->alt_setting; - mount_cb_data.as_info[i].ep_addr = as->ep_addr; - mount_cb_data.as_info[i].ep_size = as->ep_size; - mount_cb_data.as_info[i].ep_dir = as->ep_dir; - mount_cb_data.as_info[i].format_type = as->format_type; - mount_cb_data.as_info[i].num_channels = as->num_channels; - mount_cb_data.as_info[i].sub_frame_size = as->sub_frame_size; - mount_cb_data.as_info[i].bit_resolution = as->bit_resolution; - mount_cb_data.as_info[i].sam_freq_type = as->sam_freq_type; - mount_cb_data.as_info[i].sam_freq_lower = as->sam_freq_lower; - mount_cb_data.as_info[i].sam_freq_upper = as->sam_freq_upper; - for (uint8_t j = 0; j < CFG_TUH_AUDIO_MAX_SAM_FREQ; j++) { - mount_cb_data.as_info[i].sam_freq[j] = as->sam_freq[j]; - } - } - tuh_audio_mount_cb(idx, &mount_cb_data); + tuh_audio_mount_cb(idx); - usbh_driver_set_config_complete(dev_addr, p_audio->bInterfaceNumber); + usbh_driver_set_config_complete(dev_addr, p_audio->ac_itf_num); } bool audioh_set_config(uint8_t dev_addr, uint8_t itf_num) { @@ -539,24 +448,30 @@ bool audioh_set_config(uint8_t dev_addr, uint8_t itf_num) { // If not found, check if this is an AS interface that belongs to a known AC interface if (idx >= CFG_TUH_AUDIO_MAX) { for (uint8_t i = 0; i < CFG_TUH_AUDIO_MAX; i++) { - if (_audioh_itf[i].daddr == dev_addr && _audioh_itf[i].as_interface_num == itf_num) { - // AS interface: configuration is driven by the AC interface, so just pass through - usbh_driver_set_config_complete(dev_addr, itf_num); - return true; + const audioh_interface_t *p_audio = &_audioh_itf[i]; + if (p_audio->daddr == dev_addr) { + for (uint8_t as_idx = 0; as_idx < p_audio->as_count; as_idx++) { + if (p_audio->as[as_idx].interface_num == itf_num) { + // AS interface: configuration is driven by the AC interface, so just pass through + usbh_driver_set_config_complete(dev_addr, itf_num); + return true; + } + } } } - // Not an Audio interface we own; pass through so enumeration can continue - usbh_driver_set_config_complete(dev_addr, itf_num); - return true; + // Not an Audio interface we own; pass through so enumeration can continue + usbh_driver_set_config_complete(dev_addr, itf_num); + return true; } audioh_interface_t *p_audio = &_audioh_itf[idx]; + TU_VERIFY(p_audio->as_count <= CFG_TUH_AUDIO_MAX_AS, false); // Send SET_INTERFACE for all AS interfaces with alt_setting > 0 if (p_audio->as_count > 0) { p_audio->as_set_idx = 0; - uint8_t itf = p_audio->as_interfaces[0]; - uint8_t alt = p_audio->as_alt_settings[0]; + uint8_t itf = p_audio->as[0].interface_num; + uint8_t alt = p_audio->as[0].alt_setting; if (alt > 0) { TU_LOG_DRV("AUDIO Set Interface %u Alt %u (addr = %u)\r\n", itf, alt, dev_addr); tuh_interface_set(dev_addr, itf, alt, audioh_set_interface_complete, idx); @@ -577,10 +492,21 @@ bool tuh_audio_mounted(uint8_t idx) { return p_audio->mounted; } +uint8_t tuh_audio_get_dev_addr(uint8_t idx) { + audioh_interface_t *p_audio = &_audioh_itf[idx]; + return p_audio->daddr; +} + + +uint8_t tuh_audio_get_feature_unit_id(uint8_t idx) { + audioh_interface_t *p_audio = &_audioh_itf[idx]; + return p_audio->feature_unit_id; +} + uint8_t tuh_audio_itf_get_index(uint8_t daddr, uint8_t itf_num) { for (uint8_t idx = 0; idx < CFG_TUH_AUDIO_MAX; idx++) { const audioh_interface_t *p_audio = &_audioh_itf[idx]; - if (p_audio->daddr == daddr && p_audio->bInterfaceNumber == itf_num) { + if (p_audio->daddr == daddr && p_audio->ac_itf_num == itf_num) { return idx; } } @@ -595,16 +521,19 @@ bool tuh_audio_itf_get_info(uint8_t idx, tuh_itf_info_t *info) { // re-construct descriptor tusb_desc_interface_t *desc_interface = &info->desc; - desc_interface->bLength = sizeof(tusb_desc_interface_t); - desc_interface->bDescriptorType = TUSB_DESC_INTERFACE; + desc_interface->bLength = sizeof(tusb_desc_interface_t); + desc_interface->bDescriptorType = TUSB_DESC_INTERFACE; + + uint8_t ep_in = audioh_get_ep_addr_by_dir(p_audio, TUSB_DIR_IN); + uint8_t ep_out = audioh_get_ep_addr_by_dir(p_audio, TUSB_DIR_OUT); - desc_interface->bInterfaceNumber = p_audio->bInterfaceNumber; - desc_interface->bAlternateSetting = 0; - desc_interface->bNumEndpoints = (uint8_t)((p_audio->ep_in ? 1u : 0u) + (p_audio->ep_out ? 1u : 0u)); - desc_interface->bInterfaceClass = TUSB_CLASS_AUDIO; + desc_interface->bInterfaceNumber = p_audio->ac_itf_num; + desc_interface->bAlternateSetting = 0; + desc_interface->bNumEndpoints = (uint8_t)((ep_in ? 1u : 0u) + (ep_out ? 1u : 0u)); + desc_interface->bInterfaceClass = TUSB_CLASS_AUDIO; desc_interface->bInterfaceSubClass = AUDIO_SUBCLASS_CONTROL; desc_interface->bInterfaceProtocol = 0; - desc_interface->iInterface = p_audio->iInterface; + desc_interface->iInterface = 0; return true; } @@ -612,22 +541,22 @@ bool tuh_audio_itf_get_info(uint8_t idx, tuh_itf_info_t *info) { //--------------------------------------------------------------------+ // Control Endpoint API //--------------------------------------------------------------------+ -bool tuh_audio_set_sampling_freq(uint8_t daddr, uint8_t ep_addr, uint32_t sampling_freq, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); +bool tuh_audio_set_sampling_freq(uint8_t idx, uint8_t as_idx, uint32_t sampling_freq, tuh_xfer_cb_t complete_cb, + uintptr_t user_data) { TU_VERIFY(idx < CFG_TUH_AUDIO_MAX, false); - uint8_t* freq_buf = _audioh_epbuf[idx].ctrl; - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_ENDPOINT, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = AUDIO10_CS_REQ_SET_CUR, - .wValue = tu_htole16(tu_u16(AUDIO10_EP_CTRL_SAMPLING_FREQ, 0)), // Control Selector = Sampling Freq, Channel = 0 - .wIndex = tu_htole16((uint16_t) ep_addr), - .wLength = 3 - }; + audioh_interface_t *p_audio = &_audioh_itf[idx]; + TU_VERIFY(p_audio && as_idx < p_audio->as_count, false); + + uint8_t ep_addr = p_audio->as[as_idx].ep_addr; + uint8_t daddr = p_audio->daddr; + uint8_t *freq_buf = _audioh_epbuf[idx].ctrl; + + const tusb_control_request_t request = + {.bmRequestType_bit = {.recipient = TUSB_REQ_RCPT_ENDPOINT, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT}, + .bRequest = AUDIO10_CS_REQ_SET_CUR, + .wValue = tu_htole16(tu_u16(AUDIO10_EP_CTRL_SAMPLING_FREQ, 0)), // Control Selector = Sampling Freq, Channel = 0 + .wIndex = tu_htole16((uint16_t)ep_addr), + .wLength = 3}; // UAC 1.0 sampling frequency is 3 bytes little-endian // uint8_t freq_buf[3] = { @@ -635,109 +564,97 @@ bool tuh_audio_set_sampling_freq(uint8_t daddr, uint8_t ep_addr, uint32_t sampli // (uint8_t)((sampling_freq >> 8) & 0xFF), // (uint8_t)((sampling_freq >> 16) & 0xFF) // }; - freq_buf[0] = (uint8_t)(sampling_freq & 0xFF); - freq_buf[1] = (uint8_t)((sampling_freq >> 8) & 0xFF); - freq_buf[2] = (uint8_t)((sampling_freq >> 16) & 0xFF); - tuh_xfer_t xfer = { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = freq_buf, - .complete_cb = complete_cb, - .user_data = user_data - }; + freq_buf[0] = (uint8_t)(sampling_freq & 0xFF); + freq_buf[1] = (uint8_t)((sampling_freq >> 8) & 0xFF); + freq_buf[2] = (uint8_t)((sampling_freq >> 16) & 0xFF); + tuh_xfer_t xfer = {.daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = freq_buf, + .complete_cb = complete_cb, + .user_data = user_data}; return tuh_control_xfer(&xfer); } -bool tuh_audio_get_sampling_freq(uint8_t daddr, uint8_t ep_addr, uint32_t *sampling_freq, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(sampling_freq, false); +bool tuh_audio_get_sampling_freq(uint8_t idx, uint8_t as_idx, uint32_t *sampling_freq, tuh_xfer_cb_t complete_cb, + uintptr_t user_data) { + TU_VERIFY(idx < CFG_TUH_AUDIO_MAX, false); + audioh_interface_t *p_audio = &_audioh_itf[idx]; + TU_VERIFY(p_audio && as_idx < p_audio->as_count && sampling_freq, false); + uint8_t ep_addr = p_audio->as[as_idx].ep_addr; + uint8_t daddr = p_audio->daddr; + *sampling_freq = 0; - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_ENDPOINT, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = AUDIO10_CS_REQ_GET_CUR, - .wValue = tu_htole16(tu_u16(AUDIO10_EP_CTRL_SAMPLING_FREQ, 0)), // Control Selector = Sampling Freq, Channel = 0 - .wIndex = tu_htole16((uint16_t) ep_addr), - .wLength = 3 - }; + const tusb_control_request_t request = + {.bmRequestType_bit = {.recipient = TUSB_REQ_RCPT_ENDPOINT, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN}, + .bRequest = AUDIO10_CS_REQ_GET_CUR, + .wValue = tu_htole16(tu_u16(AUDIO10_EP_CTRL_SAMPLING_FREQ, 0)), // Control Selector = Sampling Freq, Channel = 0 + .wIndex = tu_htole16((uint16_t)ep_addr), + .wLength = 3}; // Application needs to parse 3-byte little-endian sampling frequency from buffer - tuh_xfer_t xfer = { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = (uint8_t *)sampling_freq, - .complete_cb = complete_cb, - .user_data = user_data - }; + tuh_xfer_t xfer = {.daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = (uint8_t *)sampling_freq, + .complete_cb = complete_cb, + .user_data = user_data}; return tuh_control_xfer(&xfer); } -bool tuh_audio_feature_unit_set(uint8_t daddr, uint8_t itf_num, uint8_t unit_id, - uint8_t control_selector, uint8_t channel, - uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = AUDIO10_CS_REQ_SET_CUR, - .wValue = tu_htole16(tu_u16(control_selector, channel)), - .wIndex = tu_htole16(tu_u16(unit_id, itf_num)), - .wLength = 2 - }; - - uint8_t const idx = tuh_audio_itf_get_index(daddr, itf_num); +bool tuh_audio_feature_unit_set(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t value, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(idx < CFG_TUH_AUDIO_MAX, false); + uint8_t daddr = _audioh_itf[idx].daddr; + uint8_t itf_num = _audioh_itf[idx].ac_itf_num; + uint8_t unit_id = _audioh_itf[idx].feature_unit_id; - uint8_t* val_buf = _audioh_epbuf[idx].ctrl; - val_buf[0] = (uint8_t)(value & 0xFF); - val_buf[1] = (uint8_t)((value >> 8) & 0xFF); + const tusb_control_request_t request = {.bmRequestType_bit = {.recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT}, + .bRequest = AUDIO10_CS_REQ_SET_CUR, + .wValue = tu_htole16(tu_u16(control_selector, channel)), + .wIndex = tu_htole16(tu_u16(unit_id, itf_num)), + .wLength = 2}; - tuh_xfer_t xfer = { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = val_buf, - .complete_cb = complete_cb, - .user_data = user_data - }; + uint8_t *val_buf = _audioh_epbuf[idx].ctrl; + val_buf[0] = (uint8_t)(value & 0xFF); + val_buf[1] = (uint8_t)((value >> 8) & 0xFF); + + tuh_xfer_t xfer = {.daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = val_buf, + .complete_cb = complete_cb, + .user_data = user_data}; return tuh_control_xfer(&xfer); } -bool tuh_audio_feature_unit_get(uint8_t daddr, uint8_t itf_num, uint8_t unit_id, - uint8_t control_selector, uint8_t channel, - void *buffer, uint8_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_IN - }, - .bRequest = AUDIO10_CS_REQ_GET_CUR, - .wValue = tu_htole16(tu_u16(control_selector, channel)), - .wIndex = tu_htole16(tu_u16(unit_id, itf_num)), - .wLength = len - }; +bool tuh_audio_feature_unit_get(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t *buffer, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(idx < CFG_TUH_AUDIO_MAX, false); + uint8_t daddr = _audioh_itf[idx].daddr; + uint8_t itf_num = _audioh_itf[idx].ac_itf_num; + uint8_t unit_id = _audioh_itf[idx].feature_unit_id; + + const tusb_control_request_t request = {.bmRequestType_bit = {.recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN}, + .bRequest = AUDIO10_CS_REQ_GET_CUR, + .wValue = tu_htole16(tu_u16(control_selector, channel)), + .wIndex = tu_htole16(tu_u16(unit_id, itf_num)), + .wLength = 2}; - tuh_xfer_t xfer = { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = buffer, - .complete_cb = complete_cb, - .user_data = user_data - }; + tuh_xfer_t xfer = {.daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = (uint8_t *)buffer, + .complete_cb = complete_cb, + .user_data = user_data}; return tuh_control_xfer(&xfer); } @@ -755,17 +672,17 @@ bool tuh_audio_as_get_info(uint8_t idx, uint8_t as_idx, tuh_audio_as_info_t *inf TU_VERIFY(as_idx < _audioh_itf[idx].as_count, false); TU_VERIFY(info, false); - audioh_as_t *as = &_audioh_itf[idx].as[as_idx]; - info->interface_num = as->interface_num; - info->alt_setting = as->alt_setting; - info->ep_addr = as->ep_addr; - info->ep_size = as->ep_size; - info->ep_dir = as->ep_dir; - info->format_type = as->format_type; - info->num_channels = as->num_channels; + tuh_audio_as_info_t *as = &_audioh_itf[idx].as[as_idx]; + info->interface_num = as->interface_num; + info->alt_setting = as->alt_setting; + info->ep_addr = as->ep_addr; + info->ep_size = as->ep_size; + info->ep_dir = as->ep_dir; + info->format_type = as->format_type; + info->num_channels = as->num_channels; info->sub_frame_size = as->sub_frame_size; info->bit_resolution = as->bit_resolution; - info->sam_freq_type = as->sam_freq_type; + info->sam_freq_type = as->sam_freq_type; info->sam_freq_lower = as->sam_freq_lower; info->sam_freq_upper = as->sam_freq_upper; memcpy(info->sam_freq, as->sam_freq, sizeof(info->sam_freq)); @@ -775,49 +692,43 @@ bool tuh_audio_as_get_info(uint8_t idx, uint8_t as_idx, tuh_audio_as_info_t *inf //--------------------------------------------------------------------+ // Isochronous Endpoint API //--------------------------------------------------------------------+ -bool tuh_audio_receive(uint8_t daddr, uint8_t idx, uint8_t *buffer, uint16_t len) { +bool tuh_audio_receive(uint8_t idx, uint8_t as_idx, uint8_t *buffer, uint16_t len) { TU_VERIFY(idx < CFG_TUH_AUDIO_MAX); audioh_interface_t *p_audio = &_audioh_itf[idx]; - TU_VERIFY(p_audio->daddr == daddr); - TU_VERIFY(p_audio->ep_in != 0); + tuh_audio_as_info_t *as = &p_audio->as[as_idx]; + TU_VERIFY(as->ep_addr != 0); - return usbh_edpt_xfer(daddr, p_audio->ep_in, buffer, len); + return usbh_edpt_xfer(p_audio->daddr, as->ep_addr, buffer, len); } -bool tuh_audio_send(uint8_t daddr, uint8_t idx, uint8_t *buffer, uint16_t len) { +bool tuh_audio_send(uint8_t idx, uint8_t as_idx, uint8_t *buffer, uint16_t len) { TU_VERIFY(idx < CFG_TUH_AUDIO_MAX); audioh_interface_t *p_audio = &_audioh_itf[idx]; - TU_VERIFY(p_audio->daddr == daddr); - TU_VERIFY(p_audio->ep_out != 0); + tuh_audio_as_info_t *as = &p_audio->as[as_idx]; + TU_VERIFY(as->ep_addr != 0); - return usbh_edpt_xfer(daddr, p_audio->ep_out, (uint8_t *)buffer, len); + return usbh_edpt_xfer(p_audio->daddr, as->ep_addr, (uint8_t *)buffer, len); } //--------------------------------------------------------------------+ // Set Interface //--------------------------------------------------------------------+ -bool tuh_audio_set_interface(uint8_t daddr, uint8_t itf_num, uint8_t alt_setting, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_OUT - }, - .bRequest = TUSB_REQ_SET_INTERFACE, - .wValue = alt_setting, - .wIndex = itf_num, - .wLength = 0 - }; +bool tuh_audio_set_interface(uint8_t daddr, uint8_t itf_num, uint8_t alt_setting, tuh_xfer_cb_t complete_cb, + uintptr_t user_data) { + const tusb_control_request_t request = {.bmRequestType_bit = {.recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT}, + .bRequest = TUSB_REQ_SET_INTERFACE, + .wValue = alt_setting, + .wIndex = itf_num, + .wLength = 0}; - tuh_xfer_t xfer = { - .daddr = daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb, - .user_data = user_data - }; + tuh_xfer_t xfer = {.daddr = daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb, + .user_data = user_data}; return tuh_control_xfer(&xfer); } diff --git a/src/class/audio/audio_host.h b/src/class/audio/audio_host.h index 5c5a8b3df..aafd58f43 100644 --- a/src/class/audio/audio_host.h +++ b/src/class/audio/audio_host.h @@ -17,14 +17,15 @@ extern "C" { //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ +// Maximum number of Audio interfaces per Audio device #ifndef CFG_TUH_AUDIO_MAX #define CFG_TUH_AUDIO_MAX 1 #endif - +// Maximum number of Audio Streaming interfaces per Audio device #ifndef CFG_TUH_AUDIO_MAX_SAM_FREQ #define CFG_TUH_AUDIO_MAX_SAM_FREQ 5 #endif - +// Maximum number of Audio Streaming interfaces per Audio device #ifndef CFG_TUH_AUDIO_MAX_AS #define CFG_TUH_AUDIO_MAX_AS 4 #endif @@ -33,18 +34,18 @@ extern "C" { // AS Interface Info (per-interface independent storage) //--------------------------------------------------------------------+ typedef struct { - uint8_t interface_num; // AS interface number - uint8_t alt_setting; // Current alt setting - uint8_t ep_addr; // Endpoint address - uint16_t ep_size; // Max packet size - uint8_t ep_dir; // TUSB_DIR_IN or TUSB_DIR_OUT + uint8_t interface_num; // AS interface number + uint8_t alt_setting; // Current alt setting + uint8_t ep_addr; // Endpoint address + uint16_t ep_size; // Max packet size + uint8_t ep_dir; // TUSB_DIR_IN or TUSB_DIR_OUT // Format info - uint8_t format_type; - uint8_t num_channels; - uint8_t sub_frame_size; - uint8_t bit_resolution; - uint8_t sam_freq_type; + uint8_t format_type; + uint8_t num_channels; + uint8_t sub_frame_size; + uint8_t bit_resolution; + uint8_t sam_freq_type; uint32_t sam_freq[CFG_TUH_AUDIO_MAX_SAM_FREQ]; uint32_t sam_freq_lower; uint32_t sam_freq_upper; @@ -59,72 +60,15 @@ typedef struct { #endif //--------------------------------------------------------------------+ -// Descriptor Information -//--------------------------------------------------------------------+ -// Information about parsed UAC 1.0 descriptors passed to the application -// during enumeration (via tuh_audio_descriptor_cb) -typedef struct { - // Audio Control Interface descriptor - const tusb_desc_interface_t *desc_ac_interface; - - // Audio Streaming Interface descriptor (alt setting 0) - const tusb_desc_interface_t *desc_as_interface; - - // Audio Streaming Interface alt setting (with endpoints) - const tusb_desc_interface_t *desc_as_interface_alt; - - // Format Type descriptor - const uint8_t *desc_format_type; - - // Class-Specific AS Interface (AS General) descriptor - const uint8_t *desc_cs_as_general; - - // Standard Isochronous Endpoint descriptor (IN) - const tusb_desc_endpoint_t *desc_ep_in; - - // Standard Isochronous Endpoint descriptor (OUT) - const tusb_desc_endpoint_t *desc_ep_out; - - // Audio function information - uint8_t ac_interface_num; // Audio Control interface number - uint8_t as_interface_num; // Audio Streaming interface number - uint8_t alt_setting; // Current alt setting with endpoints -} tuh_audio_descriptor_cb_t; - -typedef struct { - uint8_t daddr; - uint8_t bInterfaceNumber; - uint8_t bAltSetting; - - // Terminal info (from Audio Control Interface) - uint16_t input_terminal_type; // wTerminalType of Input Terminal (0x0201 = Mic, etc.) - uint8_t input_terminal_id; // bTerminalID of Input Terminal - uint8_t input_terminal_channels; // bNrChannels of Input Terminal - uint16_t output_terminal_type; // wTerminalType of Output Terminal (0x0301 = Speaker, etc.) - uint8_t output_terminal_id; // bTerminalID of Output Terminal - - // Feature Unit info - uint8_t feature_unit_id; // bUnitID of Feature Unit (0 = none) - uint8_t feature_unit_source_id; // bSourceID of Feature Unit - - // Endpoint info - uint8_t ep_in; - uint8_t ep_out; - uint16_t ep_in_size; - uint16_t ep_out_size; - - // Multi-AS support (per AS interface independent storage) - uint8_t as_count; - tuh_audio_as_info_t as_info[CFG_TUH_AUDIO_MAX_AS]; -} tuh_audio_mount_cb_t; - -//--------------------------------------------------------------------+ // Application API //--------------------------------------------------------------------+ // Check if Audio interface is mounted bool tuh_audio_mounted(uint8_t idx); - +// Get device address of Audio interface +uint8_t tuh_audio_get_dev_addr(uint8_t idx); +// Get Feature Unit ID +uint8_t tuh_audio_get_feature_unit_id(uint8_t idx); // Get Interface index from device address + interface number // return TUSB_INDEX_INVALID_8 (0xFF) if not found uint8_t tuh_audio_itf_get_index(uint8_t daddr, uint8_t itf_num); @@ -141,8 +85,8 @@ uint8_t tuh_audio_as_get_count(uint8_t idx); bool tuh_audio_as_get_info(uint8_t idx, uint8_t as_idx, tuh_audio_as_info_t *info); // Set Audio Streaming interface alternate setting (to enable/disable endpoints) -bool tuh_audio_set_interface(uint8_t daddr, uint8_t itf_num, uint8_t alt_setting, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +bool tuh_audio_set_interface(uint8_t daddr, uint8_t itf_num, uint8_t alt_setting, tuh_xfer_cb_t complete_cb, + uintptr_t user_data); //--------------------------------------------------------------------+ // Control Endpoint API @@ -150,54 +94,77 @@ bool tuh_audio_set_interface(uint8_t daddr, uint8_t itf_num, uint8_t alt_setting // Set current sampling frequency on an isochronous endpoint (UAC 1.0) // Sampling frequency is 3 bytes little-endian -bool tuh_audio_set_sampling_freq(uint8_t daddr, uint8_t ep_addr, uint32_t sampling_freq, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// In multi-AS scenarios, pass the endpoint address from tuh_audio_as_get_info(). +bool tuh_audio_set_sampling_freq(uint8_t idx, uint8_t as_idx, uint32_t sampling_freq, tuh_xfer_cb_t complete_cb, + uintptr_t user_data); // Get current sampling frequency from an isochronous endpoint (UAC 1.0) -bool tuh_audio_get_sampling_freq(uint8_t daddr, uint8_t ep_addr, uint32_t *sampling_freq, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// In multi-AS scenarios, pass the endpoint address from tuh_audio_as_get_info(). +bool tuh_audio_get_sampling_freq(uint8_t idx, uint8_t as_idx, uint32_t *sampling_freq, tuh_xfer_cb_t complete_cb, + uintptr_t user_data); // Set current/mute/volume etc. for a feature unit (UAC 1.0) -bool tuh_audio_feature_unit_set(uint8_t daddr, uint8_t itf_num, uint8_t unit_id, - uint8_t control_selector, uint8_t channel, - uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +bool tuh_audio_feature_unit_set(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t value, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Get current/mute/volume etc. from a feature unit (UAC 1.0) -bool tuh_audio_feature_unit_get(uint8_t daddr, uint8_t itf_num, uint8_t unit_id, - uint8_t control_selector, uint8_t channel, - void *buffer, uint8_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +bool tuh_audio_feature_unit_get(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t *value, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); + +//--------------------------------------------------------------------+ +// Control Request Sync API +// Each Function will make a USB control transfer request to/from device the function will block until request is +// complete. The function will return the transfer request result +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_get_sampling_freq_sync(uint8_t idx, uint8_t as_idx, + uint32_t *sampling_freq) { + TU_API_SYNC(tuh_audio_get_sampling_freq, idx, as_idx, sampling_freq); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_set_sampling_freq_sync(uint8_t idx, uint8_t as_idx, + uint32_t sampling_freq) { + TU_API_SYNC(tuh_audio_set_sampling_freq, idx, as_idx, sampling_freq); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t +tuh_audio_feature_unit_set_sync(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t value) { + TU_API_SYNC(tuh_audio_feature_unit_set, idx, control_selector, channel, value); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t +tuh_audio_feature_unit_get_sync(uint8_t idx, uint8_t control_selector, uint8_t channel, uint16_t *value) { + TU_API_SYNC(tuh_audio_feature_unit_get, idx, control_selector, channel, value); +} //--------------------------------------------------------------------+ // Interrupt/Isochronous Endpoint API //--------------------------------------------------------------------+ -// Submit an isochronous transfer to receive audio data from IN endpoint -bool tuh_audio_receive(uint8_t daddr, uint8_t idx, uint8_t *buffer, uint16_t len); +// Submit an isochronous transfer to receive audio data from a default IN endpoint. +// In multi-AS scenarios, endpoint selection is implementation-defined default behavior. +// Use tuh_audio_as_get_info() when application needs explicit per-AS endpoint control. +bool tuh_audio_receive(uint8_t idx, uint8_t as_idx, uint8_t *buffer, uint16_t len); -// Submit an isochronous transfer to send audio data to OUT endpoint -bool tuh_audio_send(uint8_t daddr, uint8_t idx, uint8_t *buffer, uint16_t len); +// Submit an isochronous transfer to send audio data to a default OUT endpoint. +// In multi-AS scenarios, endpoint selection is implementation-defined default behavior. +// Use tuh_audio_as_get_info() when application needs explicit per-AS endpoint control. +bool tuh_audio_send(uint8_t idx, uint8_t as_idx, uint8_t *buffer, uint16_t len); //--------------------------------------------------------------------+ // Callbacks (Weak is optional) //--------------------------------------------------------------------+ -// Invoked when Audio interface descriptor is detected during enumeration. -// Application can copy/parse descriptor if needed. -// Note: may be fired before tuh_audio_mount_cb(), therefore audio interface is not mounted/ready. -void tuh_audio_descriptor_cb(uint8_t idx, const tuh_audio_descriptor_cb_t *desc_cb_data); - // Invoked when device with Audio interface is mounted -void tuh_audio_mount_cb(uint8_t idx, const tuh_audio_mount_cb_t *mount_cb_data); +void tuh_audio_mount_cb(uint8_t idx); // Invoked when device with Audio interface is un-mounted void tuh_audio_umount_cb(uint8_t idx); // Invoked when an isochronous IN transfer is complete -void tuh_audio_rx_cb(uint8_t idx, uint8_t ep_addr, uint16_t xferred_bytes); +void tuh_audio_rx_cb(uint8_t dev_addr, uint8_t ep_addr, uint16_t xferred_bytes); // Invoked when an isochronous OUT transfer is complete -void tuh_audio_tx_cb(uint8_t idx, uint8_t ep_addr, uint16_t xferred_bytes); +void tuh_audio_tx_cb(uint8_t dev_addr, uint8_t ep_addr, uint16_t xferred_bytes); //--------------------------------------------------------------------+ // Internal Class Driver API |
