Skip to content

feat(eot): allow configurable min_silence_duration for turn detectors (#7188) - #7252

Open
rrfunde wants to merge 7 commits into
livekit:mainfrom
rrfunde:fix/turn-detector-min-silence-duration
Open

feat(eot): allow configurable min_silence_duration for turn detectors (#7188)#7252
rrfunde wants to merge 7 commits into
livekit:mainfrom
rrfunde:fix/turn-detector-min-silence-duration

Conversation

@rrfunde

@rrfunde rrfunde commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Fixes #7188

Summary

Allows turn detectors to expose a configurable min_silence_duration rather than enforcing a global 200ms minimum (+50ms buffer). This allows custom or local turn detection models to operate with their intended lower VAD silence windows without raising spurious validation errors.

Changes

  • Added min_silence_duration parameter to TurnDetectorOptions, _BaseStreamingTurnDetector, and TurnDetector, defaulting to MIN_SILENCE_DURATION_MS / 1000 (0.2s).
  • Exposed min_silence_duration on _BaseStreamingTurnDetectorStream.
  • In AudioRecognition._check_vad_silence_requirement(), query detector.min_silence_duration (falling back to MIN_SILENCE_DURATION_MS / 1000 when unset) and remove the arbitrary + 50ms buffer.
  • Added unit test in tests/test_audio_recognition_turn_detection.py verifying custom turn detector minimum silence validation.

…livekit#7188)

Support exposing and configuring min_silence_duration on turn detectors and remove hardcoded +50ms buffer in AudioRecognition._check_vad_silence_requirement.
@rrfunde
rrfunde requested a review from a team as a code owner September 12, 2026 11:35
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-13T04:20:40.492496Z ebdf8d9 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

devin-ai-integration[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e18841348

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +894 to +899
detector_min_silence = getattr(detector, "min_silence_duration", None)
required = (
detector_min_silence
if detector_min_silence is not None
else MIN_SILENCE_DURATION_MS / 1000
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Apply the configurable silence threshold when starting inference

When min_silence_duration is configured below 0.2 seconds, this validation now accepts a matching low-latency VAD, but _on_vad_event still starts predictions only after the hard-coded MIN_SILENCE_DURATION_MS / 1000 threshold at line 1427. The VAD can therefore emit END_OF_SPEECH before any prediction is requested, causing _run_eou_detection to see no future and skip the turn detector entirely; values above 0.2 seconds conversely start inference before the detector's declared minimum. Use the detector/stream's configured threshold for the inference trigger as well.

Useful? React with 👍 / 👎.

@rrfunde

rrfunde commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback:

  • _on_vad_event() in AudioRecognition now uses the resolved min_silence_duration from the active turn detector or stream (falling back to 200ms default if unset), rather than the hardcoded 200ms threshold, when starting turn-detector prediction.
  • Added unit test in tests/test_audio_recognition_turn_detection.py verifying that _on_vad_event() starts prediction at the configured min_silence_duration threshold.

devin-ai-integration[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6e7a79a6ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +908 to +910
float(detector_min_silence)
if detector_min_silence is not None
else MIN_SILENCE_DURATION_MS / 1000

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep VAD silence above the inference threshold

When the VAD's min_silence_duration exactly equals the detector minimum, this validation now accepts the pairing, but the built-in and Silero VAD loops emit INFERENCE_DONE with the previous silence accumulator before incrementing it and possibly emitting END_OF_SPEECH (inference/vad.py:403-459 and plugins/silero/vad.py:495-552). For example, with 32 ms windows and both values set to 0.2 s, the last inference event reports 0.192 s, then the VAD increments to 0.224 s and ends speech, so predict() is never called and the turn commits without the detector. Fresh evidence after the prior trigger fix is this pre-increment event ordering; either require enough VAD headroom for another update or start a missing prediction at end-of-speech.

Useful? React with 👍 / 👎.

devin-ai-integration[bot]

This comment was marked as resolved.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4eb19c366d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1475 to +1479
self._turn_detector_stream is not None
and self._turn_detector_prediction_fut is None
):
self._turn_detector_prediction_fut = (
self._turn_detector_stream.predict()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip inference for an EOS received after turn commit

When endpointing commits before the VAD emits its delayed END_OF_SPEECH—for example, a 50 ms detector threshold with a 500 ms VAD threshold—the commit flushes the stream and clears _turn_detector_prediction_fut, so this block starts a second inference for the already-completed turn. With STT, _run_eou_detection then returns because the transcript was cleared, leaving an unnecessary cloud/local request pending until the next speech; the preceding vad_speech_started value already distinguishes this documented late-EOS path, so the replacement prediction should only be started for an active speech segment.

Useful? React with 👍 / 👎.

@rrfunde

rrfunde commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Fixed: Added fallback prediction trigger in END_OF_SPEECH when _turn_detector_prediction_fut has not started yet, ensuring turns with equal VAD and turn detector silence durations do not skip end-of-turn detection due to VAD pre-increment timing.

@rrfunde

rrfunde commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback: gated the fallback prediction trigger at END_OF_SPEECH on vad_speech_started, preventing redundant inference predictions when endpointing has already committed the turn before delayed VAD EOS arrives.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 474666dd05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1440 to +1441
ev.raw_accumulated_silence >= self._turn_detector_min_silence_duration
and self._speaking

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject non-positive silence thresholds

When TurnDetector(min_silence_duration=0) (or a negative value) is used, every speech-bearing INFERENCE_DONE event satisfies this comparison because its accumulated silence is zero. The preceding block then cancels the current prediction and this block immediately starts another one on every VAD window, potentially issuing dozens of cloud inference requests per second while the user is speaking and preventing a stable prediction from completing. Validate that the new option is strictly positive, or require actual accumulated silence before calling predict().

Useful? React with 👍 / 👎.

@rrfunde

rrfunde commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback:

  1. Validated that min_silence_duration must be strictly positive (> 0) across TurnDetector, _BaseStreamingTurnDetector, TurnDetectorOptions, and AudioRecognition._check_vad_silence_requirement, raising a ValueError if <= 0.
  2. Required actual positive accumulated silence (ev.raw_accumulated_silence > 0) before triggering turn-detector predictions on INFERENCE_DONE.
  3. Added unit tests for rejecting non-positive silence thresholds and verifying that 0 raw accumulated silence does not trigger predictions.

devin-ai-integration[bot]

This comment was marked as resolved.

@rrfunde

rrfunde commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback:

  • Enforced math.isfinite(min_silence_duration) and min_silence_duration > 0 across TurnDetectorOptions, _BaseStreamingTurnDetector, TurnDetector, and AudioRecognition._check_vad_silence_requirement to prevent NaN values from bypassing validation.
  • Updated AudioRecognition._turn_detector_min_silence_duration to consult _turn_detector_stream.min_silence_duration whenever the detector object does not provide a value.
  • Added unit tests for NaN threshold rejection and stream silence duration fallback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebdf8d9b25

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +915 to +916
else:
required = MIN_SILENCE_DURATION_MS / 1000

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate stream-only silence thresholds against the VAD

When a custom streaming detector exposes min_silence_duration only on its returned stream—a case _turn_detector_min_silence_duration explicitly supports—this fallback still validates against 0.2 seconds. _start() calls _update_vad() before adopting or creating the stream, so a VAD configured for 0.1 seconds is incorrectly rejected even if the stream requires only 0.08 seconds. Validation should use the candidate stream's threshold once available or occur after the stream is adopted.

Useful? React with 👍 / 👎.

local_fallback: bool = True,
http_session: aiohttp.ClientSession | None = None,
conn_options: APIConnectOptions = DEFAULT_API_CONNECT_OPTIONS,
min_silence_duration: float = MIN_SILENCE_DURATION_MS / 1000,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Record the new silence threshold in session reports

When callers set this new behavior-affecting option, TurnDetector.describe_options() still reports only the model, provider, sample rate, fallback mode, and threshold overrides. Consequently, sessions that use different min_silence_duration values are indistinguishable in the uploaded session configuration, making latency or turn-detection experiments difficult to attribute and reproduce; include the resolved value in describe_options().

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configurable min_silence_duration for turn detectors

1 participant