TAI BUI
Back to curriculum
BuildPython

Voice Activity Detection & Turn-Taking — Silero, Cobra, and the Flush Trick

Every voice agent lives or dies on two decisions: is the user speaking right now, and are they actually done? VAD answers the first. Turn-detection (VAD plus a silence hangover plus a semantic endpoint model) answers the second. Get either one wrong and your assistant either cuts people off or never shuts up.

TIME: ~45 minutesPREREQUISITES: Phase 6 · 11 (Real-Time Audio), Phase 6 · 12 (Voice Assistant)

Learning Objectives

  • Name the three decisions a voice agent makes on every 20 ms chunk (is this frame speech, has the user started, has the user finished) and explain why naive energy-threshold VAD fails once real noise shows up.
  • Build and tune the three-tier VAD cascade (energy gate, Silero VAD, semantic turn detector) along with its four key parameters: threshold, minimum speech duration, silence hangover, and pre-roll buffer.
  • Implement a turn-detection state machine that turns raw VAD output into START and END events, and explain the Kyutai flush trick that collapses STT look-ahead delay down to about 125 ms.
  • Pick the right VAD and turn-detection strategy (Silero, Cobra, WebRTC, pyannote, or a layered combination) for a given deployment scenario, and avoid the pitfalls that most often break turn-taking in production.

The Problem

A voice agent makes three distinct decisions on every 20 ms chunk:

  1. Is this frame speech? That's VAD: binary, per-frame.
  2. Has the user started a new utterance? Onset detection.
  3. Has the user finished? End-pointing, also called turn-end.

A naive energy threshold fails the moment real noise shows up — traffic, keyboards, crowd babble. The 2026 answer stacks three things instead: Silero VAD (open, deep-learned), a turn-detection model for semantic endpointing, and a VAD-calibrated silence hangover.

Warm-up0/3
1. Why do real-time audio systems process sound in small fixed-size chunks instead of waiting for a complete recording?Warm-up
A waveform of speech that stops at a vertical line marked now, with a dashed empty region labelled not spoken yet after it. Short tick marks under the waveform mark equal pieces of 20 ms. A question mark asks when the computer can start working on the sound.
Schematic, not to scale. The waveform is typed, not recorded.
2. A detector flags events and can be wrong in two ways. What is a false positive?Warm-up
A grid of ten time slots. A top row has blue blocks where an event really happens, in slots 1 to 2, 5 to 6 and 9 to 10. A second row has orange blocks where the detector fired, in slots 1, 3 and 6. Red numbered circles 1, 2 and 3 label slots 3, 6 and 9. A question asks which red number is a false positive.
Typed illustration of one detector, not data from a real system.
3. What does the root-mean-square (RMS) of a chunk of audio samples measure?Warm-up
Eight vertical stems of a waveform on a centre line with values 0.10, -0.30, 0.20, 0.05, -0.20, 0.30, -0.10 and 0.00. A question asks for the RMS of the chunk.
Typed example values.
Check: The Problem0/3
1. What three decisions does a voice agent make on every short audio chunk?Define
A row of seven small chunk boxes with waveform snippets labelled 20 ms chunks, an arrow into a box labelled voice agent, and three arrows to three boxes labelled decision 1, decision 2 and decision 3, each with a question mark.
Schematic. The waveform snippets are typed.
2. What does a voice activity detector (VAD) output for each frame of audio?Define
Twelve bars for consecutive frames numbered 7 to 18. The first four bars are short and the remaining eight are tall. Under each bar is a dashed box with a question mark for the detector's output.
Levels captured from the lesson's synthetic stream (frames 7 to 18 of 151).
3. Why does a naive energy-threshold VAD fail once real noise shows up?Explain
A bar chart of level in dBFS over 24 frames. Quiet frames are very short, speaking frames are tall, traffic and crowd babble are medium and keyboard clicks are medium spikes between quiet frames. A legend names the five sources. A question asks for the energy VAD decision on each frame.
Illustrative levels, typed, not recorded.

The Concept

VAD cascade: energy → Silero → turn-detector → flush trick

The three-tier VAD cascade

Tier 1: energy gate. Cheapest. Threshold RMS at -40 dBFS. Filters obvious silence but fires on any noise above the threshold.

Tier 2: Silero VAD (2020-2026, MIT). 1M parameters. Trained on 6000+ languages. Runs in ~1 ms per 30 ms chunk on a single CPU thread. 87.7% TPR at 5% FPR. The open-source default.

Tier 3: semantic turn detector. LiveKit's turn-detection model (2024-2026) or your own small classifier. Distinguishes "pause mid-sentence" from "done talking." Uses linguistic context (intonation + recent words), not just silence.

Key parameters and their defaults

  • Threshold. Silero outputs a probability; classify speech at > 0.5 (default) or > 0.3 (sensitive). Lower threshold = fewer first-word clips, more false positives.
  • Minimum speech duration. Reject speech shorter than 250 ms (usually coughs or chair noise).
  • Silence hangover (end-pointing). After VAD returns to 0, wait 500-800 ms before declaring end-of-turn. Too short → interrupt user. Too long → feels sluggish.
  • Pre-roll buffer. Keep 300-500 ms of audio before VAD fires. Prevents "hey" being clipped.

The flush trick (Kyutai 2025)

Streaming STT models have a look-ahead delay (500 ms for Kyutai STT-1B, 2.5 s for STT-2.6B). Normally you'd sit through that whole delay after the user stops talking before a transcript shows up. The flush trick fixes that: the moment VAD fires end-of-speech, send a flush signal to the STT and force immediate output. STT processes at ~4× realtime, so the 500 ms buffer finishes in ~125 ms.

End-to-end: 125 ms VAD + flush STT = conversational latency.

2026 VAD comparison

VADTPR @ 5% FPRLatencyLicense
WebRTC VAD (Google, 2013)50.0%30 msBSD
Silero VAD (2020-2026)87.7%~1 msMIT
Cobra VAD (Picovoice)98.9%~1 mscommercial
pyannote segmentation95%~10 msMIT-ish

Silero is the right default. Cobra is the compliance / accuracy upgrade. Energy-only VAD has no place in 2026 production.

Check: The Concept0/17
1. What is turn detection, as distinct from plain VAD?Define
A time axis from 0 to 3.9 seconds. A waveform has speech from 0.3 to 1.4 s and from 2.0 to 3.0 s with flat lines elsewhere. A VAD row shows one over the two speech stretches and zero elsewhere. Below, a dashed box with a question mark is labelled turn detection.
Typed schematic: the waveform and timings are illustrative.
2. What is a silence hangover?Define
A time axis from 0 to 3 seconds with a waveform that speaks from 0.2 to 1.4 s and is flat afterwards. A VAD row is one over the speech and zero afterwards. A marker at 1.4 s is labelled VAD drops to 0 and a marker at 1.9 s is labelled END event, with a bracket and a question mark between them.
Typed schematic. The gap length is the lesson's 500 ms default, drawn to scale.
3. What does the tier-1 energy gate in the VAD cascade do?Define
Audio chunks go into a highlighted box tier 1 energy gate, then into a box tiers 2 and 3. A question mark under the energy gate asks what it does.
Schematic of the lesson's cascade. Only tier 1 is named.
4. What does the lesson give as Silero VAD's approximate latency and parameter count?Define
An audio chunk goes into a highlighted box Silero VAD on one CPU thread, then out to a box speech or not. Two dashed boxes below read parameters: question mark and time per chunk: question mark.
Schematic. The two values are left out.
5. What does a semantic endpoint model add that silence-based end-pointing cannot?Define
A waveform with a speech burst, a boxed stretch of flat silence, then another speech burst, with an arrow towards a box labelled semantic endpoint model. A question mark asks what the model adds.
Typed schematic, not recorded audio.
6. What does 'TPR at 5% FPR' measure when VADs are compared?Define
A plot with false positive rate along the bottom from 0 to 20 percent and true positive rate up the side from 0 to 100 percent. A dashed vertical line at 5 percent false positive rate carries a question mark. A note says every VAD in the lesson's table is read at that line.
Axes only. No curve is drawn.
7. What are the lesson's defaults for minimum speech duration and pre-roll buffer?Define
A waveform with a short orange cough burst, a flat gap, then a long blue speech stretch. A dashed marker labelled VAD fires sits inside the speech. A bracket with a question mark spans the cough and a second bracket with a question mark spans the time before the VAD marker.
Typed schematic, not to scale. Both durations are left out.
8. What problem does the Kyutai 'flush trick' solve?Define
A waveform that ends at a marker user stops talking, then flat. A later marker labelled transcript appears. A bracket between them is labelled gap: question mark.
Typed schematic. The gap is left unlabelled.
9. In the 2026 VAD comparison table, which VAD has the highest TPR at 5% FPR?Define
A four-row table listing WebRTC VAD, Silero VAD, Cobra VAD and pyannote segmentation, each with a dashed box containing a question mark in the TPR at 5 percent FPR column.
Names from the lesson's table. The values are hidden.
10. A VAD reports that the user has stopped making sound. Why is that alone a poor signal to hand the turn to the agent?Explain
A waveform of speech that stops at a vertical line, then is flat. A VAD row is one during the speech and zero afterwards. An arrow from the zero region points to a box asking agent: take the turn now, with a question mark.
Typed schematic, not recorded audio.
11. What is the trade-off of lowering the Silero speech threshold from 0.5 to 0.3?Explain
A number line from 0 to 1 with ticks at 0, 0.3, 0.5 and 1. The tick at 0.3 is labelled sensitive and the tick at 0.5 is labelled default. A note says a frame counts as speech when its probability is above the threshold.
Thresholds from the lesson.
12. Why does a voice agent keep a rolling pre-roll buffer of recent audio?Explain
A chain of boxes: mic, rolling buffer that always keeps the last N ms, VAD, and STT. A question mark asks why that buffer is kept.
Schematic of the lesson's pipeline.
13. Why can the flush trick turn a 500 ms look-ahead wait into about 125 ms?Explain
A millisecond axis from 0 to 500 after end of speech. A long bar shows 500 ms of audio in the look-ahead buffer. A marker at 0 shows the flush sent and a marker at 125 ms shows the transcript ready. A question asks why the wait shrinks.
Times from the lesson and the question; drawn to scale.
14. Why does the lesson make Silero VAD the default open choice over WebRTC VAD?Explain
A two-row table of WebRTC VAD (Google, 2013) and Silero VAD (2020-2026) with columns TPR at 5 percent FPR, latency and license. Every value cell is a dashed box with a question mark. A question asks why the lesson prefers Silero as the open default.
Names and years from the lesson. The values are hidden.
15. Assume the flush trick's 4x realtime rule holds. An STT with a 2.5 s look-ahead buffer is flushed at end-of-speech. About how long until the transcript is ready?Apply
A long bar labelled 2.5 s of audio in the look-ahead buffer with a marker at its start labelled flush sent. A note says the STT processes at 4x realtime. A question asks how long until the transcript is ready.
Setup from the question; bar not to scale against any other bar.
16. Silero returns a speech probability of 0.4 for a frame. How is it classified under the default threshold and the sensitive one?Apply
One frame goes into a Silero VAD box that outputs speech probability 0.4. Two arrows lead to a default threshold 0.5 box and a sensitive threshold 0.3 box. A note says a frame is speech when the probability is above the threshold and asks for the result at each.
Setup from the question.
17. VAD fires end-of-speech right when the user stops, but a Kyutai-style streaming STT still returns text about 500 ms later. What was left out?Analyze
Three rows on a time axis. The user waveform stops at a vertical line. The VAD row drops from one to zero there, with end-of-speech fired at that point. The STT row stays working until text arrives 500 ms later.
Typed schematic. Timings from the question.

Build It

Step 1: the energy gate

python
def energy_vad(chunk, threshold_dbfs=-40.0):
    rms = (sum(x * x for x in chunk) / len(chunk)) ** 0.5
    dbfs = 20.0 * math.log10(max(rms, 1e-10))
    return dbfs > threshold_dbfs

Step 2: Silero VAD in Python

python
from silero_vad import load_silero_vad, get_speech_timestamps
 
vad = load_silero_vad()
audio = torch.tensor(waveform_16k, dtype=torch.float32)
segments = get_speech_timestamps(
    audio, vad, sampling_rate=16000,
    threshold=0.5,
    min_speech_duration_ms=250,
    min_silence_duration_ms=500,
    speech_pad_ms=300,
)
for s in segments:
    print(f"{s['start']/16000:.2f}s - {s['end']/16000:.2f}s")

Step 3: turn-end state machine

python
class TurnDetector:
    def __init__(self, silence_hangover_ms=500, min_speech_ms=250):
        self.state = "idle"
        self.speech_ms = 0
        self.silence_ms = 0
        self.silence_hangover_ms = silence_hangover_ms
        self.min_speech_ms = min_speech_ms
 
    def update(self, is_speech, chunk_ms=20):
        if is_speech:
            self.speech_ms += chunk_ms
            self.silence_ms = 0
            if self.state == "idle" and self.speech_ms >= self.min_speech_ms:
                self.state = "speaking"
                return "START"
        else:
            self.silence_ms += chunk_ms
            if self.state == "speaking" and self.silence_ms >= self.silence_hangover_ms:
                self.state = "idle"
                self.speech_ms = 0
                return "END"
        return None

Step 4: the flush trick skeleton

python
def flush_on_end(stt_client, audio_buffer):
    stt_client.send_audio(audio_buffer)
    stt_client.send_flush()
    return stt_client.recv_transcript(timeout_ms=150)

STT providers like Kyutai, Deepgram, and AssemblyAI support flush; Whisper streaming doesn't, because it's block-based and always waits for full chunks.

Check: Build It0/8
1. Why does the TurnDetector require speech_ms to reach min_speech_ms before it emits START?Explain
Five 20 ms chunk bars, a tall red one in the middle between four short ones. Below, a box idle with an arrow to a box speaking labelled START, with a dashed box reading only when question mark.
Schematic. Chunk levels are typed.
2. You're debugging a TurnDetector: it never emits an END event even though the user clearly stopped talking two seconds ago. Looking at the state machine, what condition has to be true for END to fire?Apply
A note says the user stopped talking 2 seconds ago and no END event was emitted. A state diagram has an idle box and a speaking box, with a START arrow from idle to speaking and an END arrow back. A dashed box reads END fires when: question mark.
State names and variables from the lesson's Step 3.
3. In the lesson's Step 2 Silero VAD code, what does get_speech_timestamps return, and what units are start/end in?Apply
The call to get_speech_timestamps from the lesson's Step 2 with a 16000 sampling rate, threshold 0.5, minimum speech 250 ms, minimum silence 500 ms and speech pad 300 ms. Below, a dashed box reads segments equals question mark.
Code copied from the lesson. The loop that prints the results is left out.
4. A fresh TurnDetector uses its defaults (500 ms hangover, 250 ms minimum speech). It receives uninterrupted speech chunks of 20 ms. On which chunk does update first return START?Apply
The two default settings, 500 ms hangover and 250 ms minimum speech, then fifteen green boxes numbered 1 to 15, each one 20 ms chunk of speech. A question asks on which chunk update first returns START.
Setup from the question.
5. A TurnDetector with defaults is in the speaking state. The user is silent for 400 ms, speaks for one 20 ms chunk, then goes silent for good. When does END fire?Apply
A time bar: 400 ms of silence, then one 20 ms speech chunk, then silence from then on. A question asks when END fires.
Setup from the question; the time axis counts from the start of the 400 ms silence.
6. energy_vad is called with the default threshold on a chunk where every sample is 0.001. What does it return?Apply
Two lines: a chunk of 320 samples that are all 0.001, and a call to energy_vad with the default threshold of -40.0 dBFS. A dashed box reads returns question mark.
Setup from the question. The 320-sample length is 20 ms at 16 kHz.
7. In the Silero example, get_speech_timestamps returns a segment with start 24000 and end 40000 at 16 kHz. What does the loop print?Apply
A bar from sample index 24000 to 40000 marked speech on an index line, labelled start 24000 and end 40000, with a sampling rate of 16000. A dashed box reads the loop prints: question mark.
Setup from the question. The print statement is left out.
8. You are wiring the flush trick into a voice pipeline that uses Whisper streaming as its STT backend. What should you expect when VAD fires end-of-speech?Analyze
A pipeline mic, VAD, Whisper streaming, transcript. When end-of-speech fires, a dashed line leads to the Whisper streaming box, marking where a flush signal would be sent. A question asks what to expect.
Schematic of the planned wiring.

Use It

SituationVAD choice
Open, fast, generalSilero VAD
Commercial call centerCobra VAD
On-device (phone)Silero VAD ONNX
Research / diarizationpyannote segmentation
Zero-dependency fallbackWebRTC VAD (legacy)
Need turn-ending qualitySilero + LiveKit turn-detector layered

Rule of thumb: don't ship energy-only VAD unless you genuinely have no other option.

Check: Use It0/3
1. Per the lesson's Use It table, which VAD choice is recommended for a commercial call center?Apply
A card reading Commercial call center, a voice agent answering customer calls, with a dashed box VAD choice: question mark.
Scenario named in the question.
2. Per the lesson's Use It table, what's recommended for on-device (phone) deployment versus research or diarization work?Apply
Two cards. On-device (phone), runs on the handset itself, and Research / diarization, labelling who speaks when in recordings, each with a dashed box VAD choice: question mark.
Scenario names from the question.
3. You need an open-source voice agent that rarely cuts users off mid-thought, with no commercial license. Which stack fits best?Design
A requirements card: open source with no commercial license, and rarely cuts users off mid-thought. Below, a chain of boxes frame-level VAD, end-of-turn logic and agent, with question marks under the first two.
Setup from the question.

Pitfalls

  • Fixed threshold. Works in a quiet room, falls apart the moment real noise shows up. Calibrate it on-device, or just switch to Silero.
  • Too-short silence hangover. The agent interrupts mid-sentence. 500-800 ms is the sweet spot for conversational speech.
  • Too-long hangover. It feels sluggish. A/B test against real target users to find the line.
  • No pre-roll buffer. You lose the first 200-300 ms of user audio. Always keep a rolling pre-roll.
  • Ignoring semantic endpointing. "Hmm, let me think..." contains long pauses, and users hate being cut off mid-thought. Use LiveKit's turn-detector or something similar.
Check: Pitfalls0/5
1. A voice agent works well in the quiet office where it was tuned, but in a busy cafe it fires on keyboard clicks and chatter. Its VAD is an energy gate at -40 dBFS. What is the best fix?Analyze
Two bar panels with a dashed -40 dBFS line. In the quiet office the quiet bars are far below the line and three or four speech bars are above it. In the busy cafe every bar is above the line.
Bars typed for illustration, not measured.
2. Testers say the agent never hears the 'hey' that starts their sentences, though everything after it is transcribed. VAD and hangover behave correctly. Which missing piece is most likely?Analyze
Two lines. Said: hey, what is the weather today. Heard: the same without the first word hey. Below, three boxes: VAD fine, hangover fine, and a dashed box missing piece with a question mark.
Typed example matching the question's symptom.
3. Users who say 'Hmm, let me think...' keep getting cut off even with an 800 ms hangover, because their pauses run longer. Which change targets that cause?Analyze
A waveform for the words Hmm, let me think, then a flat pause bracketed as longer than 800 ms, then more speech. A marker END at 800 ms falls inside the pause.
Typed schematic. The pause length is illustrative; only 'longer than 800 ms' comes from the question.
4. A team ships a 500 ms hangover, sees users cut off, raises it to 800 ms, then hears the agent feels slow. What is the most sound next step?Analyze
A line for silence hangover in milliseconds from 0 to 1000. A dot at 500 ms is labelled users cut off and a dot at 800 ms is labelled agent feels slow. A question asks for the most sound next step.
Setup from the question.
5. You are building a fast back-and-forth voice game and a slower customer-support bot. How should end-of-turn tuning differ?Design
Two cards. Fast back-and-forth voice game, players trade quick lines, and Customer-support bot, answers callers' questions, each with a dashed box hangover: question mark.
Apps named in the question.

Ship It

Save it as outputs/skill-vad-tuner.md. Pick a VAD model, threshold, hangover, pre-roll, and turn-detection strategy for your workload.

Author's Note

The parameter that eats the most engineering time in practice isn't the VAD model, it's the silence hangover. Every team ships 500 ms first, watches testers get cut off mid-sentence, bumps it to 800 ms, then gets complaints that the agent feels slow to respond. There's no universal right answer here: a customer-support bot tolerates a slower turn far better than a fast back-and-forth voice app does. Tune it against your own call recordings, not a default someone posted in a GitHub issue.

Exercises

  1. Easy. Run code/main.py: it simulates a speech-silence-speech-coughs sequence and tests three VAD tiers.
  2. Medium. Install silero-vad, process a 5-minute recording, and tune the threshold to minimize both first-word clips and false triggers. Report precision and recall.
  3. Hard. Build a mini turn-detector: Silero VAD plus a 3-layer MLP over the last 10 words' embeddings (use sentence-transformers). Train it on a hand-labeled turn-end dataset. Beat Silero alone by 10% F1.

Key Terms

TermWhat people sayWhat it actually means
VADVoice detectorBinary per-frame: is this speech?
Turn detectionEnd-pointingVAD + silence-hangover + semantic endpoint.
Silence hangoverWait-after-speechTime to wait before declaring turn end; 500-800 ms.
Pre-rollPre-speech bufferKeep 300-500 ms audio before VAD fires.
Flush trickKyutai hackVAD → flush-STT → 125 ms instead of 500 ms delay.
Semantic endpoint"Did they mean to stop?"ML classifier that looks at words, not just silence.
TPR @ FPR 5%ROC pointStandard VAD benchmark; 87.7% for Silero, 50% WebRTC.

Further Reading

Code

Ships With