ripe-jordan-93499
03/06/2026, 1:28 PMtall-airline-16756
03/06/2026, 1:28 PMripe-jordan-93499
03/06/2026, 1:29 PMBackgroundAudioPlayer during a SIP call, the inbound audio stream from the caller stops working. STT receives no more transcripts after the background audio track is published. The SIP bridge appears to stop forwarding the caller's microphone audio.
## Timeline from logs
13:23:33.603 - STT FINAL received: "हां बोलिए" (last successful STT)
13:23:34.299 - BackgroundAudioPlayer created + started (publish_track)
13:23:34.299 - Thinking audio starts playing (keyboard typing clip)
13:23:35.356 - Thinking audio stopped, TTS response plays normally
... user speaks but ZERO STT events after this point ...
13:24:07.410 - "stream closed" for participant microphone (SOURCE_MICROPHONE)
13:24:18.555 - Inactivity fires: stt_idle=45.0s (no STT since 13:23:33)
## What we're doing
We play a "keyboard typing" sound while the LLM is thinking, before TTS responds. We use BackgroundAudioPlayer for this:
python
from livekit.agents import BackgroundAudioPlayer, AudioConfig, BuiltinAudioClip
# Create player and publish track
player = BackgroundAudioPlayer()
await player.start(room=room, agent_session=session)
# Play keyboard typing sound in a loop
clip = BuiltinAudioClip.KEYBOARD_TYPING
handle = player.play(AudioConfig(clip, volume=0.8), loop=True)
# Later, stop it before TTS speaks
handle.stop()
player._audio_source.clear_queue()
## Root cause
BackgroundAudioPlayer.start() calls publish_track() which publishes a second audio track (background_audio) to the room. The SIP bridge seems unable to handle multiple audio tracks from the agent participant — after the second track appears, it stops forwarding the caller's inbound microphone audio to STT.
## What we tried
1. agent_session=None — same issue, plus call drops when track is unpublished
2. agent_session=session — STT dies after publish_track
3. Creating player once and reusing (no repeated publish/unpublish) — STT still dies after first publish_track
4. Avoiding aclose() (no unpublish_track) — STT still dies because the publish itself is the problem
5. Writing directly to session.output.audio.capture_frame() — blocks TTS from playing (they fight over the same output)
## Question
Is there a way to play background/thinking audio during a SIP call without publishing a separate audio track? Ideally we'd mix it into the agent's existing audio track.
Or is there a SIP bridge configuration to handle multiple audio tracks from the same participant?tall-airline-16756
03/06/2026, 1:29 PMsession.output.audio.capture_frame() conflicts with TTS, so that approach isn’t viable.
What this means for you
• Using BackgroundAudioPlayer.start() (which publishes a second background_audio track) will continue to break inbound SIP audio/STT in the current environment.
• Avoiding publish/unpublish or reusing the same player won’t help because the issue happens when the second track is published.
Workarounds you can try
• Mix the background sound into the agent’s output before it reaches LiveKit (client-side mixing) so only a single agent track is published:
a. Create a single audio output stream that combines (a) the agent’s TTS and (b) the background/typing clip locally in your process.
b. Publish only that single mixed stream to LiveKit so the SIP bridge still sees one audio source.
◦ Note: you mentioned session.output.audio.capture_frame() blocked TTS when used; that indicates you’ll need a mixing pipeline that combines TTS and background audio frames together before writing them to the single capture API rather than trying to write separate streams concurrently.
• Perform server-side mixing (if feasible in your architecture):
◦ Render/mix the background clip with TTS on your server process into one PCM stream, then push that single stream into the LiveKit agent output.
• Avoid background audio during active inbound speech:
◦ Only play the background clip locally to your agent operator (if there is a human operator) or skip it when an inbound caller is speaking so STT continuity is preserved. This is a mitigation, not a full solution.
Questions to help narrow the best approach
1. Is the agent audio (TTS) generated and sent from the same process that can perform PCM-level mixing? Or are TTS and background playback handled by separate services/processes?
2. Do you have control over the capture pipeline used to write audio into LiveKit (i.e., can you mix frames before calling capture_frame()), or must you publish via LiveKit-provided track APIs only?
3. Is there any requirement that the background sound be a separate track (e.g., for independent volume control by consumers)? If yes, we’ll need to consider alternative architectures (for example, mixing locally but exposing control metadata to clients).
If you’d like, I can:
• Walk through an example mixing flow for combining a background clip + TTS into a single PCM stream and pushing that via session.output.audio.capture_frame() without blocking TTS (I’ll need details about how your TTS frames are currently produced and how you’re calling capture_frame()).
• Help design a server-side mixer outline if TTS runs on the server.
Thanks for the clear reproduction steps and logs — once you tell me which mixing options are possible in your setup (answers to Q1–Q3), I’ll provide a concrete implementation path you can try.
Sources: Agent speech and audio | LiveKit Documentation | sip | livekit/livekit_composite | DeepWikiripe-jordan-93499
03/06/2026, 1:31 PMtall-airline-16756
03/06/2026, 1:31 PMsession.output.audio.capture_frame()), so the SIP bridge sees only one agent audio source.
◦ Important: don’t attempt to write TTS and background audio as separate concurrent writes; instead produce a single mixed frame and send that.
• Server-side mixing
◦ Render/mix TTS + background clip on the server into one stream, then send that stream to LiveKit.
• Conditional background playback (mitigation)
◦ Only play the background clip when the caller is not speaking (VAD) or play it locally for your operator, not into the published track.
• If you must have separate control over background volume for listeners, send control signals/metadata to clients so they can locally mix or adjust playback (but still publish only one mixed stream to the SIP bridge).
Questions to recommend a concrete implementation
1. Is your TTS generation and publishing happening in the same process that can perform PCM-level mixing?
2. How are you currently using session.output.audio.capture_frame() — are you able to intercept or mix frames before calling it?
3. Do you need independent volume control for background audio for downstream listeners, or is a single mixed stream acceptable?
If you can tell me which of the above fits your setup (answers to Q1–Q3), I’ll provide a concrete mixing example and step-by-step changes you can implement to avoid publishing a second track while keeping your thinking-sound behavior.
Sources: Agent speech and audio | LiveKit Documentation | livekit/livekit_composite | DeepWiki | External data and RAG | LiveKit Documentation | Choosing the right noise cancellation for your agent | LiveKitripe-jordan-93499
03/06/2026, 1:36 PMtall-airline-16756
03/06/2026, 1:37 PM