How the server decides you stopped
Inbound audio is resampled to 16 kHz and fed to a voice activity detector in 512-sample frames. The detector emits two events, and both cross the socket:input_audio_buffer.speech_started— speech began. If a reply is playing, this is a barge-in.input_audio_buffer.speech_stopped— the silence after your speech got long enough to count as the end of a turn. The reply’s clock starts here.
Knobs you can turn
All four live undersession.audio.input.turn_detection and take effect on the
next frame:
Values you set are per session. The serving pipeline is pooled and reused, so
the server restores its own defaults when your session ends; the next caller
never inherits your barge-in sensitivity.
A pause is not always the end of a turn
An end-of-turn decision made from silence alone is wrong often enough to be noticeable, so the server does not commit to it immediately. A turn that ends softly stays reopenable for about a second. If you start speaking again inside that window and nothing has answered yet, the same turn is reopened and re-transcribed with the continuation attached, rather than becoming a second turn that contradicts the first. If no reply has committed the turn at all — the model is still thinking — the window stretches to about seven seconds, because the conversation has not moved on. A turn stops accumulating after 30 seconds of audio, at which point a new one starts; without that cap a slow first token would make a still-talking speaker re-transcribe a buffer that grows with every sentence. You do not configure this, and you cannot observe the reopen directly. What you see is the effect:conversation.item.input_audio_transcription.completed
arriving with the whole thought instead of the first half of it.
Barge-in
When the user speaks over a reply, the server cancels rather than finishing. In order:input_audio_buffer.speech_startedis sent.- Generation is cancelled — the language model and the synthesizer both abort mid-token, and audio already queued for you is dropped.
- The turn closes with
response.done,response.status: "cancelled"andstatus_details.reason: "turn_detected". - The pipeline is already transcribing the new utterance.
response.cancel does the same thing on your own initiative, closing the turn
with reason: "client_cancelled".
conversation.item.truncate is accepted and acknowledged with
conversation.item.truncated, but the server keeps no per-item audio history to
trim, so it changes nothing on this backend. Barge-in is already handled by the
path above. Send it if your client library does; do not rely on it to correct
the model’s context.What still goes wrong
Three failures are worth knowing before you hear one and conclude the model is bad.A thinking pause read as the end of a turn
A thinking pause read as the end of a turn
Somebody says “so the invoice number is…” and stops to look it up. The
reopen window covers a second of that, and
silence_duration_ms covers more
if you raise it, but a five-second hunt through a drawer will be answered.
If your users routinely pause to fetch information, raise
silence_duration_ms and tell the model in instructions to wait rather
than to fill silence.An interruption during the first token
An interruption during the first token
Cancellation is cooperative: a handler already blocked inside a network call
is closed rather than polled, but the very first moments of a turn are the
tightest race in the pipeline. Occasionally a syllable of the cancelled
reply reaches you. Dropping playback on
speech_started hides it; draining
your buffer does not.Recovery after a cut-off turn
Recovery after a cut-off turn
A cancelled turn is still a turn: it is in the conversation as the partial
thing the model said. If your agent tends to restart its whole answer after
an interruption, that is a prompt problem, not a protocol one — say in
instructions that it should answer the new question rather than resume
the sentence it was cut off in.Measure it instead of listening for it
Every session records what actually happened, so you can find a turn-taking bug in data rather than by ear. Per organization, the aggregate carries the distribution and the barge-in count. This one is always recorded, whatever your deployment does with audio:barge_in_count with a stable latency curve usually means the agent is
too verbose rather than too slow — see Latency.
Per turn, where the deployment retains session transcripts, each assistant
entry in a session’s transcript carries its own ttfb_ms and an
interrupted: true flag, so you can read which turn was cut off and what the
model had been asked to say in it:
transcript field comes back empty. The organization aggregate above is
unaffected.
Where a recording does exist it tells you the rest: the assistant track is cut
back to the wall-clock point playback reached, so what you hear is what the
caller heard, interruption included.
Next
Latency
Where the seconds go, and which of them you control.
Duet
Two live sessions, which is how you exercise all of this on purpose.
Realtime events
The event names above, in both directions.
Sessions
Transcripts, per-turn timing and recordings.