Skip to main content

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 ICE & TURN Work

If you’ve ever wondered why some calls sound great and others don’t, the answer is often in ICE — the protocol that finds the best path for media between two endpoints. Understanding ICE helps you diagnose one-way audio, connection failures, and latency issues.

The Problem ICE Solves

Two devices want to send audio to each other. But between them:
  • NAT (Network Address Translation) — Private IPs (192.168.x.x) aren’t reachable from the internet
  • Firewalls — Block incoming connections
  • Symmetric NAT — Even STUN can’t discover the public mapping
ICE (Interactive Connectivity Establishment) systematically tries every possible path and picks the best one.

The Three Candidate Types

ICE discovers three types of candidates, in order of preference:

1. Host Candidates (Local)

Your device’s local network interfaces (e.g., 192.168.1.105 on WiFi).
  • Works when: Both devices are on the same LAN (rare for WebRTC calls)
  • Quality: Best — zero extra latency
  • Reality: Almost never used for WebRTC calls — both parties are rarely on the same network

2. Server-Reflexive Candidates (srflx) — via STUN

Your public IP, discovered by asking a STUN server (e.g., 203.0.113.5). How STUN works:
  1. SDK sends a request to stun.telnyx.com:3478
  2. STUN server sees the source IP (your public IP)
  3. STUN server sends it back: “Your public IP is 203.0.113.5”
  4. SDK creates a srflx candidate with that IP
  • Works when: Your NAT allows inbound traffic to the mapped port (most home/office routers)
  • Quality: Good — direct path, minimal extra latency
  • Blockers: Symmetric NAT, strict firewalls

3. Relay Candidates — via TURN

An IP address allocated on a TURN server that relays your media (e.g., 64.16.248.1). How TURN works:
  1. SDK authenticates with turn.telnyx.com:3478 (UDP) or turn.telnyx.com:443 (TCP)
  2. TURN server allocates a relay address (e.g., 64.16.248.1:50000)
  3. All media is sent TO the TURN server, which forwards it to the remote party
  4. Remote party also sends TO the TURN server, which forwards to you
  • Works when: Always — TURN is the fallback that never fails
  • Quality: Adds latency (each packet goes through the TURN server) but guarantees connectivity
  • Required when: Symmetric NAT, strict corporate firewalls, mobile carriers that block P2P

ICE Candidate Priority

The SDK tries candidates in this priority order:
PriorityTypePathLatency Impact
1 (best)HostDirect LANNone
2srflxDirect internet via STUNMinimal
3 (worst)RelayThrough TURN server+20-80ms per direction
In practice, most WebRTC calls use srflx (direct) or relay (TURN). Host candidates rarely work because both parties are on different networks.
A common misconception: “If my call uses TURN relay, something is wrong.”False. TURN relay is normal and expected in many network conditions — mobile networks, corporate networks, some ISPs. The question isn’t “is TURN being used?” but “is the TURN server close to me?”

ICE Gathering Process

When a call starts, the SDK gathers candidates in this sequence:
TimeEventResult
t=0msSDK starts ICE gatheringHost candidates collected (e.g., 192.168.1.105 WiFi, 10.0.0.2 Docker)
~50msSTUN request to stun.telnyx.com:3478srflx candidate discovered (e.g., 203.0.113.5:54321)
~100msTURN allocate to turn.telnyx.com:3478relay candidate allocated (e.g., 64.16.248.1:50000)
~200msSDP sent to remote party with all candidates(or sent incrementally with Trickle ICE)

Trickle ICE

By default, the SDK uses Trickle ICE — it sends candidates as they’re discovered rather than waiting for all of them:
const client = new TelnyxRTC({
  login_token: jwt,
  trickleIce: true, // default in SDK 2.25.20+
});
ModeBehaviorCall setup impact
Without Trickle ICESDK waits for ALL candidates (200-500ms) before sending INVITESlower setup
With Trickle ICESDK sends INVITE immediately with host candidates, then sends srflx/relay as discovered200-500ms faster

ICE Connectivity Checks

Once both sides have candidates, ICE performs connectivity checks in this order:
StepProtocolPurpose
1STUN BindingCan I reach you? Can you reach me?
2NominationThis candidate pair works — let’s use it
3DTLS handshakeEncrypt the media path
4SRTP flowsEncrypted audio starts
If the STUN check fails (e.g., firewall blocks it), ICE tries the next candidate pair until it finds one that works — falling back to TURN relay if necessary.

DTLS — Encrypting Media

After ICE finds a working path, DTLS (Datagram Transport Layer Security) encrypts the media:
PropertyValue
ProtocolDTLS-SRTP (RFC 5764)
CipherAES_CM_128_HMAC_SHA1_80 (most common)
Key exchangeECDHE (forward secrecy)
FingerprintIn SDP, verified during handshake
DTLS states:
StateMeaning
newNo handshake started
connectingHandshake in progress
connectedKeys exchanged, media encrypted
failedHandshake failed (often a network/firewall issue)
If DTLS is stuck at connecting, media won’t flow even if ICE connected. This is the #1 cause of one-way audio.

TURN Server Selection

Telnyx operates TURN servers in multiple regions:
RegionTURN ServerIP Range
US Eastturn-us-east.telnyx.com64.16.248.x
US Westturn-us-west.telnyx.com64.16.229.x
Europeturn-eu.telnyx.com185.183.x.x
Asia-Pacificturn-apac.telnyx.com(varies)
The SDK automatically selects the nearest TURN server. You can override:
const client = new TelnyxRTC({
  login_token: jwt,
  iceServers: [{
    urls: 'turn:turn-eu.telnyx.com:443?transport=udp',
    username: '...',
    credential: '...',
  }],
});

UDP vs TCP TURN

TransportPortLatencyWhen to Use
UDP (default)3478LowerMost cases
TCP443Higher (~20-40ms extra)When UDP is blocked
TLS443HighestWhen TCP is blocked (rare)
The SDK tries UDP first, falls back to TCP automatically.

Troubleshooting ICE Issues

STUN fails (error 701)

Cause: Firewall blocks stun.telnyx.com:3478 (UDP) Result: No srflx candidates — must use relay Fix: Open UDP 3478 to STUN servers, or accept TURN relay

All ICE fails

Cause: Both STUN and TURN are blocked Result: Call cannot connect — no media path exists Fix: Open access to TURN servers (TCP 443 minimum)

Relay when srflx should work

Cause: Symmetric NAT — NAT mapping changes per destination Result: STUN-discovered port doesn’t accept inbound from B2BUA-RTC Fix: This is normal; TURN relay is the correct solution

High latency on relay

Cause: TURN server is geographically distant Result: 100ms+ added round-trip Fix: Configure iceServers to use a closer TURN server

See Also