fix: disable duplicate dynamic silence logic in DynamicStreamingVAD#3240
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates DynamicStreamingVAD.feed to pass silence_schedule to self.model.generate(). The reviewer identified a conflicting dual-implementation of dynamic silence thresholding where the model's internal logic silently overrides the user-configured thresholds in DynamicStreamingVAD. They suggested passing dynamic_silence=False to self.model.generate() to disable the redundant internal logic and allow DynamicStreamingVAD's implementation to manage the thresholding as designed.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
LauraGPT
left a comment
There was a problem hiding this comment.
Thanks for fixing the duplicate threshold controller. I confirmed on the real CPU FSMN-VAD that dynamic_silence=False prevents the model-level schedule from overwriting DynamicStreamingVAD after the cache exists: a custom 3000 ms schedule now remains at a 2850 ms counter threshold instead of being reset to 1850 ms.
There is still a first-call correctness gap that needs to be fixed before merge. _apply_dynamic_threshold() runs before self.model.generate(), so the first call has no cache["stats"] to update. With this patch disabling the model schedule, generate() initializes the first call with the model's default 800 ms end-silence setting, regardless of the wrapper's configured schedule. Because feed() explicitly accepts an arbitrary-length chunk and the model internally slices it, this makes segmentation depend on how the caller chunks identical audio.
Real-model reproduction at ad3f3e402, using the repository's runtime/funasr_api/asr_example.wav plus two seconds of silence and silence_schedule=[(inf, 10000)]:
- one
feed(full_audio): returns[[610, 5440]]; counter threshold is650(800 ms total); feed(first_60_ms)followed byfeed(rest): returns[]; counter threshold is9850(10000 ms total).
Please initialize the first model call with the wrapper's desired end-silence setting (for example through the existing max_end_silence_time initialization path, or an equivalent cache initialization) while keeping the model-level dynamic schedule disabled.
Please also add focused regression coverage for both parts of the contract:
- the wrapper's custom silence schedule and
speech_noise_thresare not overwritten by the model-level defaults; - identical audio produces the same result when supplied as one initial chunk or split after the first streaming chunk.
The current focused suite (tests/test_fsmn_vad_dynamic_silence.py plus tests/test_realtime_ws_service.py) passes 15 tests, but none exercises the DynamicStreamingVAD/model interaction changed by this PR.
Pass the wrapper silence and noise thresholds into the initial FSMN-VAD cache so first-call behavior does not depend on caller chunking. Add a regression that exercises the wrapper with the production cache initializer. Assisted-by: Codex:gpt-5.6
LauraGPT
left a comment
There was a problem hiding this comment.
Verified the first-call fix on head 92b749cdf.
- The initial FSMN-VAD cache now receives the wrapper-configured end-silence and
speech_noise_thresvalues before processing audio. - The new wrapper/cache regression failed on the previous head (
650 != 9850, and one-chunk[[0, 1000]]versus split[]) and passes after the fix. - The focused suite passes 17/17 tests; compile, targeted Ruff, and diff checks pass.
- A real CPU
fsmn-vadrun with the repository audio plus two seconds of silence produces identical one-chunk and 60 ms-split results ([]), with both caches at threshold9850and noise threshold0.73.
The requested threshold-preservation and chunking-invariance contract is covered.
Preserve the bounded streaming VAD buffer fix alongside the first-call dynamic threshold initialization from #3240. Assisted-by: Codex:gpt-5.6
Summary
Disable the model-level dynamic silence logic when
DynamicStreamingVADmanages the threshold through_apply_dynamic_threshold().This prevents
model.pyfrom overwriting the caller-configured VAD threshold on every streaming chunk.