Preserve voice meter history through quiet samples (#44928)

## Why

A quiet sample cleared all earlier activity from that channel's voice meter, making recent speech disappear immediately.

## What changed

Let quiet samples scroll into the microphone and speaker meter history so earlier activity remains visible until it ages out.

## Testing

Update history assertions and the meter snapshot to cover quiet samples on each channel and the eventual return to silence after a full history window.

GitOrigin-RevId: 834157df28c9d2cfbe9fa17bbfaf32b81313a295
This commit is contained in:
Benjamin Carlsson
2026-09-11 22:17:40 +00:00
committed by copyberry
parent 1b5e27c7f0
commit 16491f7f70
3 changed files with 21 additions and 13 deletions
@@ -222,15 +222,6 @@ impl ChatWidget {
.audio_meter_history
.iter()
.any(|(microphone, speaker)| *microphone > 0 || *speaker > 0);
// Release a quiet channel instead of waiting for old peaks to scroll out.
for (microphone, speaker) in &mut self.realtime_conversation.audio_meter_history {
if microphone_intensity == 0 {
*microphone = 0;
}
if speaker_intensity == 0 {
*speaker = 0;
}
}
if self.realtime_conversation.audio_meter_history.len() >= MAX_REALTIME_AUDIO_METER_FRAMES {
self.realtime_conversation.audio_meter_history.pop_front();
}
@@ -266,7 +266,7 @@ async fn voice_meters_do_not_sample_again_on_early_redraws() {
(119, 255)
])
);
// Each channel settles on its first quiet sample, without clearing the other one.
// Quiet samples scroll into each channel without erasing earlier speech.
for (elapsed_ms, peaks) in [(700, (0, 8192)), (800, (8192, 0))] {
chat.refresh_realtime_audio_meters(
now + std::time::Duration::from_millis(elapsed_ms),
@@ -274,6 +274,20 @@ async fn voice_meters_do_not_sample_again_on_early_redraws() {
);
meters.push(render_meter(&chat, /*width*/ 80));
}
for frame in 0..super::super::MAX_REALTIME_AUDIO_METER_FRAMES {
chat.refresh_realtime_audio_meters(
now + std::time::Duration::from_millis(900 + frame as u64 * 100),
|| (0, 0),
);
if frame == 0 {
meters.push(render_meter(&chat, /*width*/ 80));
}
}
assert_eq!(
chat.realtime_conversation.audio_meter_history,
std::collections::VecDeque::from([(0, 0); super::super::MAX_REALTIME_AUDIO_METER_FRAMES])
);
meters.push(render_meter(&chat, /*width*/ 80));
insta::assert_snapshot!(meters.join("\n"));
}
@@ -287,7 +301,7 @@ async fn voice_meters_preserve_silence_and_restart_sampling_after_reset() {
chat.refresh_realtime_audio_meters(now + std::time::Duration::from_secs(1), || (0, 0));
assert_eq!(
chat.realtime_conversation.audio_meter_history,
std::collections::VecDeque::from([(0, 0), (0, 0)])
std::collections::VecDeque::from([(255, 119), (0, 0)])
);
chat.reset_realtime_conversation();
activate_voice(&mut chat);
@@ -1,8 +1,11 @@
---
source: tui/src/chatwidget/realtime/recording_controls_tests.rs
assertion_line: 291
expression: "meters.join(\"\\n\")"
---
mic ██████ codex ▅▅▅▅▅▅
mic ██████ codex ▅▅▅▅▅▅
mic ▁▁▁▁▁▁ codex ▅▅▅▅██
mic ▁▁▁▁▁█ codex ▁▁▁▁▁▁
mic ████▅▁ codex ▅▅▅▅██
mic ███▅▁█ codex ▅▅▅██▁
mic ██▅▁█▁ codex ▅▅██▁▁
mic ▁▁▁▁▁▁ codex ▁▁▁▁▁▁