πŸ“‘

WebRTC

WHIP/WHEP primary stream Β· HLS fallback Β· VP9 / H.264 / Opus Β· Socket.IO signaling Β· MediaRecorder S3 recording

🎯 Overview

WebRTC (Web Real-Time Communication) is de kern van alle real-time audio/video features op TeezU v7.0. Primaire ingest via WHIP, delivery via WHEP β€” met HLS als automatische fallback voor legacy clients. Signaling verloopt via Socket.IO (niet raw WebSocket).

πŸ“Ή Livestream (WHIP/WHEP)

Sub-second latency via WebRTC Ingestion/Egress Protocol. OBS β†’ WHIP β†’ MediaSoup SFU β†’ WHEP kijkers.

🎀 Voice & Collab

Opus audio met echo cancellation. Tot 4 simultane deelnemers in collab stream mode via SFU.

πŸ–₯️ Screen & Recording

getDisplayMedia() voor screen sharing. MediaRecorder β†’ 10s segmenten β†’ AWS S3 via Fastify presigned URLs.

πŸ“‘ WHIP/WHEP Protocol

Standaard WebRTC ingest/egress protocol. Browser-native, geen plugin. <300ms end-to-end latency.

πŸ”„ HLS Fallback

Automatische fallback voor legacy browsers & TV's. 5–10s latency, adaptive bitrate 360p/720p/1080p.

🎭 Freeze & Reveal

Server-side state machine via Fastify. LIVE β†’ FROZEN (blauwe glow) β†’ REVEAL (confetti animatie).

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              CLIENT A                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚ Browser  β”‚β†’ β”‚MediaStreamβ”‚β†’ β”‚RTCPeerConβ”‚     β”‚
β”‚  β”‚   API    β”‚  β”‚   API     β”‚  β”‚ nection  β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   SIGNALING SERVER         β”‚
                    β”‚   (Socket.io)              β”‚
                    β”‚   - Offer/Answer           β”‚
                    β”‚   - ICE Candidates         β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              CLIENT B              β”‚           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ Browser  │← β”‚MediaStream│← β”‚RTCPeerConβ”‚    β”‚
β”‚  β”‚   API    β”‚  β”‚   API     β”‚  β”‚ nection  β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     
        Direct P2P Connection (when possible)
                   Client A ↔ Client B
                   
        TURN Relay (when NAT/firewall blocks P2P)
           Client A ↔ TURN Server ↔ Client B

πŸ”§ Core Components

RTCPeerConnection

De core WebRTC API voor peer-to-peer verbindingen.

  • β€’ Creates connection between peers
  • β€’ Handles media streams
  • β€’ Manages ICE candidates
  • β€’ Negotiates codecs
  • β€’ Monitors connection state

MediaStream API

Toegang tot camera, microfoon en scherm.

  • β€’ getUserMedia() - camera/mic
  • β€’ getDisplayMedia() - screen share
  • β€’ MediaRecorder - recording
  • β€’ Audio/video tracks
  • β€’ Constraints & settings

Signaling Server

Socket.io server voor SDP exchange en ICE candidates.

  • β€’ Room management
  • β€’ SDP offer/answer exchange
  • β€’ ICE candidate relay
  • β€’ Connection status updates
  • β€’ Error handling

STUN/TURN Servers

NAT traversal en relay servers.

  • β€’ STUN - discover public IP
  • β€’ TURN - relay when P2P fails
  • β€’ Google STUN (free)
  • β€’ Coturn (self-hosted TURN)
  • β€’ Fallback strategies

πŸ“Š Connection Flow

Step-by-Step Process

1
Initialize Connection
Create RTCPeerConnection with STUN/TURN config
2
Get Media Stream
Request camera/mic access via getUserMedia()
3
Add Tracks
Add audio/video tracks to peer connection
4
Create Offer
Caller creates SDP offer and sends via signaling
5
Create Answer
Callee receives offer, creates SDP answer
6
Exchange ICE Candidates
Both peers discover and exchange network candidates
7
Connection Established
P2P connection active, media streams flowing

βš™οΈ Configuration

// ICE Server Configuration (v7.0)
const config = {
  iceServers: [
    // Google STUN servers (free, discover public IP)
    { urls: 'stun:stun.l.google.com:19302' },
    { urls: 'stun:stun1.l.google.com:19302' },
    // Custom TeezU STUN server
    { urls: 'stun:stun.teezu.online:3478' },
    // TURN relay server (NAT traversal fallback)
    {
      urls: [
        'turn:turn.teezu.online:3478',
        'turn:turn.teezu.online:5349?transport=tcp'  // TCP fallback
      ],
      username: 'teezu',
      credential: process.env.TURN_SECRET
    }
  ],
  iceTransportPolicy: 'all',   // Try P2P first, TURN as fallback
  bundlePolicy: 'max-bundle',
  rtcpMuxPolicy: 'require'
};

const peerConnection = new RTCPeerConnection(config);

// Signaling via Socket.IO (niet raw WebSocket)
socket.emit('webrtc:offer',  { sdp: offer,     roomId });
socket.on('webrtc:answer',   ({ sdp })       => pc.setRemoteDescription(sdp));
socket.on('webrtc:ice',      ({ candidate }) => pc.addIceCandidate(candidate));

πŸ“ˆ Quality & Performance

Adaptive Bitrate

Automatische aanpassing van kwaliteit op basis van netwerk condities.

  • β€’ Bandwidth estimation
  • β€’ Quality scaling (1080p β†’ 480p)
  • β€’ Frame rate adjustment
  • β€’ Audio fallback

Audio Processing

Advanced audio features voor betere spraakkwaliteit.

  • β€’ Echo cancellation
  • β€’ Noise suppression
  • β€’ Auto gain control
  • β€’ Opus codec

πŸ“‘ Streaming Protocol: WHIP/WHEP + HLS Fallback

βœ… Primary: WebRTC (WHIP/WHEP)

WebRTC Ingestion Protocol (WHIP) voor uploaden, WebRTC Egress Protocol (WHEP) voor kijkers β€” sub-second latency.

  • β€’ Latency <300ms (near real-time)
  • β€’ Browser-native, geen plugin vereist
  • β€’ OBS β†’ WHIP endpoint β†’ MediaSoup SFU
  • β€’ Kijker ontvangt via WHEP endpoint
  • β€’ Ondersteund in Chrome, Firefox, Edge

πŸ”„ Fallback: HLS (HTTP Live Streaming)

Automatische fallback voor kijkers die geen WebRTC ondersteunen (oudere browsers, smart TV's).

  • β€’ 5–10s latency (CDN-vriendelijk)
  • β€’ Adaptive bitrate: 360p / 720p / 1080p
  • β€’ Segment caching via CloudFront CDN
  • β€’ Compatibel met alle browsers & smart TV's
  • β€’ Auto-select wanneer WebRTC niet beschikbaar

🎬 Codec Priorities

πŸ₯‡

VP9 β€” Preferred Video

  • β€’ Betere compressie dan H.264
  • β€’ Open-source, royalty-free
  • β€’ Chrome / Firefox / Edge native
  • β€’ Hardware-encoding op moderne GPUs
πŸ₯ˆ

H.264 β€” Fallback Video

  • β€’ Universele hardware-ondersteuning
  • β€’ Safari & iOS compatibel
  • β€’ Hardware encoding op mobiel
  • β€’ Actief wanneer VP9 niet beschikbaar
🎡

Opus β€” Audio

  • β€’ Standaard WebRTC audio codec
  • β€’ 6–510 kbps adaptief bitrate
  • β€’ Echo cancellation ingebouwd
  • β€’ Noise suppression + auto gain control

πŸ–₯️ Screen Sharing & Recording

Screen Sharing (getDisplayMedia)

Via getDisplayMedia() API β€” kies scherm, venster of browser-tab.

// Screen share initialiseren
const screenStream = await navigator.mediaDevices
  .getDisplayMedia({
    video: {
      cursor: 'always',
      displaySurface: 'browser',
      frameRate: { ideal: 30 }
    },
    audio: true  // System audio (Chrome only)
  });

// Vervang video track in peer connection
const sender = pc.getSenders()
  .find(s => s.track?.kind === 'video');
await sender.replaceTrack(
  screenStream.getVideoTracks()[0]
);

Recording β†’ AWS S3

MediaRecorder neemt 10s segmenten op en uploadt naar S3 via Fastify presigned URLs.

// MediaRecorder setup
const recorder = new MediaRecorder(stream, {
  mimeType: 'video/webm;codecs=vp9,opus'
});

let segmentId = 0;
// Segment elke 10s uploaden naar S3
recorder.ondataavailable = async (e) => {
  if (e.data.size > 0) {
    await uploadSegmentToS3(
      e.data,
      segmentId++
    );
  }
};

recorder.start(10_000); // 10s segmenten

πŸ‘₯ Multi-stream & Freeze / Reveal

Multi-stream β€” max 4 deelnemers

Collaborative livestreams met tot 4 gelijktijdige participant-streams via MediaSoup SFU.

  • β€’ Max 4 simultane video-streams (collab mode)
  • β€’ SFU routeert efficiΓ«nt β€” geen P2P mesh overhead
  • β€’ Elke deelnemer publiceert 1 stream, ontvangt 3
  • β€’ Bandwidth-bewust: auto quality degradation
  • β€’ Room-based signaling via Socket.IO rooms
  • β€’ Host kan deelnemers muten / verwijderen

Freeze & Reveal State Machine

Server-side state machine beheerd via Fastify. Creator controleert stream visibility in real-time.

// Stream states (server-side Fastify)
// LIVE    β†’ Normale stream
// FROZEN  β†’ Video gepauzeerd (blauwe glow)
//           Audio blijft actief voor kijkers
// REVEAL  β†’ FROZEN β†’ LIVE (confetti animatie)
// OFFLINE β†’ Stream beΓ«indigd

// Client emits (creator controls)
socket.emit('stream:freeze', { streamId });
socket.emit('stream:reveal', { streamId });

// Server broadcast β†’ alle kijkers
socket.on('stream:state', ({ state }) => {
  if (state === 'FROZEN') applyBlueGlow();
  if (state === 'REVEAL') triggerConfetti();
  updateStreamOverlay(state);
});