From 16491f7f708d0869fc2356f12172f0b5e3922d19 Mon Sep 17 00:00:00 2001 From: Benjamin Carlsson Date: Fri, 11 Sep 2026 21:59:37 +0000 Subject: [PATCH] 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 --- .../chatwidget/realtime/recording_controls.rs | 9 --------- .../realtime/recording_controls_tests.rs | 18 ++++++++++++++++-- ...s_do_not_sample_again_on_early_redraws.snap | 7 +++++-- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/codex-rs/tui/src/chatwidget/realtime/recording_controls.rs b/codex-rs/tui/src/chatwidget/realtime/recording_controls.rs index baccdeed88..595b5b77fa 100644 --- a/codex-rs/tui/src/chatwidget/realtime/recording_controls.rs +++ b/codex-rs/tui/src/chatwidget/realtime/recording_controls.rs @@ -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(); } diff --git a/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs b/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs index 5096465de2..b288ae1029 100644 --- a/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs +++ b/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs @@ -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); diff --git a/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_meters_do_not_sample_again_on_early_redraws.snap b/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_meters_do_not_sample_again_on_early_redraws.snap index c22ab37dd8..faf1c5f7f9 100644 --- a/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_meters_do_not_sample_again_on_early_redraws.snap +++ b/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_meters_do_not_sample_again_on_early_redraws.snap @@ -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 ▁▁▁▁▁▁