Under the hood · 10 min read
How WebRTC opens a call between two browsers
Signalling, ICE candidates, STUN, the DTLS handshake and SRTP — the four steps every browser call goes through, explained without the spec language.
WebRTC is the technology that lets two browsers exchange audio, video and data directly. It ships in every current browser, needs no plugin, and is what ClearChat is built on.
It is also famously confusing, because it solves four separate problems at once and the documentation tends to describe all four simultaneously. Here they are one at a time.
The problem it's solving
Two browsers want to send each other video. Neither has a public address anyone can dial. Both sit behind a home router doing network address translation, so from the outside they share one address with every other device in the house. Neither knows what video formats the other supports. And neither has any way to send the other a message.
That last one is the catch: WebRTC cannot start itself. Something outside it has to carry the first message.
Step 1 — Signalling: you carry the first message
One side generates an offer: a block of text in SDP format listing the media it wants to send, the codecs it speaks, and a fingerprint of the certificate it will use for encryption. The other side replies with an answer in the same format.
WebRTC does not specify how those two blobs get from one browser to the other. That is left entirely to you. A WebSocket to a small server is typical. So is a QR code, a chat message, or — as ClearChat originally did — copying a code and pasting it into WhatsApp.
This is why every “serverless” claim deserves a second look. Signalling always happens. It just doesn't have to be big, and it doesn't have to see your media.
Step 2 — ICE: finding a route that works
Now both sides know what the other wants. They still don't know how to reach each other.
ICE (Interactive Connectivity Establishment) solves this by brute force: each side gathers every address it might be reachable on, sends the list over, and then both sides try every combination until something works.
The addresses, called candidates, come in kinds:
- host — the device's own local address, like
192.168.1.40. Works when both people are on the same network. - srflx (server-reflexive) — the public address the world sees, discovered by asking a STUN server “what address did this packet come from?”. STUN is tiny, stateless, and never touches your media. ClearChat uses public STUN servers for this.
- relay — an address on a TURN server, which forwards packets when nothing else works. TURN carries your traffic, so it costs real bandwidth. ClearChat does not run one, which is the direct cause of the failures described in why a call won't connect.
Candidates are usually sent as they're discovered rather than all at once — trickle ICE — so connection setup can start before gathering finishes.
Step 3 — DTLS: agreeing on keys
Once a route is found, the two sides perform a DTLS handshake — essentially TLS over UDP — and derive the keys used to encrypt media.
The important detail is how each side knows it is talking to the right party. Remember the fingerprint in the SDP from step 1? After the handshake, each side checks that the certificate the other actually presented matches the fingerprint that arrived through signalling. If they differ, the connection is dropped.
That check is what ties encryption to identity — and it is why the signalling channel matters so much more than it first appears. Whoever controls signalling can substitute a fingerprint. That threat, and what can be done about it, is the subject of is your call really end-to-end encrypted.
Step 4 — SRTP and data channels: the actual call
With keys agreed, media flows as SRTP — encrypted RTP. This is not optional. WebRTC has no unencrypted mode; a browser will not send plain RTP at all.
Alongside media, WebRTC offers data channels, which carry arbitrary bytes over SCTP with the same encryption. Text chat, file transfer and small control messages all ride here. ClearChat uses one data channel for your messages and a second for coordination between the two browsers.
Changing things mid-call
Swapping your camera for a screen share does not require redoing any of the above. The sender
object exposes replaceTrack(), which swaps the media source underneath an established
connection with no new offer and no interruption.
This matters more than it sounds. In a design like ClearChat's, where the signalling socket
closes once the call is up, replaceTrack() is the only way to change what you're sending
— there is no longer a channel to negotiate over. It's why
screen sharing can be added to a live call at all.
Watching it happen
Open chrome://webrtc-internals in a Chromium browser (or
about:webrtc in Firefox) before starting a call. You'll see the offer and answer in full,
every candidate as it's gathered, which pair won, and live statistics for packets, bitrate and
round-trip time.
It is the fastest way to turn “it doesn't work” into a specific answer about which of the four steps failed.