Skip to content

How it works ​

Two peers join the same room through a small WebSocket signaling server. The server only relays control messages: the SDP offer and answer, ICE candidates and the E2EE key. Audio, video and chat go directly between the peers over WebRTC. Google's public STUN server helps each peer find its public address.

That is the default mode: a room holds two people. Group calls are an optional mode where everyone connects to a small SFU server instead.

The pieces ​

PieceTechStart reading at
Signaling serverNode.js, wsserver.js
SFU server (optional)Go, Pionsfu-server/
WebVue 3, TypeScript, ViteuseCall.ts
AndroidKotlin, Jetpack Compose, webrtc-sdkPeerConnectionClient.kt
iOSSwift, SwiftUI, webrtc-sdkPeerConnectionClient.swift
macOSSwift, SwiftUI + AppKit, the iOS engineWebRTCDemoMacApp.swift
WindowsC#, WinUI 3, libwebrtc through a C shimCallViewModel.cs
UI
Vue 3, Tailwind CSS, shadcn-vue
WebRTC
The browser's own RTCPeerConnection
Signaling socket
WebSocket
Camera
getUserMedia()
Screen sharing
getDisplayMedia()
Switching sources
RTCRtpSender.replaceTrack()
E2EE
Insertable Streams or RTCRtpScriptTransform, in a worker
Backgrounds and stickers
MediaPipe ImageSegmenter + FaceLandmarker, canvas 2D
Picture-in-picture
Document Picture-in-Picture API, video PiP fallback
Everything about this platform →

Rules every client follows ​

These few decisions are what let five independent apps call each other. Each one has its own page.

  • The peer already in the room makes the offer. The one who joins second answers. Nobody ever offers at the same time. Signaling
  • The chat channel is created before the first offer, so opening the chat never renegotiates. Chat
  • Switching between camera, screen and file never renegotiates. The video sender stays, only what feeds it changes. Switching video sources
  • Camera state travels as a message. A disabled track still sends black frames, so each side tells the other with media state, 300 ms before or after the track changes. Camera and mic state
  • E2EE uses one frame format and one set of key options, and VP8 goes first when it is on. End-to-end encryption
  • No reconnect. If the signaling socket closes, the call ends. Signaling

The full repository layout, with every file and what it does, is in ARCHITECTURE.md.