Skip to content

livekit-sip BYE to inbound call routing error #642

@jonathanciechanowski

Description

@jonathanciechanowski

BYE routes back to itself instead of reaching the remote side → 481 → caller stuck on dead audio

What's happening

When livekit-sip tries to hang up an inbound call, the BYE it sends includes its own address in the Route headers. The BYE loops through the proxy chain and comes right back to livekit-sip instead of reaching the trunk provider. The call never actually gets torn down on the remote end, so the caller sits on dead audio until the provider's RTP timeout kicks in (~49 seconds in our case).

This looks related to the closed #112, but that fix addressed a missing From tag. This is a different problem — the Route set itself is wrong.

Setup

   
livekit/sip v1.2.0 — digest sha256:96ef59d461e6, git 8c4e964, built 2025-11-11
livekit-server-sdk 2.15.0
@livekit/rtc-node 0.12.2
Trunk provider Telnyx (inbound, UDP)
Topology Telnyx FreeSWITCH → two SIP proxies (TCP) → livekit-sip (TCP)

Full SIP trace

<details> <summary>Click to expand — complete annotated pcap dump</summary>
# ─── INVITE ────────────────────────────────────────────────────────
# T+0.000s  <PROXY_A>:5060 → <LIVEKIT_SIP>:5060  TCP

INVITE sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060 SIP/2.0
Record-Route: <sip:<PROXY_A>;transport=tcp;r2=on;lr;ftag=<FTAG>>
Record-Route: <sip:<PROXY_B>;r2=on;lr;ftag=<FTAG>>
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK2128.d1817250b841b56ec747a99ce287860e.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;received=<TELNYX_FS>;rport=6000;branch=z9hG4bKKNpXFtNcv1SUB
Max-Forwards: 58
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937604 INVITE
Contact: <sip:mod_sofia@<TELNYX_FS>:6000>
Content-Type: application/sdp
Content-Length: 356

v=0
o=Telnyx 1774963398 1774963399 IN IP4 <TELNYX_MEDIA>
s=Telnyx
c=IN IP4 <TELNYX_MEDIA>
t=0 0
m=audio 19394 RTP/AVP 9 0 8 18 101
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=no
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=rtcp:19395 IN IP4 <TELNYX_MEDIA>
a=ptime:20

─── 100 Processing ───────────────────────────────────────────────

T+0.044s <LIVEKIT_SIP>:5060 → <PROXY_A> TCP

SIP/2.0 100 Processing
Record-Route: <sip:<LIVEKIT_SIP>:5060;transport=tcp;lr>
Record-Route: <sip:<PROXY_A>;lr;ftag=<FTAG>;transport=tcp;r2=on>
Record-Route: <sip:<PROXY_B>;r2=on;lr;ftag=<FTAG>>
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK2128.d1817250b841b56ec747a99ce287860e.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;received=<TELNYX_FS>;rport=6000;branch=z9hG4bKKNpXFtNcv1SUB
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937604 INVITE
Content-Length: 0

─── 180 Ringing ──────────────────────────────────────────────────

T+0.046s <LIVEKIT_SIP>:5060 → <PROXY_A> TCP

SIP/2.0 180 Ringing
Record-Route: <sip:<LIVEKIT_SIP>:5060;transport=tcp;lr>
Record-Route: <sip:<PROXY_A>;ftag=<FTAG>;transport=tcp;r2=on;lr>
Record-Route: <sip:<PROXY_B>;r2=on;lr;ftag=<FTAG>>
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK2128.d1817250b841b56ec747a99ce287860e.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;branch=z9hG4bKKNpXFtNcv1SUB;received=<TELNYX_FS>;rport=6000
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937604 INVITE
Content-Length: 0

─── 200 OK ───────────────────────────────────────────────────────

T+0.560s <LIVEKIT_SIP>:5060 → <PROXY_A> TCP

SIP/2.0 200 OK
Record-Route: <sip:<LIVEKIT_SIP>:5060;lr;transport=tcp>
Record-Route: <sip:<PROXY_A>;r2=on;lr;ftag=<FTAG>;transport=tcp>
Record-Route: <sip:<PROXY_B>;ftag=<FTAG>;r2=on;lr>
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK2128.d1817250b841b56ec747a99ce287860e.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;received=<TELNYX_FS>;rport=6000;branch=z9hG4bKKNpXFtNcv1SUB
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937604 INVITE
Content-Length: 222
Contact: <sip:<LIVEKIT_SIP>:5060;transport=tcp>
Content-Type: application/sdp

v=0
o=- 1774963398 1774963400 IN IP4 <LIVEKIT_SIP>
s=LiveKit
c=IN IP4 <LIVEKIT_SIP>
t=0 0
m=audio 16941 RTP/AVP 9 101
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=sendrecv

─── ACK ──────────────────────────────────────────────────────────

T+0.603s <PROXY_A>:5060 → <LIVEKIT_SIP>:5060 TCP

ACK sip:<LIVEKIT_SIP>:5060;transport=tcp SIP/2.0
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK2128.5e49f9c6a60ddb153db90772ebdf108d.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;received=<TELNYX_FS>;rport=6000;branch=z9hG4bKSBejtvt1aQZBH
Route: <sip:<LIVEKIT_SIP>:5060;lr;transport=tcp>
Max-Forwards: 69
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937604 ACK
Contact: <sip:mod_sofia@<TELNYX_FS>:6000>
Content-Length: 0

─── BYE from livekit-sip (BROKEN) ───────────────────────────────

T+41.260s <LIVEKIT_SIP>:54792 → <PROXY_A>:5060 TCP

BYE sip:mod_sofia@<TELNYX_FS>:6000 SIP/2.0
Route: <sip:<LIVEKIT_SIP>:5060;transport=tcp;lr> ← BUG
Route: <sip:<PROXY_A>;r2=on;lr;ftag=<FTAG>;transport=tcp>
Route: <sip:<PROXY_B>;ftag=<FTAG>;r2=on;lr>
Via: SIP/2.0/TCP <LIVEKIT_SIP>:5060;branch=z9hG4bK.tsYZQnOE4AsUynnI;alias
Max-Forwards: 70
Call-ID: <REDACTED_CALL_ID>
Content-Length: 0
CSeq: 112937605 BYE
From: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
To: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>

─── BYE after proxy hop (looping back) ──────────────────────────

T+41.260s <PROXY_B>:5060 → <LIVEKIT_SIP>:5060 TCP

BYE sip:mod_sofia@<TELNYX_FS>:6000 SIP/2.0
Route: <sip:<LIVEKIT_SIP>:5060;transport=tcp;lr>
Route: <sip:<PROXY_A>;r2=on;lr;ftag=<FTAG>;transport=tcp>
Route: <sip:<PROXY_B>;ftag=<FTAG>;r2=on;lr>
Via: SIP/2.0/TCP <PROXY_B>;branch=z9hG4bK3128.2e0a389d13590bfbfc645976691f4e0b.0;i=181f8d;conid=14217601
Via: SIP/2.0/TCP <LIVEKIT_SIP>:5060;rport=54792;branch=z9hG4bK.tsYZQnOE4AsUynnI;alias
Max-Forwards: 69
Call-ID: <REDACTED_CALL_ID>
Content-Length: 0
CSeq: 112937605 BYE
From: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
To: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>

─── 481 (originated by livekit-sip, not Telnyx) ─────────────────

T+41.282s <LIVEKIT_SIP>:5060 → <PROXY_A> TCP

SIP/2.0 481 Call does not exist
Via: SIP/2.0/TCP <PROXY_B>;branch=z9hG4bK3128.2e0a389d13590bfbfc645976691f4e0b.0;i=181f8d;conid=14217601
Via: SIP/2.0/TCP <LIVEKIT_SIP>:5060;rport=54792;branch=z9hG4bK.tsYZQnOE4AsUynnI;alias
From: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
To: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937605 BYE
Content-Length: 0

─── 481 forwarded back ──────────────────────────────────────────

T+41.283s <PROXY_A>:5060 → <LIVEKIT_SIP>:54792 TCP

SIP/2.0 481 Call does not exist
Via: SIP/2.0/TCP <LIVEKIT_SIP>:5060;rport=54792;branch=z9hG4bK.tsYZQnOE4AsUynnI;alias
From: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
To: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937605 BYE
Content-Length: 0

─── Telnyx BYE (RTP timeout, ~49s later) ────────────────────────

T+89.988s <PROXY_A>:5060 → <LIVEKIT_SIP>:5060 TCP

BYE sip:<LIVEKIT_SIP>:5060;transport=tcp SIP/2.0
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK3128.312b1fc329dcead654cba63ba17dd9e6.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;received=<TELNYX_FS>;rport=6000;branch=z9hG4bK7vUDaS8j5v0rp
Route: <sip:<LIVEKIT_SIP>:5060;lr;transport=tcp>
Max-Forwards: 69
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937605 BYE
Reason: Q.850;cause=16
Content-Length: 0

─── 481 (dialog already gone) ───────────────────────────────────

T+90.010s <LIVEKIT_SIP>:5060 → <PROXY_A> TCP

SIP/2.0 481 Call does not exist
Via: SIP/2.0/TCP <PROXY_A>;branch=z9hG4bK3128.312b1fc329dcead654cba63ba17dd9e6.0
Via: SIP/2.0/UDP <TELNYX_FS>:6000;rport=6000;branch=z9hG4bK7vUDaS8j5v0rp;received=<TELNYX_FS>
From: "<CALLER>" <sip:<CALLER>@sip.telnyx.com>;tag=<FTAG>
To: <sip:<CALLED>@sip.<SCREENER_DOMAIN>:5060>;tag=<LTAG>
Call-ID: <REDACTED_CALL_ID>
CSeq: 112937605 BYE
Content-Length: 0


</details>

Expected behavior

livekit-sip should strip its own URI from the Route set when building outbound in-dialog requests like BYE (per RFC 3261 §12.2.1.1). The BYE should make it all the way to the remote UA and get a clean 200 OK back.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions