Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4390153
feat(audio): add USB Audio Host (UAC 1.0) support
Jul 16, 2026
f76a0f2
Potential fix for pull request finding
zjzhang-cn Jul 16, 2026
817807d
fix(class/audio): handle non-audio interface in enumeration and fix a…
Jul 17, 2026
70113a3
fix(class/audio): fix control request byte order and buffer usage in …
Jul 17, 2026
d4dfed4
fix(class/audio): fix indentation in audioh_set_config after UAC 1.0 …
Jul 17, 2026
786eef5
style(class/audio): rename descriptor variables to desc_ prefix and u…
Jul 17, 2026
e9578eb
Refactor TUH_AUDIO API and simplify multi-AS interface support
Jul 21, 2026
c950109
feat(class/audio): rework TUH_AUDIO into a WASAPI/ALSA-like stream API
Aug 14, 2026
3db8be8
fix(audio): repair the host audio example build
HiFiPhile Aug 25, 2026
367693f
fix(audio): distinguish data and feedback endpoints
HiFiPhile Aug 25, 2026
5fb0a3d
fix(audio): place transfer buffers in configured memory
HiFiPhile Aug 25, 2026
3e3de77
fix(audio): close endpoints before stream reconfiguration
HiFiPhile Aug 25, 2026
edb883a
fix(audio): retain stream state when stop fails
HiFiPhile Aug 25, 2026
350b4fe
fix(audio): serialize Feature Unit requests
HiFiPhile Aug 25, 2026
ebec43e
fix(audio): clear stale Feature Unit associations
HiFiPhile Aug 25, 2026
b26958c
feat(audio): track a Feature Unit per stream direction
HiFiPhile Aug 25, 2026
59b5f9b
fix(audio): configure playback-only example devices
HiFiPhile Aug 25, 2026
f849af3
fix(audio): honor full-speed isochronous intervals
HiFiPhile Aug 25, 2026
a57307b
fix(audio): reject continuous UAC1 sample-rate ranges
HiFiPhile Aug 25, 2026
ef63143
fix(audio): resolve Feature Units independent of order
HiFiPhile Aug 25, 2026
61e3544
test(audio): add UAC1 host driver coverage
HiFiPhile Aug 25, 2026
e590b45
feat(audio): demonstrate speaker volume control
HiFiPhile Aug 25, 2026
dfac26a
Merge master updates into the UAC1 host branch
HiFiPhile Aug 25, 2026
ddf4bad
fix(audio): drive streams from transfer completion
HiFiPhile Aug 25, 2026
aab34b8
refactor(audio): separate stream configuration and start
HiFiPhile Aug 25, 2026
9863f02
fix(audio): avoid playback alt-setting glitch at startup
HiFiPhile Aug 25, 2026
6028a4d
fix(audio): generate a continuous high-resolution test tone
HiFiPhile Aug 25, 2026
8fdf71b
refactor(audio): simplify UAC1 interface discovery
HiFiPhile Aug 25, 2026
0fd3995
fix(audio): accept one data endpoint per AS alternate
HiFiPhile Aug 25, 2026
6224310
fix(audio): keep stream state consistent on control failures
HiFiPhile Aug 25, 2026
3f0a82a
fix(audio): reject unsupported UAC2 interfaces
HiFiPhile Aug 25, 2026
ad9ecdd
fix(audio): retain multiple pending Feature Units
HiFiPhile Aug 25, 2026
ea7d4ef
fix(audio): discard capture data without playback
HiFiPhile Aug 25, 2026
87511ce
fix(audio): release instances without supported streams
HiFiPhile Aug 25, 2026
b0bd26e
fix(audio): decode full-speed isochronous bInterval
HiFiPhile Aug 25, 2026
28a63e7
refactor(audio): simplify class endpoint association
HiFiPhile Aug 25, 2026
d494b7c
fix(audio): validate descriptors before parsing
HiFiPhile Aug 25, 2026
b45f129
feat(audio): discover stream mute and volume controls
HiFiPhile Aug 25, 2026
1b53f8a
restrict example to supported hcd
HiFiPhile Aug 25, 2026
91f3cd0
Merge remote-tracking branch 'origin/master' into feature/tuh-audio-u…
HiFiPhile Aug 25, 2026
934bc7d
fix ci-select-test
HiFiPhile Aug 25, 2026
e2c6dcf
address copilot review findings
HiFiPhile Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ family_initialize_project(tinyusb_host_examples ${CMAKE_CURRENT_LIST_DIR})

# family_add_subdirectory will filter what to actually add based on selected FAMILY
set(EXAMPLE_LIST
audio_host
bare_api
cdc_msc_hid
cdc_msc_hid_freertos
Expand Down
30 changes: 30 additions & 0 deletions examples/host/audio_host/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.20)

include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)

project(audio_host C CXX ASM)

# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR})

# Espressif has its own cmake build system
if(FAMILY STREQUAL "espressif")
return()
endif()

add_executable(${PROJECT_NAME})

# Example source
target_sources(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/audio_app.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)

# Example include
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)

# Configure compilation flags and libraries for the example without RTOS.
# See the corresponding function in hw/bsp/FAMILY/family.cmake for details.
family_configure_host_example(${PROJECT_NAME} noos)
6 changes: 6 additions & 0 deletions examples/host/audio_host/CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"version": 6,
"include": [
"../../../hw/bsp/BoardPresets.json"
]
}
14 changes: 14 additions & 0 deletions examples/host/audio_host/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
include ../../../hw/bsp/family_support.mk

INC += \
src \


# Example source
EXAMPLE_SOURCE += \
src/audio_app.c \
src/main.c

SRC_C += $(addprefix $(EXAMPLE_PATH)/, $(EXAMPLE_SOURCE))

include ../../../hw/bsp/family_rules.mk
117 changes: 117 additions & 0 deletions examples/host/audio_host/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# USB Audio Host Example

This example demonstrates how to use TinyUSB's USB Audio Host driver (TUH_AUDIO) to capture audio from a UAC 1.0 compatible USB microphone and echo it back to the speaker, using a WASAPI/ALSA-like high-level API. The application never touches USB interfaces, alternate settings, or endpoint addresses — it only selects supported `{format, sample_rate, channels}` configurations by stream index.

## Features

- Enumerates and mounts USB Audio Class 1.0 devices
- Discovers the device's logical streams (capture/playback) and their supported configurations (discrete tuples only)
- Reports each stream's master mute/volume capabilities and cached volume range
- Configures and starts an S16_LE capture stream (48 kHz preferred, 44.1 kHz fallback; stereo preferred, mono accepted)
- Echoes captured audio to an S16_LE playback stream at the same sample rate (same channel count preferred, mono/stereo conversion otherwise)
- Frame-based FIFO API: `tuh_audio_read()` / `tuh_audio_write()` queue frames; the driver schedules transfers at the endpoint's polling interval
- Cycles the streams through three phases (5 s each): mic-only (capture, data dropped), spk-only (sine test tone), and echo (capture looped back to playback)

## Supported Devices

This example supports UAC 1.0 devices whose Type I Format descriptor lists discrete sampling frequencies (`bSamFreqType > 0`), such as:

- USB microphones
- USB headsets (mono microphone + speaker)
- USB audio interfaces

The echo needs a matching S16_LE playback stream at the capture sample rate; devices without one run capture-only. The sample rate and channel preferences are configured by the `SAMPLE_RATES` / `AUDIO_MAX_CHANNELS` macros in `src/audio_app.c` (48 kHz stereo by default). Non-PCM formats are rejected by the driver.

## Limitations and trade-offs

- Explicit feedback endpoint data is ignored. Asynchronous playback still uses the nominal sample rate, but device/host clock drift is not corrected and may cause underruns, overruns, or audible pops and clicks. An implicit-feedback IN endpoint is treated as an ordinary audio-data endpoint and is not used to pace playback.
- UAC1 Type I Format descriptors with `bSamFreqType == 0` are unsupported; the driver requires a list of discrete sampling frequencies.
- Master mute and volume controls are discovered before the mount callback, including the volume MIN/MAX/RES range. Feature Units without master mute or volume are ignored. The typed API controls the master channel; the lower-level Feature Unit API remains available for fixed-width UAC1 controls on the associated unit.
- The UAC1 `MaxPacketsOnly` endpoint attribute is not supported. OUT transfers are not padded to `wMaxPacketSize`, and padding in IN transfers is not removed from the reported audio data.

## Building

### Using CMake (recommended)

```bash
cd examples/host/audio_host
mkdir -p build && cd build
cmake -DBOARD=<your_board> -G Ninja ..
cmake --build .
```

Replace `<your_board>` with your target board name (e.g., `raspberry_pi_pico`, `stm32f407disco`, etc.)

### Using Make

```bash
cd examples/host/audio_host
make BOARD=<your_board> all
```

## Flashing

```bash
# Using CMake: list the board-specific flash targets, then select one
ninja -t targets
ninja audio_host-jlink # example for a board with J-Link support

# Using Make
make BOARD=<your_board> flash
```

## Usage

1. Build and flash the example to your board
2. Connect a USB Audio device (UAC 1.0) to the USB host port
3. Open a serial terminal to view output
4. The example will:
- Print each stream's Feature Unit ID, master mute/volume capabilities, cached volume range, and supported configurations when mounted
- Look for an S16_LE capture configuration at a preferred sample rate (48 kHz first, 44.1 kHz fallback; stereo preferred, mono accepted) and configure it
- Echo captured audio to an S16_LE playback configuration at the same sample rate (same channel count preferred, converted otherwise)
- Read/unmute the microphone and speaker Feature Units and set supported master volumes near -6 dB
- Drain the capture FIFO in `audio_app_task_read()` and queue the frames into the playback FIFO; a sine test tone plays on the playback stream when no capture stream is echoing
- Cycle through the three phases (mic-only / spk-only / echo, 5 s each) with `tuh_audio_start()` / `tuh_audio_stop()`; a failed stream is restarted automatically 100 ms after the error callback

## Serial Output Example

```
TinyUSB Host USB Audio Example
Connect a USB Audio Device (UAC 1.0) to test
Audio device mounted: idx=0 addr=1
capture stream 1 Feature Unit ID: 5, configurations: 2
master mute supported
master volume range: min=-23040 max=1536 res=256 (1/256 dB)
[0] format=1 rate=44100 channels=2
[1] format=1 rate=48000 channels=2
playback stream 0 Feature Unit ID: 2, configurations: 2
master mute supported
master volume range: min=-23040 max=1536 res=256 (1/256 dB)
[0] format=1 rate=44100 channels=2
[1] format=1 rate=48000 channels=2
Configuring 48 kHz S16_LE capture (2 channels)
Microphone configured
Microphone Feature Unit 5 master mute: off
Microphone Feature Unit 5 master volume: 0 (1/256 dB)
Microphone master volume set: -1536 (1/256 dB)
Configuring 48 kHz S16_LE playback (2 channels)
Speaker configured
Speaker Feature Unit 2 master mute: off
Speaker Feature Unit 2 master volume: 0 (1/256 dB)
Speaker master volume set: -1536 (1/256 dB)
```

## Configuration

Edit `src/tusb_config.h` to modify:
- `CFG_TUH_AUDIO_MAX`: Maximum number of audio devices supported
- `CFG_TUH_AUDIO_EPIN_BUFSIZE`: Maximum size of one capture transfer the driver submits (configurations needing a larger per-poll-interval packet are rejected)
- `CFG_TUH_AUDIO_EPOUT_BUFSIZE`: Maximum size of one playback transfer the driver submits
- `CFG_TUH_AUDIO_STREAM_BUFSIZE`: Per-stream FIFO depth in bytes (default 1024, i.e. four 256 B packets); capture overwrites the oldest frames when full

## Notes

- While a stream is running, the driver keeps one isochronous transfer in flight and re-submits on completion, so transfers follow the endpoint's `bInterval`. `tuh_audio_capture_cb()` / `tuh_audio_playback_cb()` report each completed transfer; `tuh_audio_err_cb()` reports failures. The example restarts the failed stream automatically 100 ms after the error callback.
- Capture and playback streams in the same Audio Control instance must use the same sample rate.
- `tuh_audio_read()` / `tuh_audio_write()` are non-blocking FIFO operations: they return the number of whole frames actually queued/read (0 when the FIFO is empty/full or the stream is not running), and `tuh_audio_read_available()` / `tuh_audio_write_available()` report the FIFO occupancy in frames. `tuh_audio_write()` only queues data; the playback transfer-completion chain sends it, or sends silence when the FIFO does not contain a complete polling interval without consuming the partial data.
- Isochronous transfers require the host to poll `tuh_task()` continuously; the capture FIFO absorbs short scheduling gaps and overwrites the oldest frames when full.
27 changes: 27 additions & 0 deletions examples/host/audio_host/only.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
family:at32f402_405
family:at32f415
family:at32f423
family:at32f425
family:at32f435_437
family:at32f45x
family:efm32
family:kinetis_kl
family:rx
board:nrf54h20dk
board:nrf54lm20dk
board:stm32l476disco
board:stm32l496nucleo
board:stm32l4p5nucleo
board:stm32l4r5nucleo
mcu:MAX3421
mcu:MSP432E4
mcu:RAXXX
mcu:RP2040
mcu:STM32F2
mcu:STM32F4
mcu:STM32F7
mcu:STM32H7
mcu:STM32H7RS
mcu:STM32N6
mcu:STM32U5
mcu:STM32WBA
28 changes: 28 additions & 0 deletions examples/host/audio_host/src/app.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2025 TinyUSB contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/

#ifndef TUSB_TINYUSB_EXAMPLES_APP_H
#define TUSB_TINYUSB_EXAMPLES_APP_H

#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>

void led_blinking_task(void);
void audio_app_task_read(void);
void audio_app_task_write(void);
void defer_queue_task(void);
#endif
Loading
Loading