stocky-monkey-97351
05/22/2026, 10:44 AMrealtime_audio_output_node() emit custom audio frames before the first OpenAI Realtime audio frame arrives?
I’m trying to implement a non-blocking prerecorded filler/backchannel preroll for avatar lipsync: after the user stops speaking, OpenAI Realtime should start generating the real response immediately; if no model audio is available after ~200–400 ms, I want to emit a short WAV like “mmh / ok / I see” into the same avatar audio stream, then cancel it as soon as the first real model audio frame arrives.
The key requirement is that this must not behave like session.say(...) or a queued assistant speech item, because that only shifts the latency later. It needs to mask latency while the realtime response is already being generated.
Is this supported with realtime_audio_output_node(), or does that node only process/transform model audio frames after the model has already started producing them?tall-airline-16756
05/22/2026, 10:44 AMtall-airline-16756
05/22/2026, 10:44 AMrealtime_audio_output_node() can emit custom/prerecorded frames before the model’s first audio frame.
Short answer: No — realtime_audio_output_node() only receives and processes audio frames that the realtime model has already started producing. It cannot emit custom frames before the model’s audio stream begins.
What you can do instead:
• Publish a separate audio source/track for the preroll filler (e.g., a LocalAudioTrack or background audio player) and start that immediately after user speech ends.
• Monitor the model audio stream and, once the first model AudioFrame arrives, stop/cancel the preroll track and switch to the model audio stream so the model audio plays without queuing or delaying it.
If you want, I can outline a concise implementation approach for your stack (browser WebRTC + WebAudio, or server-side publishing) and the exact switch/stop logic you’d use to ensure the preroll is canceled immediately when model audio arrives. Which environment are you implementing this in?
Sources: Pipeline nodes and hooks | LiveKit Documentation | Stream music over WebRTC using React and WebAudio | LiveKit | Background audio | LiveKit Documentation, with interactive elementsstocky-monkey-97351
05/22/2026, 10:47 AMrealtime_audio_output_node() cannot emit audio before the first model frame.
The remaining key question for our use case is about avatar lipsync.
If we publish the filler/backchannel as a separate audio source/track while the OpenAI Realtime response is already being generated, can that separate track still drive the same avatar lipsync/speaking animation?
In other words, is there a supported way for a secondary, temporary audio track to be treated as avatar speech for lipsync purposes, without becoming a queued session.say(...) item and without blocking the main realtime model response?
Desired behavior:
1. User stops speaking.
2. OpenAI Realtime starts generating immediately.
3. A short prerecorded filler WAV is published through a secondary server-side audio source/track.
4. The avatar lipsyncs to that filler.
5. As soon as the first OpenAI Realtime audio frame arrives, the filler track is stopped and the avatar switches to lipsyncing the real model audio.
6. No extra assistant turn is created and no delay is added to the model response.
Is this possible with LiveKit’s avatar/audio pipeline today? If yes, should this be implemented as a server-side published LocalAudioTrack, a browser-side WebAudio track, or some other LiveKit pattern?tall-airline-16756
05/22/2026, 10:47 AMrealtime_audio_output_node() cannot be used to inject preroll; use a separate published track.
◦ Make the filler track low-priority and interruptible; cancel it immediately on the first model frame to avoid overlap or added latency.
◦ Test edge cases: very-short model audio, jittered arrival, and network delays to ensure lipsync handoff is smooth.
If you’d like, tell me whether your avatar/lipsync runs in the browser or on the server and which SDK you’re using (JS/TS, native). I’ll provide a short, concrete implementation sketch for that environment.
, with interactive elementsstocky-monkey-97351
05/22/2026, 11:01 AMavatar_preroll_filler?
2. Should the agent send a data message/event to the client such as active_lipsync_source=filler_track_sid?
3. When the model audio starts, should the server unpublish/mute the filler track and send another data message such as active_lipsync_source=agent_audio_track_sid?
4. Is there any built-in LiveKit convention for this active speech/lipsync source switching, or should we implement it entirely in our avatar client layer?
Our goal is to avoid session.say(...), avoid queued assistant turns, and keep OpenAI Realtime generation running in parallel while the avatar lipsyncs to a short filler preroll.tall-airline-16756
05/22/2026, 11:02 AMavatar_preroll_filler) so clients can discover it without guessing SIDs.
◦ Also ensure the agent/model audio track has an identifiable name/metadata (e.g., agent_realtime_audio).
1. Signaling the active lipsync source
◦ Use LiveKit data messages (reliable or unreliable depending on your tolerance) to tell the client which track to use for lipsync.
◦ Message format example (JSON): { "type":"active_lipsync", "track_name":"avatar_preroll_filler", "track_sid":"<optional>" }
◦ Have the client resolve the track either by trackSid (if provided) or by matching the published track `name`/metadata.
1. Switching back on model audio arrival
◦ On the server, detect the first model audio frame arrival.
◦ Immediately stop/unpublish or mute the filler track (unpublish if you want to remove it; mute if you might reuse it).
◦ Send another data message: { "type":"active_lipsync", "track_name":"agent_realtime_audio", "track_sid":"..." }
◦ Client should switch the lipsync input instantly to the model audio track and stop any filler-processing.
1. Client-side lipsync behavior
◦ Implement the lipsync component to accept an explicit active-track selection (by SID or name) rather than always using the first/primary audio track.
◦ When switching sources, smoothly transition lip animation (e.g., zero-crossfade amplitude smoothing) to avoid visual pops.
◦ If the filler is audible and overlapping with model audio for a few ms, prefer muting filler on first model frame to avoid double-speech.
1. Delivery and reliability considerations
◦ Use a reliable data message for the initial active-source switch to avoid missed signals.
◦ Still make the client robust: if a data message is missed, allow the client to fallback by choosing the louder live track or by listening for model frames on known agent track.
◦ Keep filler short and interruptible; ensure server-side timing cancels it immediately on first model frame.
Why this works
• LiveKit can carry multiple simultaneous audio tracks, but which one drives your avatar is an application decision. Explicit signaling plus clear track metadata gives deterministic, low-latency control without queuing a session.say turn.
If you want, I can provide:
• A small example message schema and client-side pseudocode for selecting tracks and switching lipsync in a LiveKit web (JS) avatar. Which would you prefer: pseudocode for the browser lipsync component or a short server-side sequence for publishing/muting the filler track?, with interactive elements