Documentation Index
Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
Use this file to discover all available pages before exploring further.
How WebRTC Signaling Works
WebRTC itself has no signaling protocol — it only defines how to establish media. The signaling (how you say “call this number” or “I’m ringing”) is up to the application. Here’s how the Telnyx WebRTC SDK does it.The Signaling Path
Key components:| Component | Role | Protocol |
|---|---|---|
| Your App | User interface | JavaScript |
| TelnyxRTC SDK | SDK logic | Internal |
| VSP | Voice SDK Proxy — translates WebSocket ↔ SIP | WebSocket + SIP |
| SIP Proxy | Routes SIP messages to carriers | SIP/UDP |
| B2BUA-RTC | Media gateway (WebRTC ↔ RTP) | DTLS/SRTP + RTP |
VSP handles signaling only. B2BUA-RTC handles media only. They are separate systems.
WebSocket Connection
The SDK opens a single persistent WebSocket tortc.telnyx.com:
What the DNS resolution does
rtc.telnyx.com resolves to the nearest VSP based on DNS-based geo-routing:
| Region | VSP DC |
|---|---|
| North America | NJ1 |
| Europe | AMS3, FR5 |
| Asia-Pacific | CN1 |
Outbound Call Flow
When you callclient.newCall():
What the SDK does at each step:
newCall()— Creates a Call object, starts ICE gathering- SIP INVITE — SDK sends invite message over WebSocket, VSP translates to SIP
- SDP negotiation — Codec selection (OPUS, PCMU, PCMA), ICE candidates exchanged
- Ringing — Remote party’s phone is ringing.
call.state === 'ringing' - Answer (200 OK) — Remote party picked up.
call.state === 'active' - Media flows — Audio transmitted via WebRTC (separate from signaling)
Inbound Call Flow
When someone calls your WebRTC client: What the SDK does:- Incoming INVITE — VSP receives SIP INVITE, pushes to SDK over WebSocket
callUpdatenotification —notification.call.state === 'ringing'- Your app decides — Call
call.answer()orcall.hangup() - Answer — SDK sends 200 OK, establishes WebRTC media
- Media flows — Two-way audio established
Session Description Protocol (SDP)
During call setup, both sides exchange SDP (Session Description Protocol) to agree on:| SDP Negotiates | Example |
|---|---|
| Audio codecs | OPUS (preferred), PCMU (G.711u), PCMA (G.711a) |
| Codec parameters | OPUS with FEC, stereo/mono, sample rate |
| ICE candidates | How to reach each other for media |
| DTLS fingerprint | For encrypting media (SRTP) |
| Media direction | Sendrecv (two-way), sendonly, recvonly |
| Bandwidth | Maximum bitrate |
Codec Priority
The SDK’s default codec priority:- OPUS — Best quality, handles packet loss well, variable bitrate
- PCMU — G.711μ-law, universal compatibility, 64kbps
- PCMA — G.711A-law, European PSTN standard, 64kbps
OPUS is strongly preferred — it handles jitter and packet loss better than G.711, and uses less bandwidth.
WebSocket Reconnection
If the WebSocket drops, the SDK automatically reconnects: See Handle Reconnection for the full reconnection behavior and how to handle it in your app.Custom Headers
You can pass custom SIP headers in both directions:Outbound (your app → carrier)
Inbound (carrier → your app)
Inbound custom headers are available in the notification:What Signals What
| Action | SDK Method | SIP Message | Who Initiates |
|---|---|---|---|
| Make a call | newCall() | INVITE | Client |
| Answer a call | call.answer() | 200 OK | Client |
| Reject a call | call.hangup() | 487 Request Terminated | Client |
| End a call | call.hangup() | BYE | Either side |
| Put on hold | call.hold() | re-INVITE with sendonly | Client |
| Resume from hold | call.unhold() | re-INVITE with sendrecv | Client |
| Send DTMF | call.sendDigits() | INFO (RFC 2833) | Client |
| Mute audio | call.mute() | (local only, no SIP) | Client |
Mute is a local operation — it stops sending audio from your microphone but doesn’t send any SIP signal. The remote party doesn’t know you’re muted (unless you tell them via your app).