faint-printer-85167
03/17/2026, 6:46 PMspeech not done in time after interruption, cancelling the speech arbitrarily
• failed to perform clear buffer rpc
• livekit.rtc.rpc.RpcError: Connection timeout
• didn't receive playback finished event after clear buffer, marking playout as done arbitrarily
I also noticed that some track_unmuted / track_muted callbacks appeared to receive an object without .identity, which looked like a RemoteTrackPublication.
Questions
1. What exactly does wait_for_playout() guarantee in the Python Agents/avatar stack? Does it mean:
• audio has been fully heard by the remote participant, or
• audio frames have only been queued / handed off locally?
2. Under what conditions does the avatar stack issue a clear buffer rpc? If the avatar participant has already disconnected, is RpcError: Connection timeout expected in that case?
3. If the avatar participant disconnects mid-session, what is the recommended application-side behavior during interruption / shutdown? Should app code:
skip buffer clear attempts,
skip interrupt() paths that depend on avatar connectivity,
• or simply treat clear buffer rpc timeout as benign?
4. Is there a supported way to detect whether avatar/audio output is still audibly playing for the remote participant, beyond wait_for_playout()? I’m trying to prevent an idle watchdog from re-prompting while users can still hear the question.
5. For Python room event handlers like track_unmuted and track_muted, what are the exact callback argument types? Can the second callback argument ever be a publication-like object instead of a participant object? If so, what is the correct supported way to recover the speaker identity?
6. Are there known issues or best practices for:
• avatar disconnects during active playout
• speech not done in time after interruption
• clear buffer rpc timeout during shutdown / participant disconnect
Goal
I want to make my agent robust in these scenarios:
• avatar disconnects should not cause noisy or blocking teardown
• playback cleanup should degrade gracefully if the avatar is already gone
• watchdog timers should not fire while TTS is still effectively playing
• track event handling should not assume the wrong callback object type
If helpful, I can also share a minimal log excerpt or a reduced repro sequence.tall-airline-16756
03/17/2026, 6:46 PMtall-airline-16756
03/17/2026, 6:47 PMwait_for_playout() actually guarantees, when clear buffer RPCs are sent and why they can time out, how to handle avatar disconnects during shutdown/interrupt, detecting remote audible playback, and the track_muted / track_unmuted callback argument types.
1) What does wait_for_playout() guarantee?
• wait_for_playout() does NOT guarantee the remote participant has actually heard the audio end-to-end.
• It guarantees that the agent has finished handing off audio frames into the agent/avatar playback pipeline (i.e., locally queued/processed for playback).
• End-to-end audible confirmation requires a playback-finished callback from the avatar server/renderer; if that callback cannot be received (for example because the avatar disconnected), wait_for_playout() cannot confirm remote rendering.
How this affects you:
• Treat wait_for_playout() as a “local enqueue and local-completion” signal, not a proof of remote audible playback.
2) When does the avatar stack issue a clear buffer RPC, and is Connection timeout expected if the avatar disconnected?
• The agent sends a clear buffer RPC when you interrupt or cancel playback (to discard any queued avatar frames and reset avatar state).
• If the avatar participant (the renderer/server side) has disconnected, the RPC cannot be delivered and a RpcError: Connection timeout is expected.
• That timeout indicates the avatar endpoint is unreachable over the room connection — this is normal if the participant already left.
3) Recommended application behavior when avatar disconnects mid-session
• Treat clear buffer RPC timeouts as benign and non-fatal:
◦ Do not block shutdown or interruption flow waiting for RPC success.
◦ Catch RpcError/Connection timeout and continue cleanup.
◦ Log at debug or info level rather than failing the agent flow.
• Practical pattern:
a. Wrap RPC calls in try/except and handle RpcError as recoverable.
b. Cancel/cleanup local speech handles and pending state regardless of RPC outcome.
c. If you rely on graceful drain, consider session.shutdown(drain=True) semantics (or your equivalent) but do not let RPC timeouts stall the whole shutdown.
• Alternatively, if you have strong reasons to avoid issuing clear buffer after disconnect, you can check participant presence before calling clear buffer; but that check can race (participant may disconnect between check and RPC). Safer is “attempt RPC, handle timeout as benign.”
4) Is there a supported way to detect whether audio is still audibly playing remotely (beyond wait_for_playout())?
• There is no guaranteed SDK API that confirms “remote user is still hearing audio” once the audio has been handed off.
• The next-best signals:
◦ The avatar server’s playback-finished RPC/callback — rely on it when available.
◦ Use wait_for_playout() to avoid immediate re-prompting (best available local signal).
◦ Guard watchdog timers by: start watchdog only after a known idle period following wait_for_playout(), or reset watchdog when you get explicit playback-finished callbacks.
• Practical approach for your watchdog:
◦ Do not trigger re-prompting until wait_for_playout() completes.
◦ Add a small safety window (e.g., a configurable short delay) after wait_for_playout() before the watchdog can reprompt to account for network/playout jitter.
◦ If the avatar disconnects and you don’t get a playback-finished callback, treat the clear-buffer timeout as benign and allow watchdog to proceed after a conservative timeout.
5) track_unmuted / track_muted callback argument types — can the second argument ever be a publication-like object?
• The event signature is: (publication, participant).
◦ First argument: TrackPublication (e.g., RemoteTrackPublication).
◦ Second argument: Participant instance representing the publisher.
• The second argument should be a Participant object and you should be able to read participant.identity.
• If you observe a publication-like object in the participant slot:
◦ That indicates an SDK/event-dispatching mismatch or a bug or version inconsistency in the SDK stack or wrappers.
◦ Actionable safeguards:
▪︎ Add a defensive type check before accessing .identity.
▪︎ If the second arg is a RemoteTrackPublication, retrieve the identity from the publication’s publisher information if available, or fall back to participant lookup by publication.sid or other metadata.
Example defensive pattern:
def on_track_muted(publication, maybe_participant):
if hasattr(maybe_participant, "identity"):
publisher_id = maybe_participant.identity
elif hasattr(publication, "publisher_identity"):
publisher_id = publication.publisher_identity
else:
publisher_id = "<unknown>"
• If you can reproduce this mismatch reliably, share a minimal log/repro — it’s worth verifying you’re on compatible SDK versions and that no wrapper is changing arguments.
6) Known issues and best practices (summary)
• Avatar disconnects during active playout:
◦ Expected in unreliable networks; handle gracefully.
◦ Best practice: agent remains functional; clear buffer rpc failures are benign.
• `speech not done in time after interruption`:
◦ This is a fallback safety path when play-out doesn’t complete in a timeout after interruption.
◦ It’s a defensive behavior: the agent marks playout done to avoid deadlocks.
◦ Use wait_for_playout() patterns and avoid awaiting long-running speech handles without timeouts.
• clear buffer rpc timeout during shutdown / participant disconnect:
◦ Expected and benign if participant left.
◦ Treat as non-blocking; continue shutdown.
Concrete recommendations to harden your agent
• Wrap avatar RPCs in try/except and treat RpcError/Connection timeout as recoverable.
• Use wait_for_playout() to gate re-prompts; add a small configurable safety window after it completes.
• Do local cleanup (cancel speech handles, clear local buffers) even if RPCs fail.
• Log these RPC timeouts at debug/info level so they don’t look like critical errors.
• Add defensive type checking in track event handlers and recover identity from publication metadata if needed.
• If you need exact audible confirmation for users, build a protocol-level acknowledgement (e.g., avatar server sends explicit playback-finished event that you treat as authoritative) — otherwise rely on local handoff + playback-finished callbacks when present.
Next steps / offer
• If you want, paste a minimal log excerpt showing the exact sequence (timestamps around the disconnect + RPC attempts). I can point to which lines to suppress or which checks to add.
• If you can reproduce the track callback identity mismatch, share a tiny repro and I’ll show how to adapt the handler safely and what to inspect in SDK versions.
If you’d like, I can convert the recommendations into a small code-template for your shutdown/interruption path (with try/except handling, watchdog gating, and defensively-typed track handlers). Which would help more: a log review, a code-template, or both?
Sources: client-sdk-js | livekit/livekit_composite | DeepWiki | Agent speech and audio | LiveKit Documentation | Bringing AI avatars to voice agents | LiveKit | How Playback built a global stadium for watching sports together | LiveKit | Forwarding to the frontend | LiveKit Documentation, with interactive elements