From e9578eb103a90d5ab059a067b2e17ca1ddcedee5 Mon Sep 17 00:00:00 2001 From: "Zhang, Zhenjiang" Date: Tue, 21 Jul 2026 11:23:27 +0800 Subject: Refactor TUH_AUDIO API and simplify multi-AS interface support This commit refactors the TUH_AUDIO (USB Audio Host) class driver to simplify its public API and improve multi-AS (Audio Streaming) interface support. The changes are focused on three files: the core driver (audio_host.c/h) and the example application (audio_app.c). Key changes in src/class/audio/audio_host.h: - Remove tuh_audio_descriptor_cb_t and tuh_audio_mount_cb_t structures. The mount callback no longer passes a large descriptor-info struct; applications query per-AS info via tuh_audio_as_get_info(). - Add tuh_audio_get_dev_addr() and tuh_audio_get_feature_unit_id() accessors to retrieve device address and feature-unit ID from an interface index. - Simplify control-transfer APIs by replacing (daddr, itf_num, unit_id) parameters with a single idx parameter: tuh_audio_set_sampling_freq(idx, as_idx, ...) tuh_audio_get_sampling_freq(idx, as_idx, ...) tuh_audio_feature_unit_set(idx, control_selector, channel, ...) tuh_audio_feature_unit_get(idx, control_selector, channel, ...) - Add synchronous wrapper APIs using TU_API_SYNC macro: tuh_audio_get_sampling_freq_sync() tuh_audio_set_sampling_freq_sync() tuh_audio_feature_unit_set_sync() tuh_audio_feature_unit_get_sync() - Update isochronous endpoint APIs to use (idx, as_idx) instead of (daddr, idx): tuh_audio_receive(idx, as_idx, buffer, len) tuh_audio_send(idx, as_idx, buffer, len) - Remove tuh_audio_descriptor_cb() weak callback. - Update tuh_audio_mount_cb() signature from mount_cb(param) to no param. - Update tuh_audio_rx_cb()/tuh_audio_tx_cb() first parameter from idx to dev_addr for consistency with other class drivers. Key changes in src/class/audio/audio_host.c: - Delete tuh_audio_descriptor_cb weak stub. - Refactor get_idx_by_ep_addr() to iterate all AS interfaces per device instead of relying on single ep_in/ep_out fields. - Add audioh_get_ep_addr_by_dir() helper to find an endpoint address by direction across multiple AS interfaces. - Simplify audioh_close() cleanup: remove now-removed single-endpoint fields (ep_in, ep_out) and rely on tu_memclr(p_audio->as, ...). - Update audioh_xfer_cb() to pass dev_addr (not idx) to rx/tx callbacks, matching the new callback signature. - Simplify audioh_open(): remove descriptor-callback emission and the temporary desc_cb structure; store only ac_itf_num instead of bInterfaceNumber + iInterface + as_interface_num. - Rename local descriptor pointers for clarity: desc_input_terminal (was desc_it) desc_output_terminal (was desc_ot) Key changes in examples/host/audio_host/src/audio_app.c: - Remove now-unnecessary globals: audio_ep_in, audio_ep_out, audio_ac_itf, audio_feature_unit_id. - Initialize audio_dev_addr, audio_idx, audiostream_in_idx, audiostream_out_idx to 0xFF (TUSB_INDEX_INVALID_8) instead of 0. - Update print_as_interfaces() to use tuh_audio_as_get_count() and tuh_audio_as_get_info() instead of accessing mount_cb_data. - Update all callback signatures and API calls to match the new driver API. --- src/class/audio/audio_host.h | 163 +++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 98 deletions(-) (limited to 'src/class/audio/audio_host.h') 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; @@ -58,73 +59,16 @@ typedef struct { #define CFG_TUH_AUDIO_EPOUT_BUFSIZE 192 #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 -- cgit v1.3.1