patterntypescriptModerate
WebRTC Signaling Channel Must Be Established Before Offer/Answer Exchange
Viewed 0 times
webrtcsignalingSDPoffer answersetLocalDescriptionsetRemoteDescriptionpeer negotiation
Problem
Two peers need to exchange SDP offer/answer to negotiate codecs and media capabilities, but WebRTC itself provides no signaling transport — developers must build it themselves.
Solution
Build a signaling layer (WebSocket, SSE, or HTTP polling) to relay SDP and ICE candidates between peers. The initiating peer creates an offer, the remote peer answers. Both call setLocalDescription() and setRemoteDescription() in the correct order.
// Caller side
async function startCall(signalingChannel: WebSocket, pc: RTCPeerConnection) {
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
signalingChannel.send(JSON.stringify({ type: 'offer', sdp: offer.sdp }));
}
// Callee side
async function handleOffer(signalingChannel: WebSocket, pc: RTCPeerConnection, offer: RTCSessionDescriptionInit) {
await pc.setRemoteDescription(new RTCSessionDescription(offer));
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
signalingChannel.send(JSON.stringify({ type: 'answer', sdp: answer.sdp }));
}Why
WebRTC is intentionally transport-agnostic for signaling so it can be used in diverse environments. The spec only defines the peer connection API; developers choose the signaling transport that fits their infrastructure.
Gotchas
- Never call createAnswer() before setRemoteDescription() — it will throw.
- SDP strings contain newlines; JSON.stringify handles them but raw WebSocket text must not strip them.
- Re-negotiation (adding a track after call starts) requires another offer/answer cycle.
- Perfect Negotiation pattern avoids glare (simultaneous offers) with a polite/impolite peer role.
Revisions (0)
No revisions yet.