This message was deleted.
# ask-ai
s
This message was deleted.
t
Thanks for reaching out, VAMSI. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — this is a clear problem description and I can see why it’s urgent for your welfare-check use case. I’m responding to your report that agent audio (from
session.say()
/ TTS) is generated and appears in transcripts, the SIP bridge subscribes to the agent track and callStatus is "active", but the callee hears silence until they speak first. Short answer • Self-hosted LiveKit commonly needs explicit early-media / preconnect handling and proper NAT traversal (STUN/TURN) so outbound agent-first audio is actually delivered to the PSTN/SIP endpoint. Cloud handles many of those optimizations for you; self-hosted does not. There are three practical areas to check and steps to try right away. What to check and try (priority order) 1) Ensure the call really has an established RTP path before sending audio • Even if
sip.callStatus == "active"
, the remote SIP endpoint may not have an established bidirectional RTP/early-media path until it sends media. Confirm ICE/DTLS/RTP negotiation completed for the SIP participant and the SIP bridge shows RTP packets flowing to the trunk. • Action: enable verbose logs on your
livekit-sip
service and the LiveKit server and watch ICE connection states / RTP packet counters during the outbound flow. Look for RTP being sent from LiveKit to the SIP trunk when the agent speaks. 2) Enable/force early media / preconnect buffering • Self-hosted can miss early-media; enable buffering or preconnect so audio is ready and sent immediately: ◦ If you use the agent session options, enable preconnect buffering (example maps to agent SDK RoomOptions audio preconnect). ◦ When creating the SIP participant, set
play_dialtone=True
(this often forces early media path establishment). • Action: try creating the SIP participant with
play_dialtone=True
and enable any
is_preconnect_buffer_enabled
/ preconnect options in your agent session so the TTS audio is buffered and the bridge has media to forward immediately. 3) Wait for explicit subscription/track confirmation before speaking • Confirm the SIP bridge has subscribed to the agent audio publication and wait for that subscription event before calling `session.say()`: ◦ Wait for the publication
subscribed
event or otherwise wait for the SIP bridge subscription promise/future to resolve. • Action: add logic to wait on the track publication
subscribed
event (or an equivalent SDK subscription confirmation) before starting TTS playback. Additional environment/config items to verify • STUN/TURN: Make sure your STUN/TURN are configured and reachable from both LiveKit and the SIP bridge so ICE can establish a routable path to the trunk if NAT is involved. • SIP trunk early-media settings: Some PSTN/SIP trunks need early-media explicitly allowed or have call flow settings that block early RTP until the callee answers or sends media. Check your Twilio SIP trunk settings for early media / WebRTC-to-SIP behavior. • Opus/DTX/VAD: If the SIP bridge or trunk treats silence as no-media, disable aggressive DTX/VAD to avoid the trunk dropping incoming RTP pre-voice. • Timing: Try a short non-speech buffer (brief tone or ~200ms silence) before the agent speech as a pragmatic workaround that can nudge the path open. Why this happens (concise) • LiveKit Cloud pre-warms/handles early media and ICE behavior for you. Self-hosted deployments require correct early-media handling, ICE candidate flow, and trunk settings; without these, outbound audio from the agent can be generated locally and published, but the SIP/telephony leg won’t accept/route it until the remote side establishes or signals media presence first. If you want, I can help you debug this step-by-step • I can show the exact places to enable/collect logs from
livekit-sip
and LiveKit and which log lines/metrics to share. • I can provide a small code snippet to wait for publication
subscribed
and a snippet to create the SIP participant with
play_dialtone=True
. • If you prefer, paste the relevant
livekit-sip
and SIP trunk configuration snippets (redact secrets) and a short excerpt of the SIP/LiveKit logs around the call start and the agent-first TTS time, and I’ll point to the exact indicators to look for. If you'd like the small code snippets now, tell me whether you want Python (agent SDK) or another SDK and I’ll give the exact wait-for-subscription and create-sip-participant examples. Sources: SIP Lifecycle Management Agent | LiveKit Documentation | examples/voice_agents | livekit/livekit_composite | DeepWiki, with interactive elements
I don't have the answer you're looking for. You could also try asking your question: • in one of the other Slack channels or • to https://deepwiki.com/livekit/livekit_composite which is trained on all LiveKit source code If you find the answer, please post it here to help others!