Web Real-Time Communication
Web Real-Time Communication (WebRTC) is the open standard for browsers and native applications to exchange real-time audio, video, and arbitrary data peer-to-peer (P2P) at sub-second latency over the public Internet. The standard is jointly governed by the W3C (which defines the JavaScript API surface) and the IETF (which defines the wire protocols). Origins trace to Google’s 2011 open-sourcing of the Global IP Solutions (GIPS) audio engine after acquiring GIPS earlier that year, plus standards work that ran from 2011 through the 2017 W3C Candidate Recommendation and the 2024 final Recommendation. WebRTC’s architectural genius is the separation of signaling from media: the application is responsible for getting two endpoints to exchange a Session Description Protocol (SDP, RFC 4566) blob over whatever channel it likes (HTTPS POST, WebSocket Protocol, even a copy-paste between two browsers); after that out-of-band rendezvous, WebRTC handles the rest — Network Address Translation (NAT) traversal via Interactive Connectivity Establishment (ICE, see NAT Traversal), DTLS-SRTP encryption, codec negotiation, packet loss recovery — autonomously between the peers. The result is browsers can do real-time video calls without browser plugins, the foundational capability that enabled Google Meet, Discord (voice), the browser clients of Zoom and Microsoft Teams, every “WebRTC vendor” SaaS (Daily, LiveKit, Twilio Programmable Video, Agora, Vonage), and the vast majority of browser-based interactive video products.
1. Origins and Standardization Timeline
The path to WebRTC began with Skype’s success in the 2000s demonstrating that high-quality interactive voice and video over the Internet was tractable, but the technology was proprietary and Skype’s protocol was famously obfuscated. By 2010 the landscape was: Adobe Flash for browser-based video (with Real-Time Messaging Protocol for streaming and a separate RTMFP for P2P), proprietary apps for native, and no open browser standard for real-time communication.
Google acquired Global IP Solutions in May 2010 for $68.2M, primarily for GIPS’s iSAC and iLBC voice codecs and their NetEQ jitter buffer — battle-tested code from a decade of Skype-era proprietary work. In May 2011 Google open-sourced the GIPS code as the WebRTC project, donating it under a BSD-style license to lay the foundation for an open browser real-time communication standard. The W3C and IETF kicked off complementary working groups (W3C WEBRTC and IETF RTCWEB) the same year.
Standards milestones:
- 2011: WebRTC project open-sourced; standards groups form.
- 2013: Chrome, Firefox first ship WebRTC. First Chrome-Firefox interop demonstrated.
- 2015: Safari adds basic WebRTC. Edge follows shortly after.
- 2017: W3C Candidate Recommendation; the first “WebRTC 1.0 is real” milestone.
- 2018: IETF RFCs for the wire protocols mostly finalized — RFC 8825 (overview), RFC 8826 (security considerations), RFC 8827 (security architecture), RFC 8834 (media transport), RFC 8835 (transport), RFC 8836 (congestion control), and RFC 8829 (JSEP).
- 2021: WebRTC 1.0 W3C Recommendation candidate.
- 2024: WebRTC 1.0 W3C final Recommendation (Jennings, Boström, Bruaroey 2024).
- Ongoing: WebRTC-NV (Next Version) work — Insertable Streams, WebTransport, WebCodecs, MediaCapture-Transform.
2. The Three Core APIs
WebRTC’s W3C surface area is three intertwined JavaScript APIs:
2.1 getUserMedia — capture
navigator.mediaDevices.getUserMedia({ video: true, audio: true }) returns a Promise resolving to a MediaStream containing live MediaStreamTrack objects (one for the camera, one for the microphone). The browser prompts the user for permission. The constraints object can specify resolution ({ video: { width: 1920, height: 1080 } }), framerate, audio sample rate, echo cancellation flags, and dozens more parameters. Sister APIs getDisplayMedia (screen capture) and getUserMedia for camera/mic are the only paths to acquire raw media in a browser; the API’s permission model is the security backbone.
2.2 RTCPeerConnection — media exchange
The RTCPeerConnection object represents one P2P media session. Its lifecycle:
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.example.com:3478' },
{ urls: 'turn:turn.example.com:3478', username: 'u', credential: 'p' },
],
});
stream.getTracks().forEach(track => pc.addTrack(track, stream));
pc.onicecandidate = (e) => signaling.send({ candidate: e.candidate });
pc.ontrack = (e) => remoteVideoEl.srcObject = e.streams[0];
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
signaling.send({ sdp: offer });
// later, after receiving the peer's answer:
await pc.setRemoteDescription(answer);Walking through what happens: addTrack queues media for sending. createOffer synthesizes an SDP describing the local capabilities (codecs, resolutions, encryption parameters). setLocalDescription activates that offer locally. onicecandidate fires repeatedly as ICE gathering produces candidate IP:port tuples; the application forwards them via signaling. setRemoteDescription accepts the peer’s answer; ICE then starts connectivity checks. Once a working candidate pair is found, the DTLS handshake runs over it, SRTP keys are derived, and media flows.
2.3 RTCDataChannel — arbitrary data
const channel = pc.createDataChannel('chat', { ordered: true, maxRetransmits: 3 });
channel.onmessage = (e) => console.log('received:', e.data);
channel.send('hello');Data channels carry arbitrary application data over the same SCTP-over-DTLS-over-UDP transport that WebRTC uses for media bookkeeping. The two configuration knobs ordered and maxRetransmits (or maxPacketLifeTime) make data channels behave anywhere on the spectrum from “TCP-like reliable ordered” to “UDP-like unreliable unordered”. Used heavily by WebRTC-based games, file transfer apps (Snapdrop, ShareDrop), and as a side-channel for chat in video calls.
3. Signaling vs Media — the Architectural Split
The most-quoted design decision in WebRTC is that signaling is out of band — not specified by WebRTC. The application is responsible for transporting the SDP offer/answer and the ICE candidates between peers via whatever mechanism it likes. The reasoning: signaling channels already exist in every app (a chat server, a meeting service backend, a SIP gateway), and forcing a specific signaling protocol would either duplicate existing infrastructure or be incompatible with applications already using SIP, XMPP, Matrix, or proprietary systems.
The pragmatic outcome: ~95% of WebRTC applications use WebSocket Protocol for signaling. The application server runs WebSocket servers, the clients connect over WebSocket, and SDPs/candidates are exchanged as JSON over those sockets. Some apps use HTTP long-polling, HTTP/2 server-sent events, or even out-of-band copy-paste (the famous demo where you copy your SDP into your friend’s browser).
Once signaling completes the rendezvous, the application steps out of the way: media flows P2P (or to/from a server) without further server involvement. This is dramatically different from RTSP or RTMP, where the server is in the bytestream path for the entire session.
sequenceDiagram participant A as Browser A participant SIG as Signaling Server<br/>(WebSocket) participant B as Browser B participant STUN as STUN/TURN A->>SIG: connect (WebSocket) B->>SIG: connect (WebSocket) A->>A: getUserMedia → camera + mic B->>B: getUserMedia → camera + mic A->>A: createOffer → SDP A->>SIG: { sdp: offer } SIG->>B: { sdp: offer } B->>B: setRemoteDescription, createAnswer → SDP B->>SIG: { sdp: answer } SIG->>A: { sdp: answer } par ICE candidate exchange A->>STUN: STUN binding request STUN-->>A: server-reflexive candidate A->>SIG: { candidate: ... } SIG->>B: { candidate: ... } B->>STUN: STUN binding request STUN-->>B: server-reflexive candidate B->>SIG: { candidate: ... } SIG->>A: { candidate: ... } end A->>B: ICE connectivity checks (STUN over UDP) B->>A: ICE connectivity checks A->>B: DTLS handshake B->>A: DTLS handshake A->>B: SRTP-encrypted RTP video + audio B->>A: SRTP-encrypted RTP video + audio
What this diagram shows. Browser A and B both establish WebSocket connections to the signaling server. They each capture their local camera/mic. A creates an SDP offer describing what it wants to send and what codecs it supports; this offer is forwarded by the signaling server to B. B creates an answer describing what it can do; this is forwarded back. Meanwhile, both browsers gather ICE candidates by talking to STUN servers (the server-reflexive candidates — the public-side mappings of their NAT). Candidates are exchanged via signaling. Once both sides have all candidates, ICE runs connectivity checks: STUN binding requests over each candidate pair to confirm reachability. The first working pair becomes the active connection. DTLS handshake runs over that pair to derive symmetric SRTP keys. From there, RTP packets flow directly browser-to-browser, encrypted and carrying H.264 / VP9 / Opus / etc. The signaling server is no longer in the bytestream path; it becomes idle until one side disconnects or renegotiates.
4. Session Description Protocol
The SDP (RFC 4566) is the negotiation lingua franca. A WebRTC SDP offer describes:
- The codecs the offerer supports, in priority order
- The encryption parameters (DTLS fingerprint)
- The ICE credentials (
ufragandpwd— the username fragment and password used in STUN binding requests) - The transport addresses (host/srflx/relay candidates)
- The SSRCs (Synchronization Source identifiers) of the streams the offerer will send
A trimmed example offer:
v=0
o=- 4611732541 1 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE 0 1
a=ice-ufrag:Y2zL
a=ice-pwd:AS9JfTLkP4dXc0L9p7pG6Q2x
a=fingerprint:sha-256 7C:2B:...:A1
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtpmap:111 opus/48000/2
a=fmtp:111 useinbandfec=1
a=setup:actpass
a=mid:0
a=sendrecv
a=rtcp-mux
m=video 9 UDP/TLS/RTP/SAVPF 96 97
c=IN IP4 0.0.0.0
a=rtpmap:96 VP9/90000
a=rtpmap:97 H264/90000
a=fmtp:97 profile-level-id=42e01f
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 transport-cc
a=setup:actpass
a=mid:1
a=sendrecv
a=rtcp-mux
Walking the lines: v=0 is the SDP version. m=audio 9 UDP/TLS/RTP/SAVPF 111 declares an audio media line; the 9 is a placeholder port (real port comes from ICE), UDP/TLS/RTP/SAVPF is the protocol stack (UDP carrying DTLS-protected RTP with SAVPF feedback), and 111 is the dynamic payload type. rtpmap:111 opus/48000/2 maps payload type 111 to Opus codec at 48 kHz, 2 channels. The video media line offers two codecs: VP9 (payload 96) and H.264 (payload 97). The rtcp-fb lines advertise feedback messages the offerer will accept: nack (negative acknowledgement, used to request retransmits), nack pli (Picture Loss Indication, used to request a fresh keyframe after severe loss), transport-cc (transport-wide congestion control feedback, the modern bandwidth estimation feedback). setup:actpass means “I can play either DTLS role” — let the answerer pick. mid:0 and mid:1 are unique IDs for each media line, used by the BUNDLE mechanism to multiplex everything onto one transport.
The answer is structurally identical but with concrete choices: the answerer picks which codecs to actually use, picks its DTLS role (setup:active or setup:passive), and supplies its own ICE credentials and fingerprint. SDP offer/answer is simple in concept and notoriously fiddly in practice — every codec quirk, every browser version, and every interop issue reveals itself as an SDP bug.
5. The Codec Mix
WebRTC mandates a baseline codec set (RFC 8834):
Audio:
- Opus (RFC 6716). Mandatory. Co-developed by Xiph and Skype, royalty-free, optimized for both speech (≥ 6 kbps) and music (up to 510 kbps). Variable bitrate, 5–60 ms frame size, in-band FEC. Universally used in WebRTC apps for voice.
- G.711 (PCMU/PCMA). Mandatory for legacy interop with PSTN. Low-quality, fixed 64 kbps.
Video:
- VP8 (Google, 2010). Mandatory. Royalty-free.
- H.264 Constrained Baseline. Mandatory since 2018 after the patent-licensing situation was resolved. Hardware-accelerated on most devices.
- VP9 (Google, 2013). Optional but widely supported. Used in Google Meet for SVC.
- AV1 (Alliance for Open Media, 2018). Optional, growing adoption. Royalty-free, 30% better compression than VP9.
- H.265 / HEVC — not a WebRTC codec due to patent-licensing pain.
The codec wars between VP8/VP9/AV1 (Google, royalty-free) and H.264/H.265 (MPEG-LA, royalty-bearing) have shaped WebRTC profoundly. The mandatory dual VP8 + H.264 baseline is a legacy of the standoff: every implementation must support both, but device manufacturers disagree on which to hardware-accelerate, leading to subtle interop issues.
6. Topology Choices for N > 2
WebRTC’s P2P model works beautifully for two participants. For N participants, three architectures emerge:
6.1 Mesh — full P2P
Each participant connects to every other. For N participants, each maintains (N-1) PeerConnections, each uploading one stream and downloading (N-1). Total client uplink = (N-1) × bitrate.
| N | Uplink at 1 Mbps/stream | Practical? |
|---|---|---|
| 2 | 1 Mbps | yes |
| 3 | 2 Mbps | yes for most home connections |
| 5 | 4 Mbps | borderline; many residential uploads cap here |
| 10 | 9 Mbps | impractical |
| 50 | 49 Mbps | absurd |
Mesh is the WebRTC textbook example but rarely deployed beyond ~5 participants. The other failure mode is encoding cost: encoding the same source N-1 times (each peer wants its own resolution/bitrate adapted to its connection) saturates the CPU.
6.2 SFU — Selective Forwarding Unit
A central server receives every uploaded stream and forwards (without decode) to other participants based on each receiver’s subscription. From the SFU’s perspective, it’s a router. Each participant uploads ONE stream (or a few simulcast layers — see Adaptive Bitrate Streaming) and downloads (N-1).
The SFU never touches the encoded bytes (mostly — it does rewrite RTP headers for SSRC remapping). Server CPU is low; server bandwidth is high (proportional to N² aggregate fanout). Per-receiver quality adaptation is possible: send the high-resolution simulcast layer of the active speaker, low-resolution layers of others.
The SFU has become the dominant WebRTC topology for group calls. Production SFUs include Jitsi Videobridge, Janus, mediasoup, LiveKit, and proprietary implementations at Discord, Google Meet, Zoom (for browser clients). Video Conferencing System Design develops the SFU architecture in depth.
6.3 MCU — Multipoint Control Unit
A central server receives every stream, decodes them all, composes a single video (e.g., a 2×2 grid layout), re-encodes the composite, and sends one output stream to each participant. Each client uploads one and downloads one, regardless of N.
Server CPU is high (one full transcode per meeting × N output customizations if quality varies). Latency adds the encode/decode delay. Quality is one-size-fits-all (no per-receiver adaptation). MCU is mostly used today for SIP gateway interop and for server-side recording (where you want a composite video file output).
| Topology | Server CPU | Server BW | Client upload | Client download | Latency |
|---|---|---|---|---|---|
| Mesh | none | none | (N-1) streams | (N-1) streams | low |
| SFU | low | high (N²) | 1 stream | (N-1) streams | low |
| MCU | high | medium | 1 stream | 1 stream | medium |
7. NAT Traversal — Why It’s a Problem
The bulk of the residential and corporate Internet sits behind Network Address Translation (NAT) — many private IPs share one public IP. NAT translates outgoing connections by allocating ephemeral port mappings, but inbound connections are blocked unless the NAT remembers an existing outbound mapping.
P2P breaks this assumption: A wants to receive a UDP packet from B, but A’s NAT has no inbound mapping for B’s IP unless A first sent something to B, and B has the same problem.
WebRTC’s solution is the NAT Traversal suite: STUN (discover your public-side mapping), TURN (relay through a public server when direct connectivity fails), and ICE (the meta-protocol that gathers candidates and tries them). See the dedicated note for full details. The headline numbers: ICE typically succeeds without TURN for ~85–90% of WebRTC connections; the remaining 10–15% need TURN, which costs the application provider (TURN bandwidth is server bandwidth, not free P2P bandwidth).
8. Security Architecture
WebRTC has mandatory encryption end-to-end (in the literal P2P case): DTLS-SRTP. The DTLS handshake runs after ICE selects a working candidate pair; the resulting symmetric keys feed SRTP for media encryption. This is non-optional — there is no plaintext WebRTC.
Additional security features:
- Mandatory consent prompts. Browsers require explicit user consent for camera/mic access. The permission UI is browser-controlled; applications cannot bypass it.
- Origin-bound permissions. Permissions are scoped to the origin (https://example.com), not to the page, so cross-origin frames can’t silently grab the user’s camera.
- Identity providers (optional). RFC 8827 defines an identity-binding extension where a third-party identity provider signs the DTLS fingerprint. Rarely used in practice.
- Transport-level encryption is end-to-end in the P2P case — no server can decrypt. In the SFU case, the SFU has the keys (it terminates DTLS with each participant); true end-to-end encryption requires Insertable Streams or similar payload-encryption schemes (covered in Video Conferencing System Design).
The flip side: the mandatory permissions and encryption are hostile to enterprise deployment scenarios where endpoint logging or compliance scanning is required. Various proposals to permit “lawful intercept” have been rejected by the working group as inconsistent with the security model.
9. Real-World Deployments
Google Meet. Built by Google, on Google’s WebRTC stack. Uses VP9 SVC for video; Opus for audio. SFU architecture; SFU fleet runs in Google datacenters globally. Browser clients use stock WebRTC; native apps use Google’s optimized port of the same stack.
Discord (voice). Discord’s 2017 engineering blog documents the architecture: ~2.5M concurrent voice users on WebRTC (now well over 5M). Discord uses server-side mixed audio through their own SFU/MCU hybrid (decode all incoming, mix, re-encode), routing channels by guild ID via Consistent Hashing. Erlang/Elixir gateway. Opus audio; selective receive based on which users the listener has prioritized.
Zoom (browser client). Zoom’s native apps use a proprietary stack, but the browser client uses WebRTC. Connects to Zoom’s SFU-style media router.
Microsoft Teams. Browser client uses WebRTC; native client uses the Microsoft media stack (descended from Skype for Business). Both connect to the same back-end.
Twilio Programmable Video, Daily, LiveKit, Agora, Vonage, 100ms, Whereby, Jitsi Meet. All WebRTC platforms-as-a-service or open products. They differ in pricing, geographic PoP density, codec support, and how much they expose vs hide.
Cloudflare Stream WebRTC ingest. Cloudflare added WebRTC-based “WHIP” (WebRTC-HTTP Ingestion Protocol) ingest in 2022; live broadcasters can push via WebRTC instead of RTMP. End-to-end latency is sub-second versus RTMP+HLS at 5+ s.
Snapdrop, ShareDrop. P2P file transfer over WebRTC data channels. The data channels carry binary chunks; signaling matches peers on the same network.
Multiplayer browser games. WebRTC data channels for low-latency state synchronization; some game studios use it for authoritative server connections (server is one peer, client another).
10. Pitfalls
- Signaling channel design is an unsolved problem per app. WebRTC says “you handle this” — every app reinvents JSON-over-WebSocket. Edge cases (offer collision when both sides send offers simultaneously; ICE restart; media track addition mid-session) require careful state machines that beginners get wrong.
- Browser version skew. WebRTC’s API has evolved; older browsers use the deprecated “Plan B” SDP semantics, newer use “Unified Plan”. Apps targeting both must abstract over them or use
adapter.js(the canonical compatibility shim). - NAT traversal failure rates. ~10–15% of users in restrictive corporate networks need TURN relay. TURN bandwidth costs the operator and adds latency. Many WebRTC startups have died of TURN-bandwidth overruns.
- Codec / hardware acceleration mismatches. A device’s hardware H.264 decoder may not handle the specific profile-level the peer offered; software fallback works but burns battery. Mobile devices with modest CPUs can struggle with VP9 encode.
- Battery drain on mobile. Continuous video encoding + decoding + radio transmission is a battery killer. Foreground apps stay alive but background WebRTC calls are aggressively throttled by mobile OSes.
- The “bandwidth estimation flap” problem. Like ABR oscillation, naive bandwidth estimators can switch simulcast layers every few seconds. Production SFUs use careful hysteresis (Google Congestion Control GCC, transport-cc feedback).
- Echo cancellation on multi-device setups. When the speaker and microphone are on different devices (laptop speaker + Bluetooth headphone mic), the echo canceller — which assumes a single-device round-trip — gets confused. Robust apps detect and disable.
- DataChannel ordering pitfalls. Setting
ordered: true, maxRetransmits: 0is contradictory (you can’t have ordered + unreliable in a useful way) — must pick. Beginners trip over this. - The
RTCPeerConnectionis non-trivial to garbage collect. Forgetting to close it leaks file descriptors, ICE agents, and DTLS sessions. Long-lived web pages with many WebRTC sessions accumulate them. - Geographic latency on P2P. P2P routing is whatever the public Internet gives you; for two peers on different continents, the route may be poor. Some apps switch to SFU-mode for geographically distant pairs to take advantage of better backbone routing through their data centers.
- No native multi-stream simulcast on H.264. VP9-SVC works in WebRTC; H.264 simulcast is an extension that not all browsers implement uniformly. Codec choice determines what topologies work.
- Mobile foreground/background transitions kill the connection. Mobile OSes suspend background apps; the WebRTC connection drops. Apps must reconnect on resume, which takes 1–3 seconds.
11. Worked Example — A Two-Person Video Call
End-to-end, hop-by-hop:
T = 0 s. User A clicks “Start Call” on a web page. The page already has a WebSocket connection to the signaling server.
T = 100 ms. getUserMedia({ video: true, audio: true }) resolves with a MediaStream. (Permission already granted; first call would add ~1 s of permission UI.)
T = 110 ms. new RTCPeerConnection({ iceServers: [...] }). pc.addTrack(...) for video and audio.
T = 115 ms. pc.createOffer() produces an SDP describing what A wants to send (Opus + VP9 + H.264, ICE credentials, DTLS fingerprint).
T = 120 ms. pc.setLocalDescription(offer). ICE gathering starts — the browser begins sending STUN binding requests to the configured STUN servers.
T = 130 ms. A’s WebSocket sends { type: 'offer', sdp: ... } to the signaling server, which forwards to B.
T = 200 ms. Meanwhile, A’s STUN servers respond with server-reflexive candidates (A’s public IP:port as seen from outside the NAT). A’s browser fires onicecandidate events; A’s WebSocket forwards these to B.
T = 350 ms. B receives the offer. pc.setRemoteDescription(offer). B already has its local stream from getUserMedia. pc.createAnswer() produces B’s SDP. setLocalDescription. ICE gathering on B’s side starts.
T = 380 ms. B’s WebSocket sends { type: 'answer', sdp: ... }. Forwarded to A.
T = 450 ms. A receives the answer. pc.setRemoteDescription(answer). Both sides now have each other’s SDPs.
T = 500 ms. Both sides have exchanged ICE candidates. ICE connectivity checks begin: each side sends STUN binding requests over each candidate pair (A’s host candidate ↔ B’s srflx candidate, etc.).
T = 600 ms. The first working candidate pair succeeds (typically the lowest-priority host-pair if peers are on the same LAN; otherwise srflx-srflx through both NATs).
T = 700 ms. DTLS handshake over the working candidate pair. Exchanges Client Hello, Server Hello, certificates, key exchange — roughly 3 round trips × 30 ms each = 90 ms.
T = 800 ms. SRTP master keys derived from DTLS handshake. Encryption initialized.
T = 810 ms. First RTP packet sent from A. Carries an Opus audio frame from A’s mic (Opus is typically the first to flow because audio frames are 20 ms and ready immediately; video is encoded at frame rate).
T = 850 ms. A’s first encoded video frame (an IDR keyframe ~40 KB) is sent. Multiple RTP packets due to MTU fragmentation.
T = 900 ms. B’s ontrack event fires; B’s <video> element is fed the incoming MediaStream and starts displaying A’s video. Reverse direction symmetric: B’s audio/video starts arriving at A.
T = 1000 ms. Steady state. RTP packets at ~30 fps × 2 directions, each ~5–50 KB, plus ~50 audio packets/sec each ~50 bytes. RTCP reports flow every 2–5 seconds for jitter and loss feedback. Bandwidth estimator monitors transport-cc feedback and adjusts encoder bitrate dynamically.
End-to-end glass-to-glass latency in steady state: ~80–150 ms (1 frame at the encoder + ~1 RTT network + 1 frame jitter buffer + 1 frame decoder). This is dramatically lower than ABR’s 5–15 s and lower than the 200 ms threshold that’s the perceptual limit for “feels like a real conversation”.
Comparison with WebSocket Protocol. WebSocket is client-server only; both sides connect to a server, and bytes route through it. Latency includes the round trip to the server. WebRTC, by contrast, is P2P after signaling — the signaling server is bypassed for the steady-state media. WebSocket runs over TCP (head-of-line blocking under loss); WebRTC runs RTP over UDP (no HOL blocking; packet losses cause selective re-request via NACK or are concealed by the codec). WebSocket carries arbitrary application messages; WebRTC carries RTP-encapsulated media + SCTP-encapsulated DataChannel. The two protocols are complementary: most WebRTC apps use WebSocket for signaling and WebRTC for media.
12. Implementations Beyond the Browser
WebRTC’s reach extends well past browsers via several major implementations:
- libwebrtc (Google). The canonical C++ implementation, lives in the Chromium tree. Used by Chrome, Edge, Brave, Opera (all Chromium-based browsers), and shipped as a standalone library by Google for native apps. Approximately 1.5 million lines of code. Periodically extracted and re-released as
libwebrtc.aar(Android) and via CocoaPods (iOS) for native mobile apps. The de facto reference implementation. - Pion (Go). Pure-Go WebRTC stack (github.com/pion/webrtc). Heavily used in server-side WebRTC: SFUs written in Go, WebRTC-based ingest endpoints (e.g., the Cloudflare Calls infrastructure), test fixtures. Notable for being orders of magnitude smaller and more readable than libwebrtc. Doesn’t include the codec implementations (ships H.264/Opus codecs as separate dependencies).
- mediasoup (Node.js + C++). SFU framework for Node.js applications. Workers are C++ (audio/video routing) controlled from a Node.js application layer. Used by LiveKit, Daily, and many smaller WebRTC products.
- Janus (C). The original open-source WebRTC server, started by Meetecho ~2014. Plugin architecture: plugins for SFU, MCU, broadcasting, recording, SIP gateway, audio bridge. Mature, battle-tested, used in production by hundreds of small-to-medium WebRTC services.
- Ant Media Server, Wowza Streaming Engine, Red5 Pro. Commercial WebRTC servers. Bundle WebRTC with RTMP, HLS, and SRT for hybrid use cases.
- Firefox’s WebRTC stack is independently implemented and contributes to the standards process; it’s the second major implementation after libwebrtc and reveals interop bugs that wouldn’t show up in a Chrome-Chrome test.
- Apple’s WebRTC implementation in Safari/WebKit is a partial fork of libwebrtc with Apple-specific modifications (codec preferences, hardware acceleration paths). Notorious for lagging Chrome on new features.
The diversity matters because interop testing between any two implementations regularly reveals SDP edge cases, codec-negotiation quirks, and ICE-trickle-timing bugs. The WebRTC test suite (wpt.fyi/webrtc) is a moving target.
13. See Also
- Video Conferencing System Design — SFU architecture, simulcast, recording, captions
- NAT Traversal — STUN/TURN/ICE in depth
- WebSocket Protocol — the typical signaling-channel transport, contrast with media transport
- Real-Time Messaging Protocol — older single-direction live ingest protocol; contrast with WebRTC’s bidirectional P2P
- Adaptive Bitrate Streaming — the high-latency cousin; WebRTC trades scale for latency, ABR trades latency for scale
- Twitch Live Streaming System Design — the cross-link between RTMP-based ingest and WebRTC-based ingest experiments
- YouTube Video Streaming System Design — DASH-based egress; YouTube Live is RTMP ingest; YouTube Lite is exploring WebRTC ingest
- Netflix Streaming System Design — pure ABR; no WebRTC involvement (Netflix has no real-time interaction)
- Content Delivery Network System Design — orthogonal to WebRTC (CDNs cache static segments; WebRTC bypasses them)
- Consistent Hashing — used by Discord to route guild voice to backend SFU processes
- Major System Designs MOC
- SWE Interview Preparation MOC