Summary
TranscriptionSynchronizer should settle a zero-duration segment by sending its text through the normal transcription output without audio pacing.
Problem
In @livekit/agents 1.6.3, SegmentSynchronizerImpl waits for onPlaybackStarted before it releases the first text segment. This behavior blocks a segment when TTS returns non-empty text but pushes zero audio frames.
For this segment shape:
- Text input ends.
- Audio input ends.
- Pushed audio duration is zero.
SyncedAudioOutput.captureFrame does not run.
onPlaybackStarted does not occur.
- The segment does not receive the normal playback-finished or playout-drift settlement path.
As a result, the text is withheld from the transient lk.transcription stream. A later audible reply can recover the stream, but the zero-duration reply never receives live transcription.
Required behavior
When a segment has ended text input and audio input, and its pushed audio duration is zero, TranscriptionSynchronizer should settle that segment immediately and flush its text unsynchronized. It must not wait for a playback start that cannot occur.
This path should preserve normal paced delivery for segments that contain audio.
Rationale
A non-empty agent reply can remain available through application conversation-item events and chat context, but consumers of the lk.transcription stream still miss the live transcript for the affected reply. Local application-side re-emission is unsafe because it can duplicate text when timing races resolve normally. The synchronizer owns the segment state and can determine zero duration without a race.
Affected area
@livekit/agents
- Voice transcription synchronization
SegmentSynchronizerImpl
TranscriptionSynchronizer / SyncedAudioOutput segment lifecycle
Reproduction
- Enable synchronized transcription.
- Generate a reply with non-empty text.
- Make TTS complete without producing audio frames.
- Observe that the segment has no playback start.
- Observe that its text does not arrive on
lk.transcription.
- Generate a later reply with audio frames.
- Observe that the later reply can deliver transcription.
Acceptance criteria
- A segment with completed text, completed audio, and zero pushed audio duration flushes its complete text unsynchronized.
- The segment does not wait for
onPlaybackStarted.
- A zero-duration segment does not block transcription delivery for subsequent audible segments.
- Segments with one or more audio frames retain existing paced transcription behavior.
- Add regression coverage for non-empty text with zero TTS audio frames.
Local context
Quippy added synchronized transcription pacing in PR #79. Its integration test currently verifies that a zero-frame reply does not wedge the next audible reply. The application does not add a local raw-output fallback because the SDK has the authoritative segment state and a watchdog could double-deliver text.
Requested by @jonathanli12.
Backlinks:
Summary
TranscriptionSynchronizershould settle a zero-duration segment by sending its text through the normal transcription output without audio pacing.Problem
In
@livekit/agents1.6.3,SegmentSynchronizerImplwaits foronPlaybackStartedbefore it releases the first text segment. This behavior blocks a segment when TTS returns non-empty text but pushes zero audio frames.For this segment shape:
SyncedAudioOutput.captureFramedoes not run.onPlaybackStarteddoes not occur.As a result, the text is withheld from the transient
lk.transcriptionstream. A later audible reply can recover the stream, but the zero-duration reply never receives live transcription.Required behavior
When a segment has ended text input and audio input, and its pushed audio duration is zero,
TranscriptionSynchronizershould settle that segment immediately and flush its text unsynchronized. It must not wait for a playback start that cannot occur.This path should preserve normal paced delivery for segments that contain audio.
Rationale
A non-empty agent reply can remain available through application conversation-item events and chat context, but consumers of the
lk.transcriptionstream still miss the live transcript for the affected reply. Local application-side re-emission is unsafe because it can duplicate text when timing races resolve normally. The synchronizer owns the segment state and can determine zero duration without a race.Affected area
@livekit/agentsSegmentSynchronizerImplTranscriptionSynchronizer/SyncedAudioOutputsegment lifecycleReproduction
lk.transcription.Acceptance criteria
onPlaybackStarted.Local context
Quippy added synchronized transcription pacing in PR #79. Its integration test currently verifies that a zero-frame reply does not wedge the next audible reply. The application does not add a local raw-output fallback because the SDK has the authoritative segment state and a watchdog could double-deliver text.
Requested by @jonathanli12.
Backlinks: