Real-Time Communication — WebSocket, gRPC Streaming and WebRTC
WebRTC — you build the signaling yourself
In one line
WebRTC does not specify how to establish a connection, so you build the signaling that hands over the SDP yourself, find a path with ICE, exchange keys with DTLS, and then carry media with SRTP and data channels with SCTP.
Why this was needed
To make two devices talk to each other directly, there are three problems to solve. How do they announce each other's address and capabilities (signaling), by what path do they reach each other when both are behind NAT (ICE, STUN, TURN), and how do you protect the data on that path (DTLS-SRTP). WebRTC, as outlined by RFC 8825, fixed the latter two but deliberately left the first blank. JSEP (RFC 9429) only specifies how the browser produces the SDP offer and answer, and leaves to the application how to hand them to the other side. So almost every service keeps a small signaling server of its own, such as over WebSocket.
How it works
The SDP offer and answer. The offering side decides what it will send (an audio track, a data channel) and then creates the SDP with createOffer. If you don't decide what to send, it becomes an empty offer with no m= line. The SDP holds, for each medium, the m= line, the codec (a=rtpmap), the ICE credentials (a=ice-ufrag and a=ice-pwd), the fingerprint of the DTLS certificate (a=fingerprint), the DTLS role (a=setup:actpass, active, passive), and the candidates (a=candidate). The answering side puts the received offer into setRemoteDescription and replies with createAnswer.
ICE candidates. ICE (RFC 8445) gathers all possible addresses (candidate gathering), pairs them up and tries connectivity checks, and picks one of the pairs that work. There are three kinds of candidates.
| Kind | Where it comes from | Meaning |
|---|---|---|
| host | Its own interface | Within the same network, this is enough |
| srflx | The address a STUN server saw | The external address the NAT assigned |
| relay | An address lent by a TURN server | When there is no direct path, the server carries the data on your behalf |
A STUN (RFC 8489) server only returns "the address I saw you at" as XOR-MAPPED-ADDRESS in response to a Binding request and does not carry data. On a symmetric NAT or a network where UDP is blocked, even that address cannot be reached, so a TURN (RFC 8656) server lends a relay address and carries all the data for you. TURN costs bandwidth, but without it some users cannot connect at all. For places where UDP is blocked, TURN is also opened over TCP and TLS 443. There are two ways: sending the SDP after gathering all the candidates, and trickle ICE, which sends them separately as they are gathered. The aiortc used in the lab is the former, so if you configure a STUN server that cannot be reached, the offer is delayed by several seconds waiting for its response.
DTLS-SRTP and SCTP. Once the path is decided, the DTLS handshake takes place over it. The hash of the certificate the other side presents has to match the a=fingerprint received through signaling, and this prevents a man-in-the-middle attack. RFC 8827 requires all media to be encrypted, and the media keys are extracted from the DTLS handshake and used for SRTP (RFC 5764). Data channels flow over SCTP on top of DTLS (RFC 8831), and for each channel you can set separately whether order is guaranteed and the retransmission limit (maxRetransmits) or lifetime (maxPacketLifeTime). For data that is useless after 20ms, like a voice frame, it is better to send it unordered and without retransmission.
Media tracks. Audio flows over RTP. RFC 7874 specifies Opus and G.711 as the audio codecs WebRTC must implement, and RFC 7587 has Opus written as opus/48000/2 in the SDP regardless of the input sample rate.
What it looks like in the field
Jitter and loss. Voice has no room to wait for retransmission, so the receiving side absorbs the fluctuation in arrival intervals with a jitter buffer, and fills a lost frame from the sound before and after (loss concealment). A larger buffer reduces breakups, but every sound is delayed by that much. ITU-T G.114 holds that a one-way delay of 150ms or less is fine for most conversations. "It can't connect only on the company network" is usually the case where UDP is blocked and there is no TURN, or TURN is open only over UDP, and "5 seconds to connect" is the case of waiting on an unreachable STUN.
What you will do in the next lab
You build a WebSocket signaling server, create an answering peer and an offering peer with aiortc, and exchange messages with a reference peer over a data channel. You change the channel to an unordered, no-retransmission one, and measure how an srflx candidate appears with a STUN server in the same Pod and how a blocked STUN delays gathering.