diff options
Diffstat (limited to 'examples/host/audio_host/README.md')
| -rw-r--r-- | examples/host/audio_host/README.md | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/examples/host/audio_host/README.md b/examples/host/audio_host/README.md new file mode 100644 index 000000000..7f72aabaf --- /dev/null +++ b/examples/host/audio_host/README.md @@ -0,0 +1,122 @@ +# 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 or UAC 2.0 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 and 2.0 devices +- Discovers the device's logical streams (capture/playback) and their supported configurations (discrete tuples only) +- Reports each stream's mute/volume capabilities and cached volume range +- Configures and starts an S16_LE capture stream (44.1 kHz preferred, 48 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: the main loop reads capture when its FIFO is half full and fills playback when its FIFO is half drained; USB transfer callbacks are not used for FIFO servicing +- 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 UAC1 devices whose Type I Format descriptor lists discrete sampling frequencies (`bSamFreqType > 0`) and UAC2 devices using a directly connected Clock Source, 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` (44.1 kHz stereo by default). Non-PCM formats are rejected by the driver. + +## Limitations and trade-offs + +- Explicit feedback endpoints are supported with both 10.14 and 16.16 feedback values. 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. +- UAC2 supports direct Clock Sources. Clock Selectors, Clock Multipliers, Sampling Rate Converters, Clock Validity, and Valid Alternate Settings controls are not handled. +- UAC2 sampling-frequency RANGE responses are expanded into at most `CFG_TUH_AUDIO_MAX_SAM_FREQ` discrete configurations. A read-only Clock Source exposes only its current frequency. +- Master mute and volume controls are discovered before the mount callback. A Feature Unit with volume only on its logical channels is also supported: the range is read from the first controlled channel, and a stream-volume SET writes every logical channel when no writable master control exists. The typed API assumes all logical channels share one range; applications needing different per-channel ranges can use the raw control API. UAC2 volume discovery supports the common RANGE response containing one subrange. +- The `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 or 2.0) to the USB host port +3. Open a serial terminal to view output +4. The example will: + - Print each stream's mute/volume capabilities, cached volume range, and supported configurations when mounted + - Look for an S16_LE capture configuration at a preferred sample rate (44.1 kHz first, 48 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 stream volumes near -6 dB; a channel-only Feature Unit is updated one logical channel at a time + - Service both FIFOs from `audio_app_task()` at their half-full/half-drained watermarks; 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()`; their asynchronous results are printed from `tuh_audio_event_cb()`, and a failed stream is restarted automatically after 100 ms + +## Serial Output Example + +``` +TinyUSB Host USB Audio Example +Connect a USB Audio Device (UAC 1.0 or 2.0) to test +Audio device mounted: idx=0 addr=1 + capture stream 1, configurations: 2 + master mute supported + 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, configurations: 2 + master mute supported + 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 44100 S16_LE capture (2 channels) + Microphone configured + Microphone master mute: off + Microphone master volume: 0 (1/256 dB) + Microphone volume set: -1536 (1/256 dB) + Configuring 44100 S16_LE playback (2 channels) + Speaker configured + Speaker master mute: off + Speaker master volume: 0 (1/256 dB) + Speaker 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_PROTOCOLS`: Bitmask selecting UAC1 and/or UAC2 support; the example enables both +- `CFG_TUH_AUDIO_MAX_SAM_FREQ`: Maximum number of discrete frequencies retained per alternate setting or UAC2 Clock Source +- `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 + +- `tuh_audio_descriptor_cb()` exposes the validated Audio Control descriptor block during enumeration. Applications that need raw entity controls must copy the required entity IDs or descriptor fields before the callback returns, then use `tuh_audio_control_xfer()` after the device mounts. +- 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()` only count completed transfers; `audio_app_task()` services the FIFOs independently from the main loop. `tuh_audio_event_cb()` reports asynchronous start/stop results and unrecoverable transfer failures. The example restarts a failed stream automatically 100 ms later. +- Capture and playback streams running concurrently 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 read/queued. `tuh_audio_read_available()` reports captured frames ready to read; `tuh_audio_write_available()` reports free playback capacity. `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. |
