Audio

TinyUSB supports USB Audio Class 1.0 and 2.0 streaming in device and host roles.

Device driver

The descriptors define the topology, formats, channels, rates, controls, and alternate settings; the application supplies or consumes the audio samples.

Start from an example

Audio descriptors and buffer sizes are tightly coupled. Copy the closest example, confirm that it enumerates, and then change one property at a time:

Configuration

Set CFG_TUD_AUDIO to the number of audio functions, at most three. The principal options are:

Option

Default

What it controls

CFG_TUD_AUDIO_CTRL_BUF_SZ

64 bytes

Largest class control payload, such as a RANGE or channel-cluster response. Increase it to fit the largest advertised control.

CFG_TUD_AUDIO_ENABLE_EP_IN

0

Enables microphone/device-to-host streaming.

CFG_TUD_AUDIO_ENABLE_EP_OUT

0

Enables speaker/host-to-device streaming.

CFG_TUD_AUDIO_FUNC_n_EP_IN_SZ_MAX / CFG_TUD_AUDIO_FUNC_n_EP_OUT_SZ_MAX

Required per enabled direction

Maximum endpoint packet size across that function’s alternate settings.

CFG_TUD_AUDIO_FUNC_n_EP_IN_SW_BUF_SZ / CFG_TUD_AUDIO_FUNC_n_EP_OUT_SW_BUF_SZ

0

Software FIFO size. Required for each enabled direction; a value below the maximum endpoint size (the default 0 included) is a build error.

CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL

1

Adapts IN packet consumption to the FIFO fill level to reduce underruns/overruns.

CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP

0

Enables an explicit feedback endpoint, normally required by an asynchronous speaker.

CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP

0

Enables the AudioControl interrupt endpoint for status notifications.

For each enabled direction, define the maximum endpoint size used by any advertised alternate setting, for example CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX. A software FIFO such as CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ must be at least that large. Use TUD_AUDIO_EP_SIZE() as the examples do; high-speed audio has more service intervals per millisecond than full-speed audio.

Data path

Operation

Main API

tud_audio_mounted() / tud_audio_version()

Tests whether function zero is configured and returns its Audio Class version, read from the AudioControl interface descriptor.

tud_audio_available() / tud_audio_read()

Reports and removes speaker bytes from the OUT software FIFO. The read count can be shorter than requested.

tud_audio_write()

Copies microphone bytes into the IN software FIFO and returns the number written. When the FIFO is full the oldest unsent bytes are overwritten, so pace writes to the stream.

tud_audio_clear_ep_*_ff()

Discards queued samples in the selected endpoint FIFO, useful when a streaming alternate setting closes.

tud_audio_get_ep_*_ff()

Returns the underlying FIFO object for advanced zero-copy or DMA integration; the application must preserve its invariants.

tud_audio_n_fb_set()

Supplies the feedback value for one audio function when application feedback mode is used. Pass 16.16 samples per frame at full speed, or per microframe at high speed. UAC1 functions send it as 3-byte 10.14; UAC2 functions always send 4-byte 16.16.

tud_audio_feedback_update()

Updates internally calculated feedback from elapsed master-clock cycles and returns the current 16.16 value, or zero on error.

tud_audio_n_*()

Selects a function explicitly with func_id; helpers without n operate on function zero.

The host starts and stops a stream by selecting interface alternate settings. Use tud_audio_set_itf_cb() and tud_audio_set_itf_close_ep_cb() to start or stop the application-side I2S/DMA path. Do not produce or consume samples merely because the device is mounted; wait until the streaming interface is active.

tud_audio_feedback_interval_isr() runs in interrupt context from the SOF handler. The optional tud_audio_rx_done_isr() and tud_audio_tx_done_isr() callbacks usually run in interrupt context but may run in the context of the call that arms the endpoint; see Using Device Classes.

Control requests

Implement the tud_audio_get_req_*_cb() and tud_audio_set_req_*_cb() callbacks for every control advertised by the descriptors, such as clock frequency, clock validity, mute, and volume. A descriptor that advertises a control but stalls its normal requests is likely to be rejected or behave poorly on a host.

Asynchronous speakers normally need a feedback endpoint. Enable CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP and either configure the feedback method through tud_audio_feedback_params_cb() or provide feedback with tud_audio_n_fb_set(). Begin with the speaker-feedback example; incorrect feedback causes periodic underruns or overruns even when the nominal sample rates match.

Specifications used: USB Device Class Definition for Audio Devices, Release 1.0 and Release 2.0, plus Audio Data Formats, Release 2.0.

Host driver

The host driver discovers one playback stream and one capture stream in each supported AudioControl function. It presents each usable alternate setting and discrete sample rate as a complete format, sample_rate, and channels configuration. The application selects one of these tuples; TinyUSB manages interface alternate settings, endpoints, packet sizing, and explicit feedback.

Start from USB Audio Host Example. It discovers configurations, selects signed 16-bit capture and playback streams, and cycles through microphone, speaker, and loopback operation.

Configuration

Set CFG_TUH_AUDIO to enable the driver. The principal options are:

Option

Default

What it controls

CFG_TUH_AUDIO

0

Enables the Audio host class. A nonzero value includes the driver.

CFG_TUH_AUDIO_PROTOCOLS

UAC1

Bitmask of TUH_AUDIO_PROTOCOL_UAC1 and TUH_AUDIO_PROTOCOL_UAC2. Combine them to accept both versions.

CFG_TUH_AUDIO_MAX

1

Maximum number of mounted AudioControl functions.

CFG_TUH_AUDIO_MAX_AS

4

Maximum number of nonzero-bandwidth alternate settings retained per logical stream.

CFG_TUH_AUDIO_MAX_SAM_FREQ

5

Maximum discrete sample rates retained per UAC1 alternate setting or UAC2 Clock Source.

CFG_TUH_AUDIO_EPIN_BUFSIZE / CFG_TUH_AUDIO_EPOUT_BUFSIZE

256 bytes

Largest capture/playback packet the driver can submit. Capture alternate settings whose wMaxPacketSize exceeds the IN buffer or CFG_TUH_AUDIO_STREAM_BUFSIZE are dropped; a playback configuration whose packet for one polling interval is larger is rejected.

CFG_TUH_AUDIO_STREAM_BUFSIZE

1024 bytes

Per-stream FIFO depth. Playback sends silence when a complete packet is unavailable; capture overwrites the oldest complete frames when the FIFO is full.

Increase the endpoint buffers for high channel counts, sample rates, or sample widths. All buffers are statically allocated, so these maxima directly affect RAM use.

Stream lifecycle

After tuh_audio_mount_cb(), enumerate stream indices from zero through tuh_audio_stream_count() - 1. Use tuh_audio_stream_direction() to distinguish TUH_AUDIO_STREAM_PLAYBACK (host to device) from TUH_AUDIO_STREAM_CAPTURE (device to host). Then enumerate the stream’s configurations with tuh_audio_config_count() and tuh_audio_config_get().

For each stream:

  1. Call tuh_audio_configure() with a supported configuration index while the stream is stopped.

  2. Call tuh_audio_start(). A true return means that startup was submitted, not that it completed.

  3. Wait for TUH_AUDIO_EVENT_START_COMPLETE in tuh_audio_event_cb() and check that its transfer result is successful before handling samples.

  4. Use the non-blocking frame FIFO APIs while the stream runs.

  5. Call tuh_audio_stop() and wait for TUH_AUDIO_EVENT_STOP_COMPLETE before reconfiguring the stream.

Capture and playback streams in the same AudioControl function must use the same sample rate while they run concurrently. tuh_audio_active_config() returns TUSB_INDEX_INVALID_8 when no configuration is selected.

Audio data is counted in frames, not bytes. One frame contains one sample for every channel; obtain its byte size with tuh_audio_config_frame_size(). tuh_audio_read() removes whole frames from a capture FIFO, while tuh_audio_write() queues whole frames for playback. Their return values may be shorter than requested. Use tuh_audio_read_available() and tuh_audio_write_available() to service the FIFOs from the application task; the transfer callbacks are notifications and need not drive FIFO servicing. If the capture FIFO overflows while a task other than the one running tuh_task() reads it, a read can mix old and new samples; keep up with capture.

Callbacks and failures

tuh_audio_descriptor_cb() runs during enumeration, before the mount callback. Its descriptor pointers are valid only during the call. Copy any entity IDs or descriptor fields needed for later raw controls, but do not submit control transfers from this callback.

tuh_audio_capture_cb() and tuh_audio_playback_cb() report successful isochronous transfers. tuh_audio_event_cb() reports asynchronous start and stop completion and TUH_AUDIO_EVENT_XFER_FAILED. A failed stream has been stopped; the application may reconfigure or restart it. Clear all saved indices and associated state in tuh_audio_umount_cb() because an index may be reused by a later device.

Run tuh_task() continuously. Isochronous transfers follow the endpoint’s polling interval, and delaying the host task can exhaust the FIFO even when its average producer and consumer rates match.

Feature Unit controls

The driver discovers master mute and volume capabilities before the mount callback. Test mute with tuh_audio_mute_supported() and retrieve the cached volume range with tuh_audio_volume_range_get(). Volume values use signed 1/256 dB units; TUH_AUDIO_VOLUME_SILENCE represents silence, and TUH_AUDIO_CHANNEL_MASTER selects the master channel.

The asynchronous tuh_audio_mute_*() and tuh_audio_volume_*() APIs use a completion callback. Their synchronous helpers block until completion and should only be used while audio streaming is stopped; synchronous transfers can disrupt isochronous traffic. Use tuh_audio_control_xfer() for other class-specific entity controls. Buffers passed to asynchronous controls must remain valid until their completion callbacks run.

Supported formats and limitations

The host accepts Type-I PCM in signed 8-, 16-, packed 24-, 24-in-32-, and 32-bit little-endian formats. UAC1 descriptors must list discrete sample rates; continuous ranges are not supported. UAC2 requires a directly connected Clock Source. Clock Selectors, Clock Multipliers, Sampling Rate Converters, Clock Validity, and Valid Alternate Settings controls are not handled.

Explicit feedback endpoints using 10.14 or 16.16 values are supported. Implicit-feedback IN endpoints are treated as ordinary capture endpoints and do not pace playback. MaxPacketsOnly endpoints are not supported: OUT packets are not padded to wMaxPacketSize, and padding in IN packets is not removed from the captured data.