From 178426720cbe2f170872cc1469329570d37726a3 Mon Sep 17 00:00:00 2001 From: HiFiPHile Date: Thu, 27 Aug 2026 03:31:01 +0200 Subject: audio: normalize Feature Unit volume requests Accept the defined silence value and round ordinary volume requests to the nearest supported resolution step within the cached range. Add tests for silence, clamping, and step alignment. Signed-off-by: HiFiPHile --- src/class/audio/audio_host.c | 11 ++++++++++- src/class/audio/audio_host.h | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src/class/audio') diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c index ad2fd677f..c73e9f225 100644 --- a/src/class/audio/audio_host.c +++ b/src/class/audio/audio_host.c @@ -2592,7 +2592,16 @@ bool tuh_audio_volume_set(uint8_t idx, uint8_t stream_idx, int16_t volume, tuh_x uintptr_t user_data) { tuh_audio_volume_range_t range; TU_VERIFY(tuh_audio_volume_range_get(idx, stream_idx, &range), false); - TU_VERIFY(volume >= range.min && volume <= range.max, false); + if (volume != TUH_AUDIO_VOLUME_SILENCE) { + TU_VERIFY(volume >= range.min && volume <= range.max && range.res != 0, false); + const uint32_t offset = (uint32_t)((int32_t)volume - range.min); + const uint32_t steps = (offset + range.res / 2u) / range.res; + int32_t rounded = (int32_t)range.min + (int32_t)(steps * range.res); + if (rounded > range.max) { + rounded -= range.res; + } + volume = (int16_t)rounded; + } return tuh_audio_feature_unit_set(idx, stream_idx, AUDIO10_FU_CTRL_VOLUME, 0, (uint16_t)volume, complete_cb, user_data); } diff --git a/src/class/audio/audio_host.h b/src/class/audio/audio_host.h index 42cf4b4e5..4807d376a 100644 --- a/src/class/audio/audio_host.h +++ b/src/class/audio/audio_host.h @@ -241,7 +241,9 @@ bool tuh_audio_feature_unit_get(uint8_t idx, uint8_t stream_idx, uint8_t control uint16_t *value, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Master mute and volume controls. Capability and range information is cached -// before tuh_audio_mount_cb() is invoked. +// before tuh_audio_mount_cb() is invoked. Volume SET accepts +// TUH_AUDIO_VOLUME_SILENCE or a value within the cached range; finite values +// are rounded to the nearest resolution step measured from the range minimum. bool tuh_audio_mute_set(uint8_t idx, uint8_t stream_idx, bool mute, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool tuh_audio_mute_get(uint8_t idx, uint8_t stream_idx, bool *mute, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool tuh_audio_volume_set(uint8_t idx, uint8_t stream_idx, int16_t volume, tuh_xfer_cb_t complete_cb, -- cgit v1.3.1