Skip to content

Commit ff69346

Browse files
committed
fix(uac): improve uac compatibility for full-speed device
1 parent a17ddc9 commit ff69346

File tree

3 files changed

+36
-9
lines changed

3 files changed

+36
-9
lines changed

host/class/uac/usb_host_uac/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
All notable changes to this component will be documented in this file.
44

5-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [1.3.3] - 2025-11-4
8+
9+
### Changed
10+
11+
- Fixed a playback stuttering issue when bInterval was not equal to 1 in the full-speed device audio endpoint descriptor, and forced bInterval = 1 to make it compatible with these non-standard devices.
612

713
## [1.3.2] - 2025-10-21
814

host/class/uac/usb_host_uac/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
## IDF Component Manager Manifest File
2-
version: "1.3.2"
2+
version: "1.3.3"
33
description: USB Host UAC driver
44
url: https://github.com/espressif/esp-usb/tree/master/host/class/uac/usb_host_uac
55
dependencies:

host/class/uac/usb_host_uac/uac_host.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "sdkconfig.h"
1717
#include "esp_log.h"
1818
#include "esp_check.h"
19+
#include "esp_memory_utils.h"
1920
#include "freertos/FreeRTOS.h"
2021
#include "freertos/task.h"
2122
#include "freertos/semphr.h"
@@ -739,6 +740,11 @@ static esp_err_t uac_host_interface_add(uac_device_t *uac_device, uint8_t iface_
739740

740741
usb_host_get_active_config_descriptor(uac_device->dev_hdl, &config_desc);
741742
UAC_GOTO_ON_FALSE(config_desc, ESP_ERR_INVALID_STATE, "No active configuration descriptor");
743+
// Query device speed once to decide whether to force bInterval for Full-Speed
744+
usb_device_info_t dev_info_local;
745+
ESP_RETURN_ON_ERROR(usb_host_device_info(uac_device->dev_hdl, &dev_info_local), TAG, "Failed to get device info");
746+
ESP_RETURN_ON_FALSE(dev_info_local.speed != USB_SPEED_LOW, ESP_ERR_NOT_SUPPORTED, TAG, "Low-Speed device not supported");
747+
const bool is_full_speed = (dev_info_local.speed == USB_SPEED_FULL);
742748
const size_t total_length = config_desc->wTotalLength;
743749
int iface_alt_offset = 0;
744750
int iface_alt_idx = 0;
@@ -803,6 +809,21 @@ static esp_err_t uac_host_interface_add(uac_device_t *uac_device, uint8_t iface_
803809
iface_alt->ep_addr = ep_desc->bEndpointAddress;
804810
iface_alt->ep_mps = ep_desc->wMaxPacketSize;
805811
iface_alt->ep_attr = ep_desc->bmAttributes;
812+
if (is_full_speed && ep_desc->bInterval != 1) {
813+
// Full-Speed isochronous endpoints must have bInterval = 1
814+
uint8_t *_bInterval = (uint8_t *) & (ep_desc->bInterval);
815+
// Check if we can modify the bInterval value
816+
if (esp_ptr_in_dram(_bInterval) || esp_ptr_in_diram_dram(_bInterval)
817+
#if CONFIG_SPIRAM
818+
|| esp_ptr_in_psram(_bInterval)
819+
#endif
820+
) {
821+
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);
822+
*_bInterval = 1;
823+
} else {
824+
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);
825+
}
826+
}
806827
iface_alt->interval = ep_desc->bInterval;
807828
uac_iface->dev_info.type = (ep_desc->bEndpointAddress & UAC_EP_DIR_IN) ? UAC_STREAM_RX : UAC_STREAM_TX;
808829
uac_ac_feature_unit_desc_t *feature_unit_desc = _uac_host_device_find_feature_unit((uint8_t *)uac_device->cs_ac_desc,
@@ -823,7 +844,7 @@ static esp_err_t uac_host_interface_add(uac_device_t *uac_device, uint8_t iface_
823844
ESP_LOGD(TAG, "UAC %s Feature Unit ID %d, Volume Ch Map %02X, Mute Ch Map %02X", uac_iface->dev_info.type == UAC_STREAM_RX ? "RX" : "TX",
824845
feature_unit_desc->bUnitID, iface_alt->vol_ch_map, iface_alt->mute_ch_map);
825846
}
826-
ESP_LOGD(TAG, "UAC Endpoint 0x%02X, Max Packet Size %d, Attributes 0x%02X, Interval %d", ep_desc->bEndpointAddress, ep_desc->wMaxPacketSize, ep_desc->bmAttributes, ep_desc->bInterval);
847+
ESP_LOGD(TAG, "UAC Endpoint 0x%02X, Max Packet Size %d, Attributes 0x%02X, Interval %d", USB_EP_DESC_GET_EP_NUM(ep_desc), ep_desc->wMaxPacketSize, ep_desc->bmAttributes, ep_desc->bInterval);
827848
break;
828849
}
829850
case UAC_CS_ENDPOINT: {
@@ -1305,9 +1326,9 @@ static esp_err_t uac_host_interface_suspend(uac_iface_t *iface)
13051326
memcpy(&uac_request, &usb_request, sizeof(usb_setup_packet_t));
13061327
esp_err_t ret = uac_cs_request_set(iface->parent, &uac_request);
13071328
if (ret != ESP_OK) {
1308-
ESP_LOGW(TAG, "Set Interface %d-%d Failed", iface->dev_info.iface_num, 0);
1329+
ESP_LOGW(TAG, "Suspend Interface %d-%d Failed", iface->dev_info.iface_num, 0);
13091330
} else {
1310-
ESP_LOGI(TAG, "Set Interface %d-%d", iface->dev_info.iface_num, 0);
1331+
ESP_LOGI(TAG, "Suspend Interface %d-%d", iface->dev_info.iface_num, 0);
13111332
}
13121333

13131334
uint8_t ep_addr = iface->iface_alt[iface->cur_alt].ep_addr;
@@ -1353,16 +1374,16 @@ static esp_err_t uac_host_interface_resume(uac_iface_t *iface)
13531374
uac_cs_request_t uac_request = {0};
13541375
memcpy(&uac_request, &usb_request, sizeof(usb_setup_packet_t));
13551376
UAC_RETURN_ON_ERROR(uac_cs_request_set(iface->parent, &uac_request), "Unable to set Interface alternate");
1356-
ESP_LOGI(TAG, "Set Interface %d-%d", iface->dev_info.iface_num, iface->cur_alt + 1);
1377+
ESP_LOGI(TAG, "Resume Interface %d-%d", iface->dev_info.iface_num, iface->cur_alt + 1);
13571378
// Set endpoint frequency control
13581379
if (iface->iface_alt[iface->cur_alt].freq_ctrl_supported) {
1359-
ESP_LOGI(TAG, "Set EP %02X frequency %"PRIu32, iface->iface_alt[iface->cur_alt].ep_addr, iface->iface_alt[iface->cur_alt].cur_sampling_freq);
1380+
ESP_LOGI(TAG, "Set EP %d frequency %"PRIu32, iface->iface_alt[iface->cur_alt].ep_addr & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK, iface->iface_alt[iface->cur_alt].cur_sampling_freq);
13601381
UAC_RETURN_ON_ERROR(uac_cs_request_set_ep_frequency(iface, iface->iface_alt[iface->cur_alt].ep_addr,
13611382
iface->iface_alt[iface->cur_alt].cur_sampling_freq), "Unable to set endpoint frequency");
13621383
}
13631384
// for RX, we just submit all the transfers
13641385
if (iface->dev_info.type == UAC_STREAM_RX) {
1365-
assert(iface->iface_alt[iface->cur_alt].ep_addr & 0x80);
1386+
assert(iface->iface_alt[iface->cur_alt].ep_addr & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK);
13661387
for (int i = 0; i < iface->xfer_num; i++) {
13671388
assert(iface->free_xfer_list[i]);
13681389
iface->free_xfer_list[i]->device_handle = iface->parent->dev_hdl;
@@ -1381,7 +1402,7 @@ static esp_err_t uac_host_interface_resume(uac_iface_t *iface)
13811402
UAC_RETURN_ON_ERROR(usb_host_transfer_submit(iface->xfer_list[i]), "Unable to submit RX transfer");
13821403
}
13831404
} else if (iface->dev_info.type == UAC_STREAM_TX) {
1384-
assert(!(iface->iface_alt[iface->cur_alt].ep_addr & 0x80));
1405+
assert(!(iface->iface_alt[iface->cur_alt].ep_addr & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK));
13851406
// for TX, we submit the first transfer with data 0 to make the speaker quiet
13861407
for (int i = 0; i < iface->xfer_num; i++) {
13871408
assert(iface->free_xfer_list[i]);

0 commit comments

Comments
 (0)