lively-horse-90722
04/28/2026, 3:09 PMhandle.wait_for_playout() for a really long time in cases where session.say() is interrupted.
handle = await self._assistant.session.say(
text="speech",
allow_interruptions=True,
)
await handle.wait_for_playout()
If the user interrupts this speech by Agent, the await blocks for really long timetall-airline-16756
04/28/2026, 3:09 PMtall-airline-16756
04/28/2026, 3:10 PMhandle.wait_for_playout() when a session.say(..., allow_interruptions=True) is interrupted. Let’s troubleshoot.
What you can try now
• Check the SpeechHandle interrupted flag instead of only awaiting the playout:
a. Call await handle.wait_for_playout() with a timeout or wrap it in asyncio.wait_for(...).
b. After the wait (or on timeout), inspect handle.interrupted. If True, handle the interruption path (cancel work, start new speech, etc.).
• Use add_done_callback on the SpeechHandle to react immediately when speech ends or is cancelled instead of awaiting blocking playout.
• If you need immediate cancellation from your code, call session.interrupt() to stop playback and let the handle update promptly.
Questions to narrow this down
• Are you using any timeouts around wait_for_playout() now? If so, what values?
• Do you see handle.interrupted become True when interruption happens, or does it remain False?
• Any logs or stack traces when it blocks (audio subsystem, agent logs)?
If you share those details I’ll suggest the exact code pattern (timeout + interrupted check or callback) that fits your flow.
Sources: Turns overview | LiveKit Documentation | Function tool definition | LiveKit Documentation | Agent speech and audio | LiveKit Documentation, with interactive elementslively-horse-90722
04/28/2026, 3:20 PMawait handle.wait_for_playout() in my code. what could be the reasontall-airline-16756
04/28/2026, 3:20 PMawait handle.wait_for_playout() can hang after an interrupted session.say(...), and short, actionable ways to confirm and fix each one.
Possible causes and checks
• The speech system didn’t receive or process the interruption event.
◦ Check if handle.interrupted becomes True when the user interrupts. If it stays False the interruption wasn’t propagated.
• The SpeechHandle’s internal completion event isn’t fired when playback is cancelled.
◦ Add a done callback (handle.add_done_callback(...)) and log when it runs to see if the handle ever signals completion.
• The audio playback layer (player/driver) is stuck waiting for a stop/cleanup operation.
◦ Inspect agent or audio subsystem logs around the interruption for errors or long-running IO.
• Your code is waiting with no timeout while the handle’s completion never happens.
◦ Wrap the await in a timeout (e.g., asyncio.wait_for(handle.wait_for_playout(), timeout=...)) so you can recover if it hangs.
• A race between interruption and playout completion leaves the handle in a limbo state.
◦ After a timeout or callback, explicitly check handle.interrupted and treat that as finished (don’t rely only on wait_for_playout()).
Immediate, practical fixes
1. Use a timeout and check the flag:
◦ Wrap await handle.wait_for_playout() in asyncio.wait_for(...). After timeout or completion, check if handle.interrupted: ….
1. React with a callback:
◦ handle.add_done_callback(lambda h: asyncio.create_task(on_done(h))) to avoid blocking.
1. Trigger explicit interruption from your code when needed:
◦ Call session.interrupt() to force playback cancellation if you detect the user interrupted.
1. Add logging:
◦ Log when you call session.say(), when interruption arrives, the interrupted flag, and when callbacks run — this narrows the root cause quickly.
If you want, paste:
• the exact code around the say/interrupt sequence,
• whether handle.interrupted flips to True, and
• any relevant logs
and I’ll point to the best code pattern to make this reliable.
, with interactive elements