fix(uac): fix TX packet size for non-integer sample rates (e.g.44100 Hz)#493
fix(uac): fix TX packet size for non-integer sample rates (e.g.44100 Hz)#493leeebo wants to merge 1 commit into
Conversation
|
@TDA-2030 @pedrominatel PTAL! |
There was a problem hiding this comment.
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(frombSubframeSize) and use it for packet-size calculations and example PCM generation/buffer sizing. - Enhance the
audio_playerexample 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, somic_freqmay become 0. Handle the continuous-range case by choosing a valid frequency from[sample_freq_lower, sample_freq_upper]instead of readingsample_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_FREQis a Kconfigint, but it’s stored inuint32_t mic_freq. A negative Kconfig value will wrap. Use a signed temporary or add a Kconfig range/validation before casting touint32_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.
tore-espressif
left a comment
There was a problem hiding this comment.
@leeebo Thanks, LGTM!
Should also test on hardware? In case it is in a hurry, we can merge now
resolved #174
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_playerexample.Breaking Change
uac_host_dev_alt_param_t(public header) gains a new fielduint8_t subframe_sizeinserted betweenchannelsandbit_resolution, reflecting the UAC Type IbSubframeSizedescriptor field. Any code that initialises this struct with positional (non-designated) initialisers, or compares instances withmemcmp, 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 bybSubframeSizein the UAC Type I Format Type descriptor), the calculation underestimated the packet size and caused transfer errors.The fix reads
bSubframeSizefrom the descriptor into the newsubframe_sizefield and uses it in the packet size formula:sample_freq × channels × subframe_size.Example improvements (
audio_player)CONFIG_EXAMPLE_SPK_SAMPLE_FREQandCONFIG_EXAMPLE_MIC_SAMPLE_FREQKconfig options (default0= 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_tonenow usessubframe_sizefor frame-size calculation and PCM byte packing, supporting 24-bit-in-4-byte and other non-standard layouts.subframe_sizeinstead ofbit_resolution / 8for 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):
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.CONFIG_EXAMPLE_SPK_SAMPLE_FREQ=0(auto); driver selects 48000 Hz (device default), tone plays correctly.Checklist
Before submitting a Pull Request, please ensure the following: