Skip to content
Parth Patel
All articles

What is WebRTC, and how do you actually use it?

NAT, ICE, STUN, TURN and the signalling server - the five pieces you need to understand before two browsers can talk to each other directly.

4 min read
  • webrtc
  • networking

WebRTC lets you add real-time communication to your application on top of an open standard. The API surface is small. The reason it feels hard is that everything interesting happens in the network underneath it - so this is a tour of that, in the order you actually run into it.

NAT (Network Address Translation)

NAT is a method of mapping an IP address space into another by modifying network address information in the IP header of packets while they are in transit across a traffic routing device.

Whenever you want to talk to a machine outside the private network you're on, your ISP's gateway router assigns a public IP address for that conversation, and maps your private IP onto it. That mapping is NAT.

Private Network                  Internet                  Other Peer
┌──────────────┐              ┌──────────┐              ┌──────────────┐
│ Peer1        │ ───────────► │ NAT/ISP  │ ───────────► │ Peer2        │
│ 192.168.x.x  │              │ PublicIP │              │ 192.168.x.x  │
└──────────────┘              └──────────┘              └──────────────┘
Private IP  ──mapped by NAT──► Public IP

Between NAT, firewalls and corporate network policy, simply reaching the other peer becomes the hard part. WebRTC uses ICE to get around it.

ICE (Interactive Connectivity Establishment)

ICE is the technique for finding the available paths across the internet between two devices, so they can talk directly. There is usually more than one possible path, and each one is called a candidate.

ICE relies on STUN and TURN servers to discover those candidates.

                  ICE
                   │
        ┌──────────┴──────────┐
        │                     │
      STUN                  TURN
        │                     │
Find public IP       Relay traffic if
and candidates       direct path fails

STUN (Session Traversal Utilities for NAT)

Suppose Peer1 wants to connect to Peer2 and both sit behind different firewalls. Each of them needs to know its own public IP address before it has anything useful to share with the other.

That is all a STUN server does: it's a lightweight service that replies with the IP address it saw the request come from.

Peer1 ─────► STUN Server ─────► Public IP: 203.x.x.x
Peer2 ─────► STUN Server ─────► Public IP: 145.x.x.x
 
Peer1 ◄──── Exchange Public IP ────► Peer2

TURN (Traversal Using Relays around NAT)

Sometimes a peer sits behind a NAT or firewall strict enough to block all traffic from unknown IPs, and no direct path exists at all.

A TURN server acts as a proxy. Traffic from Peer1 to Peer2 travels through the TURN server instead of going directly.

Without TURN:
Peer1  ─────X─────► Peer2
      (blocked)
 
With TURN:
Peer1 ───► TURN Server ───► Peer2
Peer1 ◄─── TURN Server ◄─── Peer2

TURN relays real media, so it costs real bandwidth - it's the fallback, not the default. I wrote up how to run your own on AWS separately.

The signalling server

Before two peers can connect, they have to exchange connection details. The server that carries those first messages is the signalling server, and once the connection is established it is no longer involved in the data transfer at all.

WebRTC deliberately doesn't specify how you do this - any two-way channel works. In Odoo POS, for instance, it can be done with RPC calls and _notify.

Peer1 ──rpc──► Server ──notify──► Peer2
Peer1 ◄─rpc── Server ◄─notify─── Peer2

Putting it together: the connection flow

Peer1                 Server                 Peer2
 │                      │                      │
 │─── ready ──────────► │ ── ready ──────────► │
 │                      │                      │
 │◄── offer ─────────── │ ◄─ offer ─────────── │
 │                      │                      │
 │── answer ──────────► │ ── answer ─────────► │
 │                      │                      │
 │◄── candidate ─────── │ ◄── candidate ────── │
 │── candidate ───────► │ ─── candidate ─────► │
 │                      │                      │
 │══════ ICE candidate exchange ═══════════════│
 │                      │                      │
 │<══════ Direct WebRTC Connection ═══════════>│

Step by step:

  1. Peer1 sends a ready / init call to the server, which forwards the signal to the other peers.
  2. On receiving ready, Peer2 creates a new RTCPeerConnection, creates an SDP offer, and sends it back to Peer1 through the signalling channel.
  3. On receiving the offer, Peer1 creates its own RTCPeerConnection, sets the offer as its remote description, creates an SDP answer, and signals it to Peer2.
  4. On receiving the answer, Peer2 sets it as its remote description, and both peers start exchanging ICE candidates.
  5. After enough candidates have been traded, a path is agreed and the connection is established.
ready/init
    │
    ▼
Create RTCPeerConnection
    │
    ▼
Create Offer ───► Send Offer
    │                 │
    │                 ▼
Receive Answer ◄── Create Answer
    │
    ▼
Exchange ICE Candidates
    │
    ▼
Direct Peer-to-Peer Connection Established

From here the two browsers are talking directly, and the signalling server can go back to sleep.

Further reading

Like this? Subscribe via RSS.