Hey team :wave: Need help with an outbound SIP iss...
# ask-ai
m
Hey team 👋 Need help with an outbound SIP issue on self-hosted LiveKit (v1.9.12). Problem: On outbound calls, session.say() and generate_reply() produce audio (shows in transcript) but the callee never hears it. Once the callee speaks first, all agent responses work perfectly. Setup: Self-hosted LiveKit v1.9.12 + SIP latest on EC2, Python agents v1.5.0, Deepgram TTS, Twilio SIP trunk. What works: Callee says "Hello" → agent responds → audio flows ✅ What doesn't: Agent greets first via session.say() → audio generated but not heard ❌ We've confirmed: • sip.callStatus becomes "active" ✅ • SIP bridge subscribes to agent's roomio_audio track ✅ • TTS generates audio successfully ✅ • Audio appears in transcript ✅ • But callee hears silence ❌ Tried everything: waiting for callStatus active, set_participant(), subscribed_fut, different SDK versions (1.3.12 + 1.5.0), playDialtone, session start before/after SIP participant — nothing works. Building an elderly welfare check platform where the agent MUST speak first. Filed a GitHub issue: [https://github.com/livekit/livekit/issues/4378] Has anyone gotten agent-first speech working on self-hosted outbound SIP? Any config we might be missing vs LiveKit Cloud? 🙏
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 very helpful context. I’m sorry you’re stuck on this; I know agent-first speech is critical for your use case. I’m going to help narrow this down and identify what we should check next. What I’m responding to: the outbound SIP call where
session.say()
/
generate_reply()
produce audio (appears in transcript) but the callee hears silence unless they speak first. You’re on self-hosted LiveKit v1.9.12 + SIP bridge, Python agents v1.5.0, Deepgram TTS, and Twilio SIP trunk. You’ve already verified callStatus is active, the SIP bridge subscribes to the agent’s
roomio_audio
track, TTS generates audio, and audio appears in transcripts. Quick summary of likely areas to check (what you CAN do next) • Media flow & SSRC/DTMF timing: If the SIP endpoint has not started receiving RTP from LiveKit (or RTP packets are being dropped) until it receives audio from the callee, the endpoint could be in a receive-only state. Check whether the SIP endpoint expects a specific RTP/RTCP exchange pattern (some trunks disable media until they detect incoming media). You can test by forcing RTP to start earlier (see next steps). • Early RTP/hold/unmute semantics: Make sure the SIP call is not put in a state that mutes or holds media from the LiveKit side until remote RTP is detected. Verify SDP direction attributes and the negotiated media direction (sendrecv vs sendonly vs recvonly) at call establishment. • SDP offered/answer differences: Compare the SDP from LiveKit → SIP and SIP → LiveKit on calls where agent speaks first vs where callee speaks first. Look for direction flags (
a=sendrecv
,
a=sendonly
,
a=recvonly
,
a=inactive
) and codec mismatches. If LiveKit is negotiating
recvonly
toward the SIP endpoint initially, the callee won’t hear agent audio. • RTP forwarding from SIP bridge: Confirm the SIP bridge is actually forwarding RTP packets to the SIP trunk when agent audio is generated. Capture RTP on the EC2 interface and/or from the Twilio side to see if packets are leaving LiveKit/SIP bridge when
session.say()
runs. • Media SSRC and track mapping: Ensure the
roomio_audio
track’s SSRC and payload type are mapped correctly in the bridge’s SDP. If payload types differ and no dynamic mapping is applied, RTP may be dropped by the SIP side. • DTMF / comfort noise / silence suppression: Check whether the SIP trunk or callee endpoint applies silence suppression or VAD and is dropping the TTS audio if it starts with low energy. Try sending an initial short tone or audible playout (e.g., 200 ms of white noise or a short beep) before TTS to see if that wakes the callee’s audio path. • Twilio SIP trunk specifics: Some trunks or proxies may delay media until they see RTP from the far end. Verify Twilio’s SIP trunk settings for early media and NAT keepalive behavior. Targeted diagnostic steps (please run when convenient) 1. Capture SDPs: ◦ Save the a) SDP from LiveKit->SIP and b) SDP from SIP->LiveKit for a call where agent speaks first and callee hears nothing. Paste the two SDPs here (redact sensitive IPs if needed). 1. Network capture on EC2: ◦ Capture UDP/TCP packets on the EC2 interface during an agent-first call and when callee speaks-first (pcap). Look for RTP from LiveKit to Twilio and confirm timestamps align with
session.say()
audio generation. 1. Verify RTP is sent immediately: â—¦ While reproducing, run a packet capture filtered for RTP ports used by the bridge to confirm RTP packets are emitted when
session.say()
runs. 1. Test a “wake” sound: ◦ Modify the agent to play a short tone (e.g., 300 Hz sine wave, 200 ms) before the TTS speech. If the callee hears the tone, it likely indicates a receive-only or silence suppression behavior on the SIP/trunk side. 1. Check negotiated directions: ◦ From the SDPs, confirm LiveKit advertises
sendrecv
and the SIP side does not answer
recvonly
toward LiveKit. 1. Try forcing a small RTP stream: â—¦ If possible, send a short RTP keepalive or periodic audio packets to Twilio immediately after call connect and before
session.say()
to ensure media path is open. Information I need from you to narrow this down (please provide any that you can) • A sanitized copy of the two SDPs (LiveKit→SIP and SIP→LiveKit) for a failing agent-first call. • A short pcap or confirmation whether RTP packets leave the SIP bridge when
session.say()
is invoked. • Any SIP/trunk settings on Twilio that could affect early media, silence suppression, or RTP gating. • Whether the callee endpoint is a SIP phone, PSTN via Twilio, or mobile — and whether behavior differs by callee type. • The SIP bridge logs around call setup and when
session.say()
is executed (timestamps help). Why I’m asking for these: the symptoms point strongly to media-negotiation or RTP-forwarding timing rather than TTS or LiveKit SDK logic, since you see transcripts and bridge subscriptions but no audio at the callee. The SDPs, RTP traces, and trunk settings will reveal whether the SIP side is refusing audio until it detects incoming media or if SSRC/codecs are mismatched. Short-term workaround ideas to try now • Prepend a short audible tone or a brief 200–500 ms audio burst before the actual greeting to force the callee’s media path open. • If you can control Twilio settings, enable any “early media” or disable silence suppression features for the trunk to see if that allows agent-first audio. • Try a test using a different SIP endpoint (pure SIP UA) to see if the problem is Twilio-specific. If you share the SDP and/or a short pcap and any Twilio trunk settings, I’ll analyze them and give concrete next steps (we can check exact SDP attributes, payload types, and expected RTP mappings). , with interactive elements
m
Thanks for the detailed diagnostic steps! Here's what we found: SDP Offer (LiveKit SIP → Twilio): m=audio 17348 RTP/AVP 9 0 8 101 a=sendrecv a=rtpmap:9 G722/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:101 telephone-event/8000 SDP direction is sendrecv — correct. Publisher WebRTC SDP (SIP bridge → LiveKit server): m=audio 9 UDP/TLS/RTP/SAVPF 111 9 0 8 a=sendrecv a=rtpmap:111 opus/48000/2 Also sendrecv. ICE connects successfully between SIP bridge and LiveKit server (both on same EC2 host, using internal IP 10.0.1.159). We also tried the "wake sound" suggestion — sent a short "." via session.say() before the greeting. Callee still heard nothing until they spoke first. Agent logs confirm TTS runs and completes: 055601 agent.sending_greeting 055608 agent.greeting_sent SIP logs confirm track subscription: 055603 track subscribed (agent roomio_audio → SIP participant) 055603 mixing track Everything looks correct in the logs — sendrecv negotiation, track subscription, audio generation. But the callee hears silence until they speak. Could this be related to the SIP bridge's deferred track subscription (PR #165)? Even though callStatus shows "active" and tracks are subscribed, the RTP packets from the agent may not be forwarded until the bridge receives RTP from the callee side? Is there a way to force the SIP bridge to start forwarding agent RTP immediately after track subscription, without waiting for callee RTP?
t
Thanks — this is excellent troubleshooting and the SDPs make the situation clear. I’m responding to your question about whether you can force the SIP bridge to start forwarding agent RTP immediately after track subscription (instead of waiting for callee RTP). Short answer • There is no runtime configuration in the self-hosted SIP bridge that forces immediate RTP forwarding once a track is subscribed. The bridge currently defers forwarding until it detects inbound RTP in many cases, so agent-first audio can be blocked. • The practical options are: (A) apply a bridge-side change to stop deferring RTP, (B) use an audio-level workaround to trigger the bridge/trunk, or (C) test trunk/endpoint settings that allow early media. I’ll list actionable next steps for each approach. What the SDPs and your logs tell us • Both sides negotiated sendrecv (so direction is correct). • Track subscription and TTS generation are happening, but RTP is not reaching the callee until the callee speaks. • This matches the known deferred-RTP behavior in the SIP bridge where it waits to detect incoming RTP before forwarding outbound RTP. Actionable options and steps 1) Short-term/workaround tests (fast to try) • Send a stronger, audible “wake” signal before the greeting: ◦ A short 200–500 ms tone (e.g., 1 kHz sine) is more reliable than a low-energy TTS “.”. You already tried a low-energy token; try a full-band tone or short click burst. ◦ If tone works, prepend it to all agent-first calls as a practical workaround. • Try tweaking Twilio trunk settings: ◦ Enable early media / disable silence suppression or VAD on the Twilio trunk if available. ◦ Check any SIP proxy/NAT settings that gate media until remote RTP is seen. • Test with a raw SIP UA (not PSTN via Twilio) to determine if this behavior is Twilio-specific. If a straight SIP phone hears agent-first audio, the trunk is the likely gate. 2) Diagnostics to confirm RTP forwarding behavior • Capture RTP on EC2 during an agent-first call (pcap) and verify: ◦ Whether RTP packets from the bridge to Twilio are present when
session.say()
runs. ◦ If no RTP is emitted until the callee speaks, that confirms the bridge is deferring forwarding. • Add bridge debug logs around RTP forwarding to see the exact condition that toggles forwarding (e.g., inbound RTP detection, RTCP, or SDP event). 3) Bridge code change (self-hosted, more involved but definitive) • Modify the SIP bridge logic to begin forwarding RTP immediately after the agent track is subscribed and the call is active — i.e., do not require prior inbound RTP detection. • Areas to inspect/patch: ◦ The “RTP gating” or “wait for inbound RTP” logic in the SIP bridge implementation (this is what PR #165 and related discussion reference). ◦ Ensure the bridge will still respect sendrecv SDP semantics and handle RTP/RTCP correctly (SSRC/payload-type mapping). • If you’re comfortable editing the bridge, I can point you to the likely code paths to change (where the bridge waits for inbound RTP before creating/forwarding RTP sockets). If you prefer, paste the bridge logs and I’ll point to specific files/conditions to inspect. • This change is only viable for self-hosted deployments and will require careful testing with various trunks to avoid regressions. 4) Longer-term: upstream fix or feature • The underlying issue appears to be a SIP bridge media-policy limitation. If the bridge were changed to not defer forwarding, agent-first speech would work for all self-hosted users. • You’ve already filed a GitHub issue — continue that thread and reference your SDPs and RTP captures. If a PR exists (PR #165 style), ask if it can be backported to your v1.9.12 stack or provide guidance on applying the patch. What I can help with next • If you want to try the bridge patch route, tell me whether you can share the SIP bridge logs and the bridge repo version/commit. I’ll point to the specific code paths to change and suggested patch logic. • If you prefer the diagnostics route, share a short pcap (RTP) or the bridge debug logs for a failing agent-first call and I’ll confirm whether RTP is leaving the bridge. • If you want to test a stronger wake tone and need a quick snippet to generate a 1 kHz 300 ms tone via your agent, tell me your agent language and I’ll provide code. If you tell me which path you want to take (workaround, diagnostics, or bridge patch), I’ll give targeted next steps and exact commands/snippets. Sources: examples/voice_agents | livekit/livekit_composite | DeepWiki | sip | livekit/livekit_composite | DeepWiki | Agents telephony integration | LiveKit Documentation | Outbound Calling Script | LiveKit Documentation | examples/dtmf | livekit/livekit_composite | DeepWiki, with interactive elements
m
We need the bridge patch route — agent MUST speak first for our elderly welfare check use case. Waiting for callee to speak first is not an option. We're running livekit/sip:latest Docker image (pulled March 2026) on EC2 with host networking. Can you point us to the specific code paths in the SIP bridge Go code that defer outbound RTP forwarding? We want to patch it to start forwarding agent RTP immediately after track subscription + callStatus active, without requiring inbound RTP detection first. Also — does LiveKit Cloud behave differently here? A community post by Zaheer_Abbas shows agent-first audio working on LiveKit Cloud (3tqm7ro6kbs.sip.livekit.cloud) with wait_until_answered=True. If Cloud doesn't defer RTP the same way, that confirms this is a self-hosted bridge behavior we can patch. Happy to share bridge logs, pcap, or anything else needed. We can also test patches quickly — our EC2 instance is fully accessible via SSM. This asks for: 1. The exact Go code file/function to patch 2. Whether Cloud behaves differently (which would confirm the fix is possible) Update: I checked the SIP bridge source code (room.go, outbound.go). Subscribe() at line 407 of outbound.go is called after SIP connection, and room.go's Subscribe() method sets subscribe=true and subscribes to all remote participant tracks immediately. SwapOutput() connects room audio output to SIP media writer. There's NO inbound RTP gating in the code — the audio pipeline should activate immediately once Subscribe() is called. So the issue may not be RTP deferral in the bridge. The audio path is: Agent TTS → LiveKit room (roomio_audio track) → SIP bridge Subscribe() → SwapOutput(media writer) → RTP to Twilio. Could the issue be in the LiveKit server-side track forwarding? The SIP bridge subscribes to the agent's track via WebRTC, and the LiveKit server forwards the track data. If the server's subscriber transport for the SIP participant doesn't start forwarding until it receives publisher data (agent audio), there could be a timing issue where the agent's TTS audio frames arrive before the WebRTC subscriber connection is fully established. Is there a way to verify that the LiveKit server is actually forwarding the agent's audio track data to the SIP bridge's subscriber connection?
t
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!
m
Update: I checked the SIP bridge source code (room.go, outbound.go). Subscribe() at line 407 of outbound.go is called after SIP connection, and room.go's Subscribe() method sets subscribe=true and subscribes to all remote participant tracks immediately. SwapOutput() connects room audio output to SIP media writer. There's NO inbound RTP gating in the code — the audio pipeline should activate immediately once Subscribe() is called. So the issue may not be RTP deferral in the bridge. The audio path is: Agent TTS → LiveKit room (roomio_audio track) → SIP bridge Subscribe() → SwapOutput(media writer) → RTP to Twilio. Could the issue be in the LiveKit server-side track forwarding? The SIP bridge subscribes to the agent's track via WebRTC, and the LiveKit server forwards the track data. If the server's subscriber transport for the SIP participant doesn't start forwarding until it receives publisher data (agent audio), there could be a timing issue where the agent's TTS audio frames arrive before the WebRTC subscriber connection is fully established. Is there a way to verify that the LiveKit server is actually forwarding the agent's audio track data to the SIP bridge's subscriber connection?