Skip to content

feat(audio): add USB Audio Host (UAC 1.0/2.0) support - #3774

Open
zjzhang-cn wants to merge 60 commits into
hathach:masterfrom
zjzhang-cn:feature/tuh-audio-uac-1.0
Open

feat(audio): add USB Audio Host (UAC 1.0/2.0) support #3774
zjzhang-cn wants to merge 60 commits into
hathach:masterfrom
zjzhang-cn:feature/tuh-audio-uac-1.0

Conversation

@zjzhang-cn

@zjzhang-cn zjzhang-cn commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Add TinyUSB Host Audio class driver supporting UAC 1.0/2.0 devices.

Features:

  • Support multiple Audio Streaming (AS) interfaces with independent format storage
  • Support both IN (Microphone) and OUT (Speaker) endpoints
  • Support Explicit feedback
  • Per-AS interface format info: channels, sample rate, bit resolution
  • Support Feature Unit volume/mute control
  • Add host/audio_host example
  • Support mono-to-stereo conversion for loopback

Changes:

  • Add src/class/audio/audio_host.c and audio_host.h
  • Register AUDIO driver in usbh.c
  • Add CFG_TUH_AUDIO macro in tusb_option.h
  • Add host/audio_host example with CMake and Makefile build support

Tested with Jabra USB headset (stereo speaker + mono microphone) on STM32F407 disco.

Zhang, Zhenjiang and others added 2 commits July 16, 2026 15:03
Add TinyUSB Host Audio class driver supporting UAC 1.0 devices.

Features:
- Support multiple Audio Streaming (AS) interfaces with independent format storage
- Support both IN (Microphone) and OUT (Speaker) endpoints
- Per-AS interface format info: channels, sample rate, bit resolution
- Support Feature Unit volume control
- Support sampling frequency get/set
- Add host/audio_host example for STM32F407 discovery board
- Support mono-to-stereo conversion for loopback

Changes:
- Add src/class/audio/audio_host.c and audio_host.h
- Register AUDIO driver in usbh.c
- Add CFG_TUH_AUDIO macro in tusb_option.h
- Add host/audio_host example with CMake and Makefile build support

Tested with Jabra USB headset (stereo speaker + mono microphone) on STM32F407 disco.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 17, 2026 02:02
@zjzhang-cn zjzhang-cn changed the title Feature/tuh audio uac 1.0 feat(audio): add USB Audio Host (UAC 1.0) support Jul 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces initial USB Audio Class (UAC 1.0) Host support to TinyUSB by adding a new host class driver (audio_host.c/.h), wiring it into the host driver registry, and providing a new host-side example application demonstrating enumeration and basic streaming/control requests.

Changes:

  • Add a new TUH Audio (UAC 1.0) host class driver and public host API header.
  • Integrate the new class driver into the host stack and build systems (CMake + Make).
  • Add a new examples/host/audio_host example + README.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/tusb.h Expose TUH audio host API when CFG_TUH_AUDIO is enabled.
src/tusb_option.h Add default CFG_TUH_AUDIO option.
src/tinyusb.mk Compile new audio host class driver.
src/host/usbh.c Register audio host class driver in the host class driver table.
src/CMakeLists.txt Add class/audio/audio_host.c to TinyUSB core sources.
src/class/audio/audio_host.h New TUH audio host public API + callback types.
src/class/audio/audio_host.c New UAC1 host driver implementation (enumeration, set_config, transfers, control requests).
examples/host/audio_host/src/tusb_config.h New example configuration enabling TUH audio.
examples/host/audio_host/src/main.c New host example main loop.
examples/host/audio_host/src/audio_app.c New example “loopback” style audio logic and callbacks.
examples/host/audio_host/src/app.h Example app header.
examples/host/audio_host/README.md Example documentation.
examples/host/audio_host/Makefile Make-based build for the new example.
examples/host/audio_host/CMakeLists.txt CMake-based build for the new example.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/README.md Outdated
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected across 2530 targets. View Project Dashboard →

…sync control transfer buffer

- Stop parsing at first non-Audio interface in audioh_open to avoid claiming unrelated interfaces
- Call usbh_driver_set_config_complete for AS and unknown interfaces to allow enumeration to continue
- Add global ctrl endpoint buffer to audioh_epbuf_t to fix use-after-return in feature_unit_set
- Add sampling_freq NULL check and initialize to 0 in tuh_audio_get_sampling_freq
- Change BOARD_TUH_RHPORT from 1 to 0 in audio_host example
- Add only.txt with supported MCU/family list for audio_host example

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 11 comments.

Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c
Comment thread src/class/audio/audio_host.c Outdated
Comment thread examples/host/audio_host/README.md Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

Hardware-in-the-loop (HIL) Test Report

hfp.json

✅ 55 passed · ❌ 1 failed · ⚪ 0 skipped · blank not run

Board usbtest cdc_msc_throughput audio_test_freertos cdc_dual_ports cdc_msc cdc_msc_freertos dfu dfu_runtime hid_boot_interface hid_generic_inout midi_test msc_dual_lun mtp printer_to_cdc duration
lpcxpresso43s67 ❌ 0/30 ✅ C 12/10.5M M 33/30.7M 85s
stm32l412nucleo ✅ 30/30 ✅ C 501/502k M 511/511k 95s
stm32f746disco ✅ 30/30 ✅ C 13.7/12.4M M 23.4/31.3M 97s
stm32f746disco-DMA ✅ 30/30 ✅ C 15/13.7M M 26.1/34M 86s

tinyusb-esp.json

✅ 0 passed · ❌ 24 failed · ⚪ 0 skipped · blank not run

Board usbtest msc_file_explorer_freertos audio_test_freertos cdc_msc_freertos device_info hid_composite_freertos duration
espressif_p4_function_ev 3s
espressif_p4_function_ev-DMA 3s
espressif_s3_devkitm 3s
espressif_s3_devkitm-DMA 3s

…audio host

- Fix missing tu_htole16() conversions for wValue and wIndex in
  tuh_audio_set_sampling_freq, tuh_audio_get_sampling_freq,
  tuh_audio_feature_unit_set, and tuh_audio_feature_unit_get
- Fix incorrect wIndex parameter order in feature unit requests
  (unit_id and itf_num were swapped)
- Replace static freq_buf with per-endpoint ctrl buffer in
  tuh_audio_set_sampling_freq to avoid concurrency issues
- Update audio_host README to match actual example behavior

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 8 comments.

Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/README.md Outdated
Comment thread src/class/audio/audio_host.c Outdated
Zhang, Zhenjiang added 2 commits July 17, 2026 14:41
…nify const style

Rename descriptor pointer variables to use desc_ prefix for consistency with audio_device.c:

- it -> desc_input_terminal

- ot -> desc_output_terminal

- fu -> desc_feature_unit

- itf -> desc_interface

- p_ep -> desc_endpoint

Unify const qualifier placement to type_t const * style.

Add file header comment describing UAC 1.0 host driver capabilities.

Switch license header to SPDX identifier.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

examples/host/audio_host/README.md:99

  • The Notes section says the example sends a "simple sine wave", but the implementation actually loops back received microphone data to the speaker (with optional mono-to-stereo conversion). This is misleading for users trying to understand the example's behavior.
## Notes

- This example uses isochronous transfers which require precise timing
- For production applications, synchronize audio transfers with the device's audio clock
- The example sends a simple sine wave for testing; replace with actual audio data in real applications

Comment thread src/class/audio/audio_host.c
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
Comment thread examples/host/audio_host/src/audio_app.c Outdated
@HiFiPhile

Copy link
Copy Markdown
Collaborator

Thank you for your work, beside auto reviews, there is a need of some architectural changes:

API shaping

tuh_audio_descriptor_cb and tuh_audio_mount_cb_t should be removed as these are class specific details, we can't expect every user to read UAC specification.
Instead we should provide a list of supported format and sample frequency , similar to aplay --dump-hw-params or Windows audio device properties tab, then the class driver select the corresponding alt settings and sample frequency based user input.
It also makes later UAC2 support easier.
Anyway tuh_descriptor_get_configuration exist if someone needs the detail.

Buffering and packet scheduling

Similar to device driver, FIFO should be included in host driver.
Packet scheduling should be implemented for OUT terminal, when non-integer sample rate is selected eg. 44.1k, the driver should send 9* 44 slots packets and 1* 45 slots packet.
(Optional) feedback support - feedback can be implemented in the same time as packet scheduling, using device feedback sample rate as reference.

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.
@zjzhang-cn

Copy link
Copy Markdown
Contributor Author

I've first completed the API design modifications. Please see if it works

@HiFiPhile

Copy link
Copy Markdown
Collaborator

As I commented earlier, the class driver should provide a WASAPI/ALSA-like high-level API for audio streaming, while keeping the USB Audio topology private.

We can keep the limitation that there is only one logical stream in each direction per instance (AC interface), which is the most common case.

If an instance has multiple Audio Streaming interfaces or alternate settings in one direction, their supported configurations can be combined into the corresponding logical stream. The driver keeps the mapping from each configuration to its interface, alternate setting, and endpoint.

This follows the general WASAPI exclusive-mode and ALSA hw: model: applications select channel count, sample format, and sample rate, while the driver performs the hardware-specific mapping.

Proposed API

Only discrete configurations need to be supported initially. Continuous sample-rate ranges can be rejected or ignored explicitly.

typedef enum {
  TUH_AUDIO_FORMAT_S8,
  TUH_AUDIO_FORMAT_S16_LE,
  TUH_AUDIO_FORMAT_S24_3LE,
  TUH_AUDIO_FORMAT_S24_LE,
  TUH_AUDIO_FORMAT_S32_LE
} tuh_audio_format_t;

typedef struct {
  tuh_audio_format_t format;
  uint32_t sample_rate;
  uint8_t channels;
} tuh_audio_stream_config_t;

typedef void (*tuh_audio_configure_cb_t)(
  uint8_t idx,
  tusb_dir_t direction,
  tusb_xfer_result_t result,
  uintptr_t user_data);

Each entry is a complete supported tuple, avoiding invalid combinations between independent format, rate, and channel lists.

bool tuh_audio_stream_exists(uint8_t idx, tusb_dir_t direction);

uint8_t tuh_audio_config_count(uint8_t idx, tusb_dir_t direction);

bool tuh_audio_config_get(
  uint8_t idx,
  tusb_dir_t direction,
  uint8_t config_idx,
  tuh_audio_stream_config_t* config);

bool tuh_audio_configure(
  uint8_t idx,
  tusb_dir_t direction,
  tuh_audio_stream_config_t const* config,
  tuh_audio_configure_cb_t complete_cb,
  uintptr_t user_data);

tuh_audio_configure() should require an exact supported tuple and asynchronously:

  1. Find its AS interface and alternate setting.
  2. Issue SET_INTERFACE.
  3. Open or reconfigure the selected endpoint.
  4. Set the endpoint sampling frequency when supported.
  5. Initialize the FIFO and packet scheduler.
  6. Invoke complete_cb after the stream is ready or an operation fails.

Streaming should be frame-based:

uint32_t tuh_audio_write(uint8_t idx, void const* buffer, uint32_t frame_count);
uint32_t tuh_audio_read(uint8_t idx, void* buffer, uint32_t frame_count);

uint32_t tuh_audio_write_available(uint8_t idx);
uint32_t tuh_audio_read_available(uint8_t idx);

bool tuh_audio_start(uint8_t idx, tusb_dir_t direction);
bool tuh_audio_stop(uint8_t idx, tusb_dir_t direction);

The class driver should own endpoint selection, FIFO management, transfer replenishment, fractional packet scheduling, and optional feedback processing.

Basic microphone example

The application selects a supported 48 kHz, mono, 16-bit capture configuration without accessing USB interfaces, alternate settings, or endpoint addresses.

static uint8_t mic_idx = TUSB_INDEX_INVALID_8;
static bool mic_ready;
static int16_t mic_samples[48];

static void mic_configured(uint8_t idx, tusb_dir_t direction,
                           tusb_xfer_result_t result, uintptr_t user_data) {
  (void) user_data;

  if (direction == TUSB_DIR_IN && result == XFER_RESULT_SUCCESS) {
    mic_ready = tuh_audio_start(idx, TUSB_DIR_IN);
  }
}

void tuh_audio_mount_cb(uint8_t idx) {
  if (!tuh_audio_stream_exists(idx, TUSB_DIR_IN)) {
    return;
  }

  for (uint8_t i = 0; i < tuh_audio_config_count(idx, TUSB_DIR_IN); i++) {
    tuh_audio_stream_config_t config;
    if (tuh_audio_config_get(idx, TUSB_DIR_IN, i, &config) &&
        config.format == TUH_AUDIO_FORMAT_S16_LE &&
        config.sample_rate == 48000 &&
        config.channels == 1) {
      mic_idx = idx;
      (void) tuh_audio_configure(idx, TUSB_DIR_IN, &config, mic_configured, 0);
      return;
    }
  }
}

void tuh_audio_umount_cb(uint8_t idx) {
  if (idx == mic_idx) {
    mic_idx = TUSB_INDEX_INVALID_8;
    mic_ready = false;
  }
}

void audio_app_task(void) {
  const uint32_t frame_count = TU_ARRAY_SIZE(mic_samples);
  if (mic_ready && tuh_audio_read_available(mic_idx) >= frame_count) {
    (void) tuh_audio_read(mic_idx, mic_samples, frame_count);
    // Process 1 ms of 48 kHz mono audio here.
  }
}

Correctness issues

  1. Audio Host can consume MIDI interfaces.
    audioh_open() continues across every TUSB_CLASS_AUDIO interface. MIDI Streaming uses the same class with another subclass, and Audio Host is registered first. Parse only associated Audio Streaming interfaces, preferably using the AC header’s interface collection.

  2. Alternate settings are overwritten and opened prematurely.
    Every discrete format must remain a separate internal configuration. Do not open every endpoint during descriptor parsing; open or reconfigure only the alternate setting selected by tuh_audio_configure().

  3. SET_INTERFACE failures are ignored.
    Check the return value of tuh_interface_set() and xfer->result. A submission failure currently stalls enumeration, while a failed transfer can still mount the device.

  4. Transfer parameters are insufficiently validated.
    Validate instance state, direction, buffers, frame counts, and endpoint packet limits before submitting transfers.

  5. Feature Unit request lengths are hard-coded.
    UAC1 mute uses a one-byte value while volume uses two bytes. The current generic API always transfers two bytes.

  6. Failed isochronous transfers reach application callbacks.
    audioh_xfer_cb() should not report failed, stalled, or aborted transfers as valid audio data.

  7. The example can overflow its TX buffer.
    Mono-to-stereo conversion doubles the received byte count without bounding it against the TX buffer and selected OUT packet size.

  8. Control-transfer byte order is incomplete.
    Setup-packet multibyte fields require little-endian conversion. Three-byte sampling frequencies and Feature Unit values must be explicitly converted to host-order values.

This smaller API should be enough for a first UAC1 host implementation while leaving room for multiple streams, continuous rates, conversion, and channel mapping later.

@zjzhang-cn

Copy link
Copy Markdown
Contributor Author

During the modification process, a phenomenon was discovered: when MIC and Speaker are both open, usbh_edpt_xfer performing write operations must be called after the TUSB_DIR_IN callback in audioh_xfer_cb; it causes issues in other places.
在修改的过程中发现一个现象,在同时打开MIC 和 Speaker后 usbh_edpt_xfer进行做写操作必须在audioh_xfer_cb的TUSB_DIR_IN回调后调用,其他的地方均有问题。

@HiFiPhile

Copy link
Copy Markdown
Collaborator

During the modification process, a phenomenon was discovered: when MIC and Speaker are both open, usbh_edpt_xfer performing write operations must be called after the TUSB_DIR_IN callback in audioh_xfer_cb; it causes issues in other places. 在修改的过程中发现一个现象,在同时打开MIC 和 Speaker后 usbh_edpt_xfer进行做写操作必须在audioh_xfer_cb的TUSB_DIR_IN回调后调用,其他的地方均有问题。

What kind of issue you met ? There could be some issues as DWC2 HCD hasn't been tested with ISO transfer yet, do you have a USB protocol analyzer ?
At a glance hcchar_bm->err_multi_count should be set to 1.
I may have some time to look into it during my holidays.
也可以给我发邮件.

Provide a high-level audio streaming API over UAC 1.0 devices while
keeping the USB topology private: applications select supported
{format, sample_rate, channels} configurations per logical stream, and
the driver owns the mapping to AS interface, alternate setting, and
endpoint.

- One logical stream per direction per instance; multiple AS interfaces
  and alternate settings in a direction are merged into the stream's
  configuration list (discrete tuples; continuous ranges exposed as a
  single configuration at the top rate)
- Asynchronous tuh_audio_configure(): SET_INTERFACE to the selected
  alternate setting, open/reconfigure the endpoint, set the sampling
  frequency when supported, initialize the FIFO and packet scheduler,
  then invoke the completion callback
- Frame-based FIFO streaming: tuh_audio_read()/tuh_audio_write() queue
  whole frames; the driver owns transfer replenishment and fractional
  packet scheduling (44.1 kHz pays back the 0.1 frame/ms remainder via
  an accumulator for exact average pacing)
- tuh_audio_start()/tuh_audio_stop() activate/deactivate the stream
  interface through SET_INTERFACE (alt n / alt 0)

Driver correctness fixes:
- Parse only the AC header's interface collection; MIDI Streaming and
  other subclasses are skipped
- Keep every discrete format as a separate configuration; endpoints are
  opened only for the alternate setting selected by tuh_audio_configure()
- Check tuh_interface_set() return values and SET_INTERFACE transfer
  results instead of ignoring failures
- Validate instance state, direction, buffers, and frame counts in every
  transfer API
- Feature Unit requests use the control's real width (mute/AGC/loudness
  1 byte, others 2 bytes) and convert multibyte values to host order
- Failed/stalled/aborted isochronous transfers reach only the error
  callback, never the capture/playback callbacks

The audio_host example uses the new API: 48 kHz stereo by default,
automatic stream restart on error callbacks, a sine test tone on the
playback stream, and periodic mic-only / spk-only / echo phase switching.
@zjzhang-cn

Copy link
Copy Markdown
Contributor Author

Running on STM32F4 requires PR 3815

Add the missing preset and shared declarations, remove duplicate initialization, and correct callback call sites so the new example builds through the normal CMake flow.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Signed-off-by: HiFiPHile <admin@hifiphile.com>
@HiFiPhile
HiFiPhile force-pushed the feature/tuh-audio-uac-1.0 branch from d0bbcad to 1b53f8a Compare August 25, 2026 08:33
@HiFiPhile

Copy link
Copy Markdown
Collaborator

Finally I've some time to visit audio host...

The general framework is good, I've made some adjustments and introduced volume/mute api. Now it works correctly with uac2_headset example.

I'm planning to add feedback and UAC2 support.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Transfer-submission failures can permanently stall streams, valid independent duplex rates are rejected, and the promised sampling-frequency get operation is absent.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

src/class/audio/audio_host.c:369

  • A failed playback submission leaves the stream marked running with no transfer in flight, so it cannot make progress or be restarted; it also silently discards the frames removed from the FIFO above. Route submission failure through the stream-error path so the application is notified and can restart.
  TU_ASSERT(usbh_edpt_xfer(s->daddr, map->ep_addr, s->edpt.ep_buf, bytes), );
  • Files reviewed: 23/23 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread src/class/audio/audio_host.c Outdated
Comment thread src/class/audio/audio_host.c Outdated
Comment thread examples/host/audio_host/README.md Outdated
Comment thread src/class/audio/audio_host.c Outdated
Signed-off-by: HiFiPHile <admin@hifiphile.com>
Signed-off-by: HiFiPHile <admin@hifiphile.com>
Store each Audio Streaming alternate setting once and flatten its sample rates only at the public API boundary. Keep feedback and pacing state playback-only, eliminating duplicate configuration fields from capture streams.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Retain every valid discrete rate in descriptor order, including duplicate public tuples. Alternate settings remain independently selectable without disruptive validation or deduplication during enumeration.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Add protocol-selectable UAC1/UAC2 parsing, UAC2 terminal and Feature Unit topology, Clock Source discovery, sampling-frequency ranges, and protocol-specific stream controls. Cover UAC2 playback, capture, control discovery, and malformed descriptors with unit tests.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Keep the fractional packet accumulator when a new explicit-feedback value is latched. Repeated feedback updates no longer bias high-speed fractional rates toward alternating undersized and oversized packets.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Move control-transfer bookkeeping out of USB memory and overlay mount-only Clock RANGE storage with cache-aligned runtime control payload buffers. Keep explicit feedback separate because it may overlap runtime requests.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Enforce a shared capture/playback sample rate only while the opposite stream is running. This lets both stopped streams be configured in either order while preventing a live shared clock from changing underneath a transfer.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Validate descriptor lengths before typed access, keep supported alternate settings when neighboring formats are unsupported, and reject MIDI 1.0 and 2.0 streaming interfaces from the Audio host parser. Extend parser coverage for malformed and mixed descriptor layouts.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Accept the defined silence value and round ordinary volume requests to the nearest supported resolution step within the cached range. Add tests for silence, clamping, and step alignment.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Use UAC1 synchronization attributes and UAC2 endpoint usage fields according to the active protocol. This prevents UAC2 audio-data IN endpoints from being mistaken for explicit feedback endpoints.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Group comments with the structures and helpers they describe, remove review-specific wording, and explain feedback-rate staging and control-buffer lifetimes in terms of runtime behavior.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Remove the narrow public Feature Unit request API while retaining managed mute and volume helpers. Expose validated Audio Control descriptors during enumeration and provide raw asynchronous and synchronous entity requests for advanced controls.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Describe configuration limits by their actual storage scope, document asynchronous stream startup and shutdown, clarify that FIFO APIs are always non-blocking, and correct playback callback ordering.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Move capture and playback FIFO servicing into the main-loop task at half-full and half-drained watermarks. Use transfer callbacks only for diagnostics, share one conversion buffer, and demonstrate that application reads and writes need not be synchronized to USB callbacks.

Signed-off-by: HiFiPHile <admin@hifiphile.com>
Report asynchronous start and stop completion with transfer results. Replace the ambiguous stream error callback and byte count with explicit transfer-failure events, and ignore stale completions after stopping.
Signed-off-by: HiFiPHile <admin@hifiphile.com>
@HiFiPhile

Copy link
Copy Markdown
Collaborator

I've finished explicit feedback and UAC2 work, spent most of the time on #3815.

Tested on Nucleo-U5A5 with a UAC2 high-speed headset.

@HiFiPhile HiFiPhile changed the title feat(audio): add USB Audio Host (UAC 1.0) support feat(audio): add USB Audio Host (UAC 1.0/2.0) support Sep 1, 2026
Signed-off-by: HiFiPHile <admin@hifiphile.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants