LabHub

Blog

WebRTC Media Infrastructure 2026 — LiveKit·Pion·Daily·100ms·mediasoup·Janus·Cloudflare Realtime and WHIP/WHEP Deep Dive

한국어English日本語

Prologue — WebRTC is 90% an infrastructure choice

In 2018, WebRTC was the problem of "how do I write a P2P video call in the browser". One STUN/TURN server, 200 lines of RTCPeerConnection code, a demo page with two video boxes. Done.

In 2026, WebRTC is a different problem.

This piece is not about "200 lines of WebRTC code". It is about "where and how do you run production media infrastructure". That one decision sets your infra cost, latency and operational burden for the next six months.

Summary — the big picture as of May 2026.

Let's start.


1. The WebRTC Infrastructure Landscape — The 2026 Map

First, classification. Not everything is in the same place.

CategoryRepresentative productOne-line summary
AI voice/video infra (managed + OSS)LiveKit Cloud / LiveKit OSSThe 2026 voice-agent standard. Agents framework.
Managed video APIDaily.co, 100ms, Twilio Video, AWS Chime SDK, VonageSDK plus managed SFU. Fast time to ship.
Edge WebRTCCloudflare Realtime / CallsGlobal edge SFU. New category.
Self-host SFU (Node.js)mediasoupLibrary form. You write the signaling yourself.
Self-host SFU (C)JanusPlugin architecture. The OG.
Full-stack OSSJitsi (Meet / Videobridge)A meeting solution plus SFU you download and run.
WebRTC engine (Go)PionThe library that made WebRTC writable in Go.
WebRTC engine (Rust)webrtc-rsThe Rust port of Pion. Growing.
Live ingestion standardWHIP / WHEPStart a WebRTC session with a single HTTP request. RTMP replacement.

The focus of this piece is the bolded set — LiveKit, Pion, Daily, 100ms, mediasoup, Janus, Jitsi, Twilio, Chime, Cloudflare Realtime. WHIP/WHEP gets its own chapter.

Why LiveKit became the standard


2. A 7-Axis Comparison Matrix

Before the deep analysis, the one-glance picture.

AxisLiveKitDaily100msmediasoupJanusJitsiTwilio VideoAWS Chime SDKCloudflare Realtime
Operating modelManaged + OSSManagedManagedOSS libraryOSS daemonOSS full stackManagedManagedManaged (edge)
LanguageGo (Pion)ClosedClosedNode.js + C++CJava + C (libwebrtc)ClosedClosedClosed
AI voice integrationFirst-class (Agents)GoodGoodDIYDIYDIYAverageGood (Voice Focus)DIY
WHIP/WHEPFirst-classSupportedSupportedPluginPluginExternal toolNot supportedNot supportedFirst-class
Global routingFirst-class in CloudFirst-classFirst-classDIYDIYDIYFirst-classFirst-classFirst-class (edge)
Price pressureStrong (OSS + Cloud)AverageAverageInfra cost onlyInfra cost onlyInfra cost onlyExpensiveExpensiveNew
New adoption trendVery strongStableStrong (India market)StableDecreasingStableDecreasingStableRapid growth

Don't decide off this table alone. The next chapters pin down what each tool can and cannot do.


3. LiveKit — Why It Became the Standard, and LiveKit Agents

LiveKit, born in 2021, is the WebRTC infrastructure that found its place the fastest. It runs both an OSS (Apache 2.0) and LiveKit Cloud track. Two decisive events happened between 2025 and 2026.

  1. The LiveKit Agents framework — Python and Node SDKs that bundle LLMs, STT, TTS and VAD to build voice agents. OpenAI Realtime API, Deepgram, AssemblyAI, ElevenLabs, Cartesia, and more integrate first-class.
  2. OpenAI officially adopted LiveKit — It came out publicly that the infrastructure behind ChatGPT voice mode runs on LiveKit. A de facto industry stamp.

Why LiveKit is strong

A LiveKit Agents skeleton

The simplest shape of a single voice agent. The code pipes microphone audio into OpenAI Realtime and sends the model's response audio back into the room.

# agent.py — minimal LiveKit Agents skeleton
import asyncio
import os
from livekit import agents, rtc
from livekit.agents import AgentSession, Agent
from livekit.plugins import openai, deepgram, elevenlabs, silero

class VoiceAssistant(Agent):
    def __init__(self) -> None:
        super().__init__(
            instructions=(
                "You are a friendly voice assistant. "
                "Answer in short, conversational sentences."
            ),
        )

    async def on_enter(self) -> None:
        # Auto-greet the user
        await self.session.say("Hi there, how can I help you?")

async def entrypoint(ctx: agents.JobContext) -> None:
    await ctx.connect()  # join the room

    session = AgentSession(
        # 1) STT — Deepgram nova-3
        stt=deepgram.STT(model="nova-3"),
        # 2) LLM — OpenAI Realtime, or plain chat completions
        llm=openai.LLM(model="gpt-4o-mini"),
        # 3) TTS — ElevenLabs
        tts=elevenlabs.TTS(voice_id="Rachel"),
        # 4) VAD — Silero voice activity detection (turn taking)
        vad=silero.VAD.load(),
    )

    await session.start(
        agent=VoiceAssistant(),
        room=ctx.room,
    )

if __name__ == "__main__":
    agents.cli.run_app(
        agents.WorkerOptions(entrypoint_fnc=entrypoint),
    )

To deploy, run python agent.py dev locally, then python agent.py start in production. When the LiveKit server creates a new room, the Agents worker is matched automatically and joins.

OpenAI Realtime + WebRTC direct mode

OpenAI's Realtime API launched in 2024 with WebSocket only. In 2025 a WebRTC connection mode was added. A client crafts an SDP and posts it directly to the OpenAI endpoint; the model responds like an SFU. Latency drops to 200–400 ms.

LiveKit Agents abstracts both options.

# Using OpenAI Realtime as a direct WebRTC connection
from livekit.plugins import openai

session = AgentSession(
    llm=openai.realtime.RealtimeModel(
        model="gpt-4o-realtime-preview",
        voice="alloy",
        # WebRTC mode — no separate STT/TTS needed
        modalities=["audio", "text"],
    ),
)

In this mode you don't need separate STT/TTS — the model handles audio in and out itself. Downsides: pricing is higher, and your model choice is locked to the OpenAI Realtime lineup.

LiveKit's weaknesses


4. Pion — The WebRTC Engine of Go

Pion is a full WebRTC implementation written in Go. First public in 2018. LiveKit, Galene, ion-sfu, and even OBS WHIP egress all sit on Pion. Go's single-binary, concurrency, and cross-compilation advantages match media-server operations well.

Why Pion

The simplest SFU peer fragment in Pion

The minimal shape of one peer taking one sender's track and forwarding it to another participant. A real SFU adds track routing, simulcast, DataChannel, and reconnection logic.

// sfu_peer.go — a 1-to-1 track-forwarding fragment in Pion
package main

import (
    "fmt"
    "github.com/pion/webrtc/v4"
)

func newPeer() (*webrtc.PeerConnection, error) {
    api := webrtc.NewAPI()
    pc, err := api.NewPeerConnection(webrtc.Configuration{
        ICEServers: []webrtc.ICEServer{
            {URLs: []string{"stun:stun.l.google.com:19302"}},
        },
    })
    if err != nil {
        return nil, err
    }

    // Take incoming track and forward it as an outgoing track
    pc.OnTrack(func(remote *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
        // Create an outgoing track (assume VP8)
        local, err := webrtc.NewTrackLocalStaticRTP(
            remote.Codec().RTPCodecCapability,
            "video",
            "pion-sfu",
        )
        if err != nil {
            return
        }
        if _, err := pc.AddTrack(local); err != nil {
            return
        }

        // Forward RTP packets as-is
        buf := make([]byte, 1500)
        for {
            n, _, readErr := remote.Read(buf)
            if readErr != nil {
                return
            }
            if _, writeErr := local.Write(buf[:n]); writeErr != nil {
                return
            }
        }
    })

    pc.OnICEConnectionStateChange(func(s webrtc.ICEConnectionState) {
        fmt.Println("ICE state:", s.String())
    })

    return pc, nil
}

The limits are clear. It handles only 1-to-1, doesn't take simulcast (multi-resolution tracks), and has no signaling. Still, it shows how direct Pion feels.

Projects on Pion


5. mediasoup — Node.js's Standard SFU Library

mediasoup is the SFU library for the Node.js world. The important point: it isn't a daemon — it's a library you import into a Node process. The worker is written in C++, and the JS layer orchestrates it.

Why mediasoup

mediasoup's downsides

I only recommend mediasoup when the team includes an engineer who deeply understands media infrastructure. Writing a mediasoup stack to fill a slot that LiveKit or managed would have covered tends to burn about six months.


6. Janus — The OG SFU Written in C

Janus, released in 2014, is a C-based SFU. The OG of WebRTC infrastructure, with a plugin architecture as its trademark.

Where Janus sits


7. Jitsi — The Full-Stack OSS Meeting Solution

Jitsi is a full-stack OSS meeting solution. One download and you get Jitsi Meet (web UI) plus Videobridge (SFU) plus Jicofo (signaling) plus Prosody (XMPP), all as one bundle that runs together.

Alternate use cases


8. The Managed Camp — Daily, 100ms, Twilio Video, AWS Chime SDK

The big pattern across managed video APIs is similar. SDK + server SDK + managed SFU + recording + analytics. But strengths diverge.

Daily.co

100ms

Twilio Video

AWS Chime SDK

Cloudflare Realtime / Calls


9. WHIP/WHEP — The New Standard Replacing RTMP

Live ingestion was long RTMP's seat. RTMP was made by Adobe in 2002, in the era of H.264 and Flash, and three weaknesses became decisive.

WHIP (WebRTC-HTTP Ingestion Protocol) and WHEP (WebRTC-HTTP Egress Protocol) are the answer. IETF-standardized.

How WHIP works

  1. The publisher posts an SDP offer to the server over HTTP POST.
  2. The server returns an SDP answer with 200 OK.
  3. Once DTLS/SRTP negotiation completes, media starts flowing.

That's the whole thing. Signaling is one HTTP round trip. No need to spin up WebSockets or a separate signaling server.

A WHIP publishing client — fetch-and-done

// whip-publisher.js — publish microphone and camera over WHIP
async function publishWHIP(endpoint, token) {
  const pc = new RTCPeerConnection({
    iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  });

  // Add local media
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: { width: 1280, height: 720 },
  });
  stream.getTracks().forEach((track) => pc.addTrack(track, stream));

  // Create the SDP offer
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  // Wait for ICE gathering to complete (simplified)
  await new Promise((resolve) => {
    if (pc.iceGatheringState === 'complete') return resolve(null);
    pc.addEventListener('icegatheringstatechange', () => {
      if (pc.iceGatheringState === 'complete') resolve(null);
    });
  });

  // POST the SDP to the WHIP endpoint
  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/sdp',
      Authorization: `Bearer ${token}`,
    },
    body: pc.localDescription.sdp,
  });

  if (!response.ok) {
    throw new Error(`WHIP failed: HTTP ${response.status}`);
  }

  // Set RemoteDescription from the server's answer
  const answer = await response.text();
  await pc.setRemoteDescription({ type: 'answer', sdp: answer });

  return pc;
}

// Usage
const pc = await publishWHIP(
  'https://ingest.example.com/whip/my-stream',
  'my-token',
);

Where WHIP/WHEP took root

Why WHIP/WHEP replaces RTMP


10. SFU vs MCU vs P2P — The Topology Decision

The topology of WebRTC infrastructure is a huge decision axis.

TopologyHow it runsWhen it fits
P2P meshEvery participant connects directly to every other2–3 people. Very small.
P2P starOne host sends to every other participant1-to-N streaming. Host upload bound.
SFUThe server receives incoming streams and forwards them to other participants as-isMeetings, webinars, live. The de facto standard.
MCUThe server decodes, mixes and re-encodes all streams into one compositePhone conferences. Lowest client load.

Why SFU is the standard

MCU's place

P2P's place


11. The Codec Landscape — Opus, VP8, VP9, AV1, H.264, H.265

WebRTC's mandatory codecs are Opus for audio and VP8/H.264 for video. The rest is optional.

Audio

Video

Simulcast and SVC

Decisions


12. Managed vs Self-Host Decision Matrix

The one big decision. This matrix is the guide.

SituationRecommendationReason
MVP, ship inside 6 monthsManaged (LiveKit Cloud, Daily, 100ms)Don't spend your time on media infrastructure
Voice-agent-centric (LLM, STT, TTS)LiveKit (Cloud or OSS)The Agents framework is waiting
Internal company meeting solutionJitsi self-hostedThe "solution" lands as-is
WHIP live ingestionLiveKit Ingress or Cloudflare RealtimeFirst-class WHIP support
Global distribution, edge routingCloudflare Realtime or LiveKit CloudSFU on the edge
Minimize infrastructure cost (mid-scale)LiveKit OSS self-hostedAvoid managed per-minute pricing
Total control over signaling and routingmediasoupLibrary-shaped, every decision is yours
Deep AWS ecosystem integrationAWS Chime SDKSyncs with IAM, S3, CloudWatch
Telephony (PSTN) integrationTwilio Voice + LiveKit SIPTwilio Voice is alive
India and Southeast Asia pricing100msPrice competitiveness

Signals to move from managed to self-hosted

The hidden costs of self-hosting


13. Client-Side Libraries

The client matters as much as the server. Half the decision.

Plain RTCPeerConnection

LiveKit Client SDK

Daily's call-frame

mediasoup-client

Janus's JS adapter

simple-peer


14. Operations — TURN, NAT, Monitoring

Half of operations goes into signaling, NAT, and observability.

STUN and TURN

Observability via getStats()

Call-quality KPIs


15. Live-Streaming Scenarios

Live broadcast has settled into a separate area of WebRTC infrastructure. Per-scenario recommendations.

ScenarioPublishingRoutingReceiving
One speaker → 10,000 viewersOBS WHIP egressLiveKit or Cloudflare Realtime SFUHLS transcode, then HLS viewers
One speaker → 100 interactiveOBS WHIP egressLiveKit SFUWHEP receive
Multi-party meeting recording → broadcastLiveKit RoomLiveKit EgressHLS transcode
Gameplay broadcast → interactive chatOBS WHIPCloudflare RealtimeWHEP or HLS

Where WebRTC live replaces RTMP live, and where it doesn't


16. Security, DRM, and E2EE

WebRTC is DTLS-SRTP encrypted by default. Media packets are always encrypted between client and server. But in SFU mode the SFU does see plaintext for routing decisions (codec info, simulcast layer selection, and so on).

E2EE — Insertable Streams

DRM


17. Case Study — A Full-Stack AI Voice Agent

What happens when these tools come together? The most common scenario.

[User browser]
    |
    | WebRTC audio in/out
    v
[LiveKit Server]
    |
    | LiveKit Agents worker joins the room automatically
    v
[Agents Worker (Python)]
    |
    +-- Deepgram STT (streaming)
    +-- OpenAI gpt-4o-mini (LLM)
    +-- ElevenLabs TTS (streaming)
    +-- Silero VAD (turn taking)
    |
    | Sends TTS audio back into the LiveKit room
    v
[User browser — immediate playback]

Latency breakdown (target: under 700 ms)

Total: 500–1,000 ms. About the limit at which people feel "this is a conversation".

OpenAI Realtime + WebRTC direct mode

In the picture above Deepgram, OpenAI, and ElevenLabs collapse into one model. Latency drops to 200–400 ms.

[User browser]
    |
    | Direct WebRTC audio
    v
[OpenAI Realtime endpoint]
    |
    | The model handles audio input/output itself
    v
[User browser — response audio]

The trade-off

Most production systems run both. Fast conversation uses Realtime, while tool-calling and custom TTS run on a plain LLM plus separate STT/TTS.


18. Common Anti-Patterns

Things I have seen far too often.

  1. Trying to run a 4+ person room on P2P mesh — it collapses at 5. Go SFU from day one.
  2. Shipping without a TURN server — the moment users come in from behind corporate networks, call-failure rate hits 30%.
  3. Disabling simulcast and broadcasting one resolution — in a 10-person room, one person on mobile 4G drops everybody.
  4. Treating getUserMedia permission as "one and done" — permission changes per page and per session. Re-check every time.
  5. Trying to run the SFU inside one WebSocket signaling process — signaling is signaling and media is media. Don't merge them.
  6. Skipping WebRTC stats collection — one user reports "it's choppy" and you can't reproduce. Collect getStats() once a minute.
  7. Cramming recording/transcoding into the SFU process — one encoding session stalls the entire SFU. Split into a separate worker.
  8. Weak VAD in AI voice agents — the model interrupts before the user finishes, or doesn't respond when they do.
  9. Accepting only RTMP among WHIP/RTMP/SRT — in 2026 you can't push AV1 or VP9 over RTMP. Add WHIP as an option.
  10. Self-hosted with monitoring limited to 5 PromQL metrics — media-server observability runs a level deeper than general web servers.

19. The Big Picture — What Became the Standard

The summary as of May 2026.

Decision checklist

Anti-pattern summary

  1. 4+ people on P2P mesh.
  2. Shipping without TURN.
  3. Disabling simulcast.
  4. No WebRTC getStats() collection.
  5. Signaling, SFU, recording, and transcoding in one process.
  6. Weak VAD in AI agents.
  7. Receiving only RTMP (no WHIP).
  8. Forcing MCU in large rooms.
  9. Mixing managed and self-hosted without a decision.
  10. Enabling E2EE while expecting server-side recording to work.

Next post preview

Candidates for the next post: LiveKit Agents deep — token-streaming, tool calling, interruption handling, A month operating WHIP/WHEP ingestion — comparing OBS, Cloudflare, and LiveKit, 100 WebRTC getStats() metrics — what to watch and what to ignore.

"WebRTC is not one standard but a bundle of standards. The teams that can operate the bundle go the farthest."

— WebRTC Media Infrastructure 2026, end.


References

Comments

No comments yet.

Sign in to leave a comment