Skip to content

fix(uac): fix TX packet size for non-integer sample rates (e.g.44100 Hz)#493

Open
leeebo wants to merge 1 commit into
espressif:masterfrom
leeebo:master
Open

fix(uac): fix TX packet size for non-integer sample rates (e.g.44100 Hz)#493
leeebo wants to merge 1 commit into
espressif:masterfrom
leeebo:master

Conversation

@leeebo
Copy link
Copy Markdown
Collaborator

@leeebo leeebo commented May 14, 2026

resolved #174

Release: usb_host_uac v1.5.0 — contains a breaking change to uac_host_dev_alt_param_t. See details below.

Description

This PR releases usb_host_uac v1.5.0 with two driver bug fixes, one public API struct extension, and improvements to the audio_player example.

Breaking Change

uac_host_dev_alt_param_t (public header) gains a new field uint8_t subframe_size inserted between channels and bit_resolution, reflecting the UAC Type I bSubframeSize descriptor field. Any code that initialises this struct with positional (non-designated) initialisers, or compares instances with memcmp, must be updated.

Driver fixes

1. Correct TX packet sizing for non-integer sample rates (e.g. 44100 Hz)

For sample rates that do not produce an integer number of bytes per 1 ms USB frame (e.g. 44100 Hz stereo 16-bit → 176.4 B/ms), the driver previously always rounded the isochronous packet size up by one byte. This introduced a constant positive byte-rate error, causing the ring buffer to drain faster than audio was written and producing audible stuttering.

The fix replaces the unconditional round-up with a fractional accumulator (packet_size_frac / packet_frac_accum). Each submitted URB contributes the floor packet size; the accumulator tracks the fractional remainder and inserts an extra byte only in the packets where it is due, keeping the long-term byte rate exact.

2. Correct TX packet sizing for non-standard subframe sizes

The packet size was previously computed as sample_freq × channels × (bit_resolution / 8). For devices that pad samples into wider subframes (e.g. 24-bit audio in a 4-byte subframe, as described by bSubframeSize in the UAC Type I Format Type descriptor), the calculation underestimated the packet size and caused transfer errors.

The fix reads bSubframeSize from the descriptor into the new subframe_size field and uses it in the packet size formula: sample_freq × channels × subframe_size.

Example improvements (audio_player)

  • Added CONFIG_EXAMPLE_SPK_SAMPLE_FREQ and CONFIG_EXAMPLE_MIC_SAMPLE_FREQ Kconfig options (default 0 = auto). When set, the example searches all device alternate settings for a matching frequency and falls back to the device default if not found.
  • generate_siren_tone now uses subframe_size for frame-size calculation and PCM byte packing, supporting 24-bit-in-4-byte and other non-standard layouts.
  • Siren tone period is now clamped dynamically: if the fixed 48 000-byte PCM buffer is shorter than two full siren periods at the current sample rate, the period is halved so the buffer always contains at least one full high→low→high cycle.
  • MIC recording buffer allocation uses subframe_size instead of bit_resolution / 8 for correct bytes-per-second sizing.

Related

N/A

Testing

Tested on ESP32-P4 with a UAC 1.0 USB headset reporting two alternate settings at 48000 Hz and 44100 Hz (stereo, 16-bit):

  • Set CONFIG_EXAMPLE_SPK_SAMPLE_FREQ=44100; confirmed driver selects the correct alternate setting, sets endpoint frequency to 44100 Hz, and plays the siren tone without stuttering for >60 s.
  • Set CONFIG_EXAMPLE_SPK_SAMPLE_FREQ=0 (auto); driver selects 48000 Hz (device default), tone plays correctly.
  • Verified log output:

Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does introduce a breaking change — documented above and in CHANGELOG.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

Copilot AI review requested due to automatic review settings May 14, 2026 04:07
@leeebo
Copy link
Copy Markdown
Collaborator Author

leeebo commented May 14, 2026

@TDA-2030 @pedrominatel PTAL!

@leeebo leeebo had a problem deploying to esp-docs preview May 14, 2026 04:09 — with GitHub Actions Failure
Copy link
Copy Markdown

Copilot AI left a comment

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 releases usb_host_uac v1.5.0 and fixes UAC TX isochronous packet sizing so playback remains stable for non-integer sample rates (e.g., 44.1 kHz) and for devices whose PCM subframe size differs from bit_resolution/8 (e.g., 24-bit audio padded to 4 bytes).

Changes:

  • Fix TX packet sizing by distributing fractional samples across packets via an accumulator (instead of unconditional round-up).
  • Extend the public alt-setting params with subframe_size (from bSubframeSize) and use it for packet-size calculations and example PCM generation/buffer sizing.
  • Enhance the audio_player example with configurable target sample rates (speaker/mic) and improved siren generation behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
host/class/uac/usb_host_uac/uac_host.c Implements fractional TX packet sizing, uses subframe_size for correct bytes-per-frame, and updates printed device params.
host/class/uac/usb_host_uac/include/usb/uac_host.h Adds subframe_size to uac_host_dev_alt_param_t (breaking struct layout change).
host/class/uac/usb_host_uac/idf_component.yml Bumps component version to 1.5.0.
host/class/uac/usb_host_uac/examples/audio_player/main/main.c Adds sample-rate selection across alt settings and updates PCM generation/buffer sizing to respect subframe_size.
host/class/uac/usb_host_uac/examples/audio_player/main/Kconfig.projbuild Adds Kconfig options for speaker/mic target sample frequency.
host/class/uac/usb_host_uac/CHANGELOG.md Documents 1.5.0 breaking change and fixes.
Comments suppressed due to low confidence (2)

host/class/uac/usb_host_uac/examples/audio_player/main/main.c:384

  • Same fallback issue as the speaker path: when mic_alt_params.sample_freq_type == 0 (continuous range), mic_alt_params.sample_freq[0] is not populated, so mic_freq may become 0. Handle the continuous-range case by choosing a valid frequency from [sample_freq_lower, sample_freq_upper] instead of reading sample_freq[0].
                        ESP_ERROR_CHECK(uac_host_get_device_alt_param(uac_device_handle, 1, &mic_alt_params));
                        mic_freq = mic_alt_params.sample_freq[0];
                    }

host/class/uac/usb_host_uac/examples/audio_player/main/main.c:377

  • Same signed/unsigned issue as speaker: CONFIG_EXAMPLE_MIC_SAMPLE_FREQ is a Kconfig int, but it’s stored in uint32_t mic_freq. A negative Kconfig value will wrap. Use a signed temporary or add a Kconfig range/validation before casting to uint32_t.
                    uint32_t mic_freq = CONFIG_EXAMPLE_MIC_SAMPLE_FREQ;
                    if (mic_freq != 0 && find_dev_alt_params_for_freq(uac_device_handle, mic_freq, &mic_alt_params)) {
                        ESP_LOGI(TAG, "Found alt setting for MIC %" PRIu32 " Hz", mic_freq);

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

Comment thread host/class/uac/usb_host_uac/uac_host.c Outdated
Comment thread host/class/uac/usb_host_uac/uac_host.c Outdated
Comment thread host/class/uac/usb_host_uac/examples/audio_player/main/main.c Outdated
Comment thread host/class/uac/usb_host_uac/examples/audio_player/main/main.c
Copy link
Copy Markdown
Collaborator

@tore-espressif tore-espressif left a comment

Choose a reason for hiding this comment

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

@leeebo Thanks, LGTM!

Should also test on hardware? In case it is in a hurry, we can merge now

@leeebo
Copy link
Copy Markdown
Collaborator Author

leeebo commented May 19, 2026

@leeebo Thanks, LGTM!

Should also test on hardware? In case it is in a hurry, we can merge now

It works on my hardware. @eggfly would you help test if the fix works for you #174?

@leeebo leeebo had a problem deploying to esp-docs preview May 19, 2026 14:17 — with GitHub Actions Failure
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.

Huge noise when playing 44100Hz mp3 in usb_audio_player example (IEC-299)

3 participants