The Call That Hasn't Started Yet
A technical companion to the WebRTC connection journey: signaling, SDP, Offer/Answer, ICE, STUN, TURN, Trickle ICE, and connectivity debugging. What this article adds The Medium article follows a WebRTC connection as a story. This companion gets closer to the implementation. We will build a small two-browser WebRTC application with: a WebSocket signaling server SDP Offer/Answer negotiation trickled ICE candidates a WebRTC DataChannel connection-state logging no framework and no build step The key distinction is simple: Signaling carries the information needed to establish the connection. WebRTC carries the actual peer data once connectivity is established. 1. Architecture Signaling WebSocket Server / \ / \ ▼ ▼ Alice Browser Bob Browser │ │ │ WebRTC │ └───────────────┘ Peer Connection The signaling server forwards: SDP offers SDP answers ICE candidates room information It does not automatically become the media or DataChannel path. 2. Project webrtc-demo/ ├── server.js └── public/ └── index.html Create it: mkdir webrtc-demo cd webrtc-demo npm init -y npm install ws mkdir public 3. Signaling server Create server.js : const http = require ( " http " ); const fs = require ( " fs " ); const path = require ( " path " ); const WebSocket = require ( " ws " ); const PORT = 8000 ; const server = http . createServer (( req , res ) => { const file = path . join ( __dirname , " public " , req . url === " / " ? " index.html " : req . url ); fs . readFile ( file , ( error , data ) => { if ( error ) { res . writeHead ( 404 ); res . end ( " Not found " ); return ; } res . writeHead ( 200 , { " Content-Type " : " text/html " }); res . end ( data ); }); }); const wss = new WebSocket . Server ({ server }); const rooms = new Map (); wss . on ( " connection " , ( socket ) => { let roomId = null ; socket . on ( " message " , ( rawMessage ) => { let message ; try { message = JSON . parse ( rawMessage ); } catch { return ; } if ( message . type === " join " ) { roomId = message . room ; if