Skip to content

Conversation

@TDA-2030
Copy link
Collaborator

@TDA-2030 TDA-2030 commented Nov 4, 2025

Description

UAC

  • Fixed a playback stuttering issue when bInterval was not equal to 1 in the full-speed device audio endpoint descriptor

UVC

  • Added SOI check to prevent output of corrupted MJPEG frames
  • Moved usb_types_uvc.h to private_include directory

Related

Testing


Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • 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.

Note

Fix UAC FS isochronous interval handling and harden UVC streaming with header/SOI validation; add an audio player example; bump UAC to 1.3.3 and UVC to 2.3.2.

  • UAC (usb_host_uac)

    • Fix/Compat: Force bInterval = 1 on Full-Speed isoch endpoints during descriptor parse to prevent playback stutter; reject Low-Speed.
    • API/Logs: Clearer Suspend/Resume logs; endpoint logs use USB_EP_DESC_GET_EP_NUM; direction asserts use USB masks.
    • Examples: New examples/audio_player (embedded WAV playback, optional MIC loopback) with build files, Kconfig, and configs.
    • Release: Bump to 1.3.3; update CHANGELOG.md.
  • UVC (usb_host_uvc)

    • Robustness: Add uvc_frame_payload_header_validate() and MJPEG SOI checks; improve BULK EoF handling; validate headers in ISOC; skip tiny/invalid frames; warn on missed EoF.
    • Refactor: Move usb_types_uvc.h to private_include; update includes across sources and tests.
    • Examples: Enhance basic stream example with driver event callback and FPS macro; tidy sdkconfig (per-target defaults).
    • Release: Bump to 2.3.2; update CHANGELOG.md.

Written by Cursor Bugbot for commit fd1c730. This will update automatically on new commits. Configure here.

cursor[bot]

This comment was marked as outdated.

@TDA-2030 TDA-2030 force-pushed the fix/improve_uac_compatibility_and_add_checks_for_uvc branch 2 times, most recently from ae92d53 to efa0fe5 Compare November 4, 2025 08:10
cursor[bot]

This comment was marked as outdated.

@TDA-2030 TDA-2030 force-pushed the fix/improve_uac_compatibility_and_add_checks_for_uvc branch 2 times, most recently from 016831a to 4ef3e94 Compare November 4, 2025 10:05
@TDA-2030 TDA-2030 changed the title Fix/improve uac compatibility and add checks for uvc fix(uvc): improve uac compatibility and add checks for uvc Nov 5, 2025
@TDA-2030 TDA-2030 force-pushed the fix/improve_uac_compatibility_and_add_checks_for_uvc branch 2 times, most recently from fae33ed to 389afe6 Compare November 6, 2025 11:39
@TDA-2030 TDA-2030 force-pushed the fix/improve_uac_compatibility_and_add_checks_for_uvc branch from 389afe6 to fd1c730 Compare November 7, 2025 02:14
Copy link
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.

@TDA-2030 UAC changes look OK. Could you please provide more information about the bInterval!=1 issue? Maybe there is a better way to fix it.

I have more comments for the UVC part, so if you want to speed up the release, please split this PR into 2. One for UAC and one for UVC, thanks!

@@ -0,0 +1,12 @@
| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 |
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should work also on H4

| Supported Targets | ESP32-S2 | ESP32-S3 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |

# UVC driver example: Video stream
Copy link
Collaborator

Choose a reason for hiding this comment

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

Outdated description.

It would be nice to provide a simple 'how-to' use this example

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines +812 to +826
if (is_full_speed && ep_desc->bInterval != 1) {
// Full-Speed isochronous endpoints must have bInterval = 1
uint8_t *_bInterval = (uint8_t *) & (ep_desc->bInterval);
// Check if we can modify the bInterval value
if (esp_ptr_in_dram(_bInterval) || esp_ptr_in_diram_dram(_bInterval)
#if CONFIG_SPIRAM
|| esp_ptr_in_psram(_bInterval)
#endif
) {
ESP_LOGW(TAG, "UAC Full-Speed device, Endpoint %d, bInterval %d, set to 1", USB_EP_DESC_GET_EP_NUM(ep_desc), ep_desc->bInterval);
*_bInterval = 1;
} else {
ESP_LOGW(TAG, "UAC Full-Speed device, Endpoint %d, bInterval %d, can't set to 1", USB_EP_DESC_GET_EP_NUM(ep_desc), ep_desc->bInterval);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a very risky, non-standard way that deserves explanation comment.

BTW, have you found the underlaying problem? If the device needs bInterval=2 why doesn't it work correctly with 2ms polling?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this operation is risky. I suspect the reason is that the camera descriptor was not modified for full-speed, while in high-speed, bInterval=4 is exactly a 1ms interval.

case UAC_HOST_DEVICE_EVENT_RX_DONE:
if (s_mic_dev_handle && s_mic_record_buf && s_mic_recording) {
uint32_t rx_size = 0;
esp_err_t ret = ESP_OK;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here is a build warning (treated as an error in CI)

esp-usb/host/class/uac/usb_host_uac/examples/audio_player/main/main.c:414:35: warning: unused variable 'ret' [-Wunused-variable]
  414 |                         esp_err_t ret = ESP_OK;
      |                                   ^~~

bool "Playback audio from microphone"
default n
help
Enabled this to playback audio from microphone
Copy link
Collaborator

Choose a reason for hiding this comment

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

Typo:

Suggested change
Enabled this to playback audio from microphone
Enable this to playback audio from microphone

CONFIG_ESP32P4_REV_MIN_0=y
CONFIG_RTC_CLK_SRC_EXT_CRYS=y
CONFIG_RTC_CLK_CAL_CYCLES=1024
CONFIG_SPIRAM=y
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we leave this config in the sdkconfig.defaults ? It's shared for all the targets.

// Check for start of new frame
const uvc_payload_header_t *payload_header = (const uvc_payload_header_t *)payload;
if (!uvc_frame_payload_header_validate(payload_header, isoc_desc->actual_num_bytes)) {
ESP_LOGD(TAG, "invalid UVC payload header, %02x, %02x, len:%d", payload[0], payload[1], transfer->actual_num_bytes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be isoc_desc ? Since you are processing individual isoc packets instead of the whole transfer.

Suggested change
ESP_LOGD(TAG, "invalid UVC payload header, %02x, %02x, len:%d", payload[0], payload[1], transfer->actual_num_bytes);
ESP_LOGD(TAG, "invalid UVC payload header, %02x, %02x, len:%d", payload[0], payload[1], isoc_desc->actual_num_bytes);

// Query device speed once to decide whether to force bInterval for Full-Speed
usb_device_info_t dev_info_local;
ESP_RETURN_ON_ERROR(usb_host_device_info(uac_device->dev_hdl, &dev_info_local), TAG, "Failed to get device info");
ESP_RETURN_ON_FALSE(dev_info_local.speed != USB_SPEED_LOW, ESP_ERR_NOT_SUPPORTED, TAG, "Low-Speed device not supported");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like this is valid point. You allocate memory for uac_iface in the beginning of the function. If the device is LS, the function just returns with an error code, leaving the memory allocated.

You could use one of the ESP_GOTO_ macros, to jump to fail: lablel and free the allocated memory.

get_wav_data(iface_alt_params.sample_freq[0], &player_config.pcm_ptr, &player_config.pcm_size,
&stm_config.sample_freq, &stm_config.channels, &stm_config.bit_resolution);

ESP_LOGI(TAG, "Start UAC speaker with %"PRIu32" Hz, %u bits, %s (PCM bytes=%u)",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just tired running the example with some UAC device.
My uac device has a sample rate of 48000, whereas this example only supports 8000 and 16000.

The get_wav_data returned error in this case, yet still the code continued and tired to start the device (even though the device is not supported) by this example.

I (753) usb_audio_player: UAC Device connected: SPK
find UAC 1.0 Speaker device
interface number: 1
total alt interfaces number: 1
--------alt interface[1]--------- 
channels = 2 
bit_resolution = 16 
sample_freq: 
	48000
	44100
E (763) usb_audio_player: Unsupported sample rate: 48000
I (768) usb_audio_player: Start UAC speaker with 0 Hz, 0 bits, Stereo (PCM bytes=0)
E (775) uac-host: uac_host_device_start(2289): Invalid bit resolution
ESP_ERROR_CHECK failed: esp_err_t 0x102 (ESP_ERR_INVALID_ARG) at 0x4000a402
--- 0x4000a402: uac_lib_task at /home/peter/esp/esp-usb/host/class/uac/usb_host_uac/examples/audio_player/main/main.c:346

And the esp kept resetting. I think the examples should be build in a way, that they crash only when some serious issue happens, not when you insert "unsupported device".

I think adding more wav files with different sample rate is not necessary here. The example could have shown something like: W usb_audio_player: Unsupported device, try different device or something similar.

#include "usb/uac_host.h"
#include <string.h>
#include <stdlib.h>

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to emphasize, that some configs are used in the code.

Suggested change
#include "sdkconfig.h"

#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_memory_utils.h"
Copy link
Collaborator

Choose a reason for hiding this comment

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

To pass the linux host test, this head should be closed in

#if !CONFIG_IDF_TARGET_LINUX
"esp_memory_utils.h"
#endif

As well as all the functions from the esp_memory_utils.h used in this file. Because the esp_memory_utils.h includes soc.h which is pretty shallow for linux target.

Or update the esp-idf/components/soc/linux/include/soc/soc.h with missing defines. But tis might not be an ideal solution.

@TDA-2030
Copy link
Collaborator Author

TDA-2030 commented Nov 26, 2025

@tore-espressif

@TDA-2030 UAC changes look OK. Could you please provide more information about the bInterval!=1 issue? Maybe there is a better way to fix it.

A customer's camera has a UAC descriptor with bInterval=4, which would mean sending data every 8 frames. However, it should actually send data every frame for proper audio playback. I limited the camera to full-speed and connected it to my computer, then used a tool to capture USB frames. I found that the computer also ignored bInterval=4 and sent data every 1ms.

I have more comments for the UVC part, so if you want to speed up the release, please split this PR into 2. One for UAC and one for UVC, thanks!

I will split this PR into 2

@TDA-2030 TDA-2030 closed this Nov 26, 2025
@TDA-2030 TDA-2030 deleted the fix/improve_uac_compatibility_and_add_checks_for_uvc branch November 26, 2025 04:31
@TDA-2030
Copy link
Collaborator Author

This PR has been split into #339 and #340

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.

4 participants