Skip to content

Commit

Permalink
fix(usb_host_uac): fix volume control logic
Browse files Browse the repository at this point in the history
  • Loading branch information
leeebo authored Oct 10, 2024
1 parent 88a7f84 commit 8b00abb
Show file tree
Hide file tree
Showing 6 changed files with 457 additions and 41 deletions.
16 changes: 16 additions & 0 deletions host/class/uac/usb_host_uac/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog for USB Host UAC

## 1.2.0 2024-09-27

### Breaking Changes:

1. Changed the parameter type of `uac_host_device_set_volume_db` from uint32_t to int16_t


### Improvements:

1. Support get current volume and mute status

### Bugfixes:

1. Fixed incorrect volume conversion. Using actual device volume range.
2. Fixed concurrency issues when suspend/stop during read/write

## 1.1.0

### Improvements
Expand Down
5 changes: 5 additions & 0 deletions host/class/uac/usb_host_uac/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ menu "USB Host UAC"
default 3
help
Number of Packets per UAC ISOC URB. It limits the minimum packets each transfer will send.
config UAC_RINGBUF_SAFE_DELETE_WAITING_MS
int "Ringbuf Safe Delete Waiting Time in ms"
default 50
help
Ringbuf Safe Delay Time in ms. It is used to wait for the ringbuf to be untouched before deleting it.
endmenu # "USB Host UAC"
2 changes: 1 addition & 1 deletion host/class/uac/usb_host_uac/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## IDF Component Manager Manifest File
version: "1.1.0"
version: "1.2.0"
description: USB Host UAC driver
url: https://github.com/espressif/esp-usb/tree/master/host/class/uac/usb_host_uac
dependencies:
Expand Down
51 changes: 46 additions & 5 deletions host/class/uac/usb_host_uac/include/usb/uac_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ esp_err_t uac_host_device_write(uac_host_device_handle_t uac_dev_handle, uint8_t

/**
* @brief Mute or un-mute the UAC device
* @param[in] iface Pointer to UAC interface structure
* @param[in] uac_dev_handle UAC device handle
* @param[in] mute True to mute, false to unmute
* @return esp_err_t
* - ESP_OK on success
Expand All @@ -392,9 +392,22 @@ esp_err_t uac_host_device_write(uac_host_device_handle_t uac_dev_handle, uint8_t
*/
esp_err_t uac_host_device_set_mute(uac_host_device_handle_t uac_dev_handle, bool mute);

/**
* @brief Get the mute status of the UAC device
* @param[in] uac_dev_handle UAC device handle
* @param[out] mute Pointer to store the mute status
* @return esp_err_t
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the device is not ready or active
* - ESP_ERR_INVALID_ARG if the device handle is invalid
* - ESP_ERR_NOT_SUPPORTED if the device does not support mute control
* - ESP_ERR_TIMEOUT if the control timed out
*/
esp_err_t uac_host_device_get_mute(uac_host_device_handle_t uac_dev_handle, bool *mute);

/**
* @brief Set the volume of the UAC device
* @param[in] iface Pointer to UAC interface structure
* @param[in] uac_dev_handle UAC device handle
* @param[in] volume Volume to set, 0-100
* @return esp_err_t
* - ESP_OK on success
Expand All @@ -405,18 +418,46 @@ esp_err_t uac_host_device_set_mute(uac_host_device_handle_t uac_dev_handle, bool
*/
esp_err_t uac_host_device_set_volume(uac_host_device_handle_t uac_dev_handle, uint8_t volume);

/**
* @brief Get the volume of the UAC device
* @param[in] uac_dev_handle UAC device handle
* @param[out] volume Pointer to store the volume, 0-100
* @return esp_err_t
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the device is not ready or active
* - ESP_ERR_INVALID_ARG if the device handle is invalid
* - ESP_ERR_NOT_SUPPORTED if the device does not support volume control
* - ESP_ERR_TIMEOUT if the control timed out
*/
esp_err_t uac_host_device_get_volume(uac_host_device_handle_t uac_dev_handle, uint8_t *volume);

/**
* @brief Set the volume of the UAC device in dB
* @param[in] iface Pointer to UAC interface structure
* @param[in] volume_db Volume to set, db
* @param[in] uac_dev_handle UAC device handle
* @param[in] volume_db Volume to set, with resolution of 1/256 dB,
* eg. 256 (0x0100) is 1 dB. 32767 (0x7FFF) is 127.996 dB. -32767 (0x8001) is -127.996 dB.
* @return esp_err_t
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the device is not ready or active
* - ESP_ERR_INVALID_ARG if the device handle is invalid
* - ESP_ERR_NOT_SUPPORTED if the device does not support volume control
* - ESP_ERR_TIMEOUT if the control timed out
*/
esp_err_t uac_host_device_set_volume_db(uac_host_device_handle_t uac_dev_handle, int16_t volume_db);

/**
* @brief Get the volume of the UAC device in dB
* @param[in] uac_dev_handle UAC device handle
* @param[out] volume_db Pointer to store the volume, with resolution of 1/256 dB,
* eg. 256 (0x0100) is 1 dB. 32767 (0x7FFF) is 127.996 dB. -32767 (0x8001) is -127.996 dB.
* @return esp_err_t
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if the device is not ready or active
* - ESP_ERR_INVALID_ARG if the device handle is invalid
* - ESP_ERR_NOT_SUPPORTED if the device does not support volume control
* - ESP_ERR_TIMEOUT if the control timed out
*/
esp_err_t uac_host_device_set_volume_db(uac_host_device_handle_t uac_dev_handle, uint32_t volume_db);
esp_err_t uac_host_device_get_volume_db(uac_host_device_handle_t uac_dev_handle, int16_t *volume_db);

#ifdef __cplusplus
}
Expand Down
52 changes: 40 additions & 12 deletions host/class/uac/usb_host_uac/test_app/main/test_host_uac.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,16 +618,29 @@ TEST_CASE("test uac tx writing", "[uac_host][tx]")
}
s_buffer += offset_size * freq_offsite_step;

// invalid operate
uint32_t volume = 10;
uint8_t volume = 0;
int16_t volume_db = 0;
uint8_t actual_volume = 0;
bool mute = false;
bool actual_mute = false;
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, uac_host_device_write(uac_device_handle, (uint8_t *)tx_buffer, tx_size, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_mute(uac_device_handle, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(uac_device_handle, volume));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_mute(uac_device_handle, mute));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_mute(uac_device_handle, &actual_mute));
TEST_ASSERT_EQUAL(mute, actual_mute);
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume_db(uac_device_handle, &volume_db));
printf("Initial Volume db: %.3f \n", (float)volume_db / 256.0);
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume_db(uac_device_handle, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume_db(uac_device_handle, &volume_db));
TEST_ASSERT_EQUAL(0, volume_db);

TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume(uac_device_handle, &actual_volume));
volume = actual_volume;
printf("Volume: %d \n", volume);
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_resume(uac_device_handle));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_write(uac_device_handle, (uint8_t *)tx_buffer, tx_size, 0));

// playback from volume 10 to 100
const uint32_t volume_max = 100;
uint8_t test_counter = 0;
const uint8_t test_counter_max = 15;
event_queue_t evt_queue = {0};
while (1) {
if (xQueueReceive(s_event_queue, &evt_queue, portMAX_DELAY)) {
Expand All @@ -638,9 +651,15 @@ TEST_CASE("test uac tx writing", "[uac_host][tx]")
case UAC_HOST_DEVICE_EVENT_TX_DONE:
if ((uint32_t)(s_buffer + offset_size) > (uint32_t)wav_file_end) {
s_buffer = (uint16_t *)(wav_file_start + 44);
volume += 20;
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(uac_device_handle, volume > 100 ? 100 : volume));
printf("Volume: %" PRIu32 "\n", volume > 100 ? 100 : volume);
volume += 10;
if (volume > 100) {
volume = 10;
}
test_counter++;
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(uac_device_handle, volume));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume(uac_device_handle, &actual_volume));
TEST_ASSERT_EQUAL(volume, actual_volume);
printf("Volume: %d \n", volume);
} else {
// fill the tx buffer with wav file data
tx_size = tx_buffer_threshold;
Expand Down Expand Up @@ -670,10 +689,10 @@ TEST_CASE("test uac tx writing", "[uac_host][tx]")
}
}
}
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_write(uac_device_handle, (uint8_t *)tx_buffer, tx_size, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_write(uac_device_handle, (uint8_t *)tx_buffer, tx_size, 1));
s_buffer += offset_size * freq_offsite_step;
}
if (volume > volume_max) {
if (test_counter > test_counter_max) {
goto exit_tx;
}
break;
Expand Down Expand Up @@ -730,9 +749,15 @@ TEST_CASE("test uac tx rx loopback", "[uac_host][tx][rx]")
.flags = FLAG_STREAM_SUSPEND_AFTER_START,
};

uint8_t actual_volume = 0;
bool actual_mute = 0;
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_start(mic_device_handle, &stream_config));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_mute(mic_device_handle, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_mute(mic_device_handle, &actual_mute));
TEST_ASSERT_EQUAL(0, actual_mute);
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(mic_device_handle, 80));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume(mic_device_handle, &actual_volume));
TEST_ASSERT_EQUAL(80, actual_volume);

uac_host_dev_alt_param_t spk_alt_params;
TEST_ASSERT_EQUAL(ESP_OK, uac_host_get_device_alt_param(spk_device_handle, 1, &spk_alt_params));
Expand All @@ -752,7 +777,11 @@ TEST_CASE("test uac tx rx loopback", "[uac_host][tx][rx]")

TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_start(spk_device_handle, &stream_config));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_mute(spk_device_handle, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_mute(spk_device_handle, &actual_mute));
TEST_ASSERT_EQUAL(0, actual_mute);
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(spk_device_handle, 80));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_get_volume(spk_device_handle, &actual_volume));
TEST_ASSERT_EQUAL(80, actual_volume);

uint8_t *rx_buffer = (uint8_t *)calloc(1, rx_buffer_threshold);
uint8_t *rx_buffer_stereo = NULL;
Expand Down Expand Up @@ -881,7 +910,6 @@ TEST_CASE("test uac tx rx loopback with disconnect", "[uac_host][tx][rx][hot-plu
.sample_freq = mic_alt_params.sample_freq[0],
.flags = FLAG_STREAM_SUSPEND_AFTER_START,
};

TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_start(mic_device_handle, &stream_config));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_mute(mic_device_handle, 0));
TEST_ASSERT_EQUAL(ESP_OK, uac_host_device_set_volume(mic_device_handle, 80));
Expand Down
Loading

0 comments on commit 8b00abb

Please sign in to comment.