LabHub

블로그

WebRTC 미디어 인프라 2026 — LiveKit·Pion·Daily·100ms·mediasoup·Janus·Cloudflare Realtime와 WHIP/WHEP 심층 탐구

한국어English日本語

프롤로그 — WebRTC는 인프라 선택이 90%다

2018년 WebRTC는 "브라우저에서 P2P 영상통화를 어떻게 짜는가"의 문제였다. STUN/TURN 서버 한 대, RTCPeerConnection 코드 200줄, 그리고 영상 두 칸짜리 데모 페이지. 끝.

2026년의 WebRTC는 다른 문제다.

이 글은 "WebRTC 코드 200줄"이 아니라 "프로덕션 미디어 인프라를 어디서 어떻게 굴리느냐"를 다룬다. 이 결정 한 번이 6개월 뒤의 인프라 비용·지연·운영 부담을 결정한다.

요약: 2026년 5월 기준 큰 그림은 이렇다.

자, 출발한다.


1장 · WebRTC 인프라의 풍경 — 2026년 지도

먼저 분류. 모두가 같은 자리에 있지 않다.

카테고리대표 제품한 줄 요약
AI 음성·영상 인프라(매니지드+OSS)LiveKit Cloud / LiveKit OSS2026년 음성 에이전트 표준. Agents 프레임워크.
매니지드 비디오 APIDaily.co, 100ms, Twilio Video, AWS Chime SDK, VonageSDK·매니지드 SFU. 빠른 출시.
엣지 WebRTCCloudflare Realtime / Calls글로벌 엣지 SFU. 새 카테고리.
자가 호스트 SFU(Node.js)mediasoup라이브러리 형태. 직접 시그널링 짠다.
자가 호스트 SFU(C)Janus플러그인 아키텍처. OG.
풀스택 OSSJitsi (Meet/Videobridge)다운로드 후 쓰는 미팅 솔루션 + SFU.
WebRTC 엔진(Go)PionGo에서 WebRTC를 짤 수 있게 한 라이브러리.
WebRTC 엔진(Rust)webrtc-rsPion의 Rust 포팅. 성장 중.
라이브 송출 표준WHIP / WHEPHTTP 한 번에 WebRTC 세션 시작. RTMP 대체.

이 글의 초점은 굵게 갈리는 LiveKit·Pion·Daily·100ms·mediasoup·Janus·Jitsi·Twilio·Chime·Cloudflare Realtime이다. WHIP/WHEP는 별도 장에서 따로 다룬다.

왜 LiveKit이 표준이 됐는가


2장 · 7축으로 보는 비교 매트릭스

상세 분석으로 들어가기 전, 한눈에 보는 큰 그림.

LiveKitDaily100msmediasoupJanusJitsiTwilio VideoAWS Chime SDKCloudflare Realtime
운영 모델매니지드+OSS매니지드매니지드OSS 라이브러리OSS 데몬OSS 풀스택매니지드매니지드매니지드(엣지)
언어Go(Pion)비공개비공개Node.js+C++CJava+C(libwebrtc)비공개비공개비공개
AI 음성 통합일급 (Agents)좋음좋음직접직접직접보통좋음 (Voice Focus)직접
WHIP/WHEP일급 지원지원지원플러그인플러그인외부 도구미지원미지원일급 지원
글로벌 라우팅클라우드에서 일급일급일급직접직접직접일급일급일급(엣지)
가격 압박강함(OSS+클라우드)보통보통인프라 비용만인프라 비용만인프라 비용만비쌈비쌈새로움
신규 채택 추이매우 강함안정강함(인도 시장)안정감소안정감소안정빠른 성장

이 표만 보고 결정을 내려선 안 된다. 다음 장부터 각 도구를 정확히 무엇이 되고 안 되는지 짚는다.


3장 · LiveKit — 표준이 된 이유, 그리고 LiveKit Agents

LiveKit은 2021년 출범 이래 가장 빠르게 자리잡은 WebRTC 인프라다. OSS(Apache 2.0)와 LiveKit Cloud 양 진영을 동시에 굴린다. 2025~2026 사이 결정적인 사건이 둘이었다.

  1. LiveKit Agents 프레임워크 — Python/Node SDK로 LLM·STT·TTS·VAD를 묶어 음성 에이전트를 만든다. OpenAI Realtime API·Deepgram·AssemblyAI·ElevenLabs·Cartesia 등이 일급 통합.
  2. OpenAI가 LiveKit을 공식 채택 — ChatGPT 음성 모드 인프라가 LiveKit 위에 올라간다는 사실이 공개됐다. 사실상 산업 표준 도장.

왜 LiveKit이 강한가

LiveKit Agents 스켈레톤

음성 에이전트 한 개의 가장 단순한 모양. 이 코드는 마이크 입력을 OpenAI Realtime로 보내고, 모델의 응답 오디오를 룸으로 도로 송출한다.

# agent.py — LiveKit Agents 최소 스켈레톤
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:
        # 인사말 자동 송출
        await self.session.say("안녕하세요. 무엇을 도와드릴까요?")

async def entrypoint(ctx: agents.JobContext) -> None:
    await ctx.connect()  # 룸에 합류

    session = AgentSession(
        # 1) STT — Deepgram nova-3
        stt=deepgram.STT(model="nova-3"),
        # 2) LLM — OpenAI Realtime(또는 일반 chat completions)
        llm=openai.LLM(model="gpt-4o-mini"),
        # 3) TTS — ElevenLabs
        tts=elevenlabs.TTS(voice_id="Rachel"),
        # 4) VAD — Silero 음성 활성 감지(턴 결정)
        vad=silero.VAD.load(),
    )

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

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

배포는 python agent.py dev로 로컬에서 띄우고, 그대로 python agent.py start로 프로덕션 모드. LiveKit 서버가 새 룸을 만들면 Agents 워커가 자동으로 매칭되어 합류한다.

OpenAI Realtime + WebRTC 직결 모드

OpenAI Realtime API는 2024년 출시 당시 WebSocket 전용이었다. 2025년 WebRTC 연결 모드가 추가됐다. 클라이언트가 SDP를 만들어 OpenAI 엔드포인트에 직접 던지면, 모델이 SFU처럼 응답한다. 지연이 200~400ms로 떨어진다.

LiveKit Agents는 이 두 가지를 모두 추상화한다.

# OpenAI Realtime을 WebRTC 직결로 쓰는 모양
from livekit.plugins import openai

session = AgentSession(
    llm=openai.realtime.RealtimeModel(
        model="gpt-4o-realtime-preview",
        voice="alloy",
        # WebRTC 모드 — 별도 STT/TTS 필요 없음
        modalities=["audio", "text"],
    ),
)

이 모드에선 STT/TTS가 따로 필요 없다. 모델이 직접 오디오 입출력을 처리한다. 단점은 가격이 높고, 모델 선택이 OpenAI Realtime 계열로 제한된다는 것.

LiveKit의 약점


4장 · Pion — Go의 WebRTC 엔진

Pion은 Go로 짜인 WebRTC 풀 구현이다. 2018년 처음 공개됐고, LiveKit·Galene·ion-sfu·OBS WHIP 송출까지 모두 Pion 위에 올라가 있다. Go의 단일 바이너리·동시성·크로스 컴파일 장점이 미디어 서버 운영에 잘 맞는다.

왜 Pion인가

Pion으로 짠 가장 단순한 SFU 피어 한 조각

피어 하나가 한 명의 발신자 트랙을 받아 다른 참가자에게 그대로 흘려보내는 코드의 최소형. 실제 SFU 구축은 트랙 라우팅·시뮬캐스트·DataChannel·재연결 처리가 추가로 들어간다.

// sfu_peer.go — Pion으로 짠 1대1 트랙 포워딩 한 조각
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
    }

    // 인입 트랙을 받아서 그대로 outgoing 트랙으로 송출
    pc.OnTrack(func(remote *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
        // outgoing 트랙 생성(VP8 가정)
        local, err := webrtc.NewTrackLocalStaticRTP(
            remote.Codec().RTPCodecCapability,
            "video",
            "pion-sfu",
        )
        if err != nil {
            return
        }
        if _, err := pc.AddTrack(local); err != nil {
            return
        }

        // RTP 패킷 그대로 포워딩
        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
}

이 코드의 한계는 명확하다. 1대1만 처리하고, 시뮬캐스트(다중 해상도 트랙)는 안 받고, 시그널링은 안 들어있다. 그래도 Pion이 얼마나 직관적인지는 잘 보여준다.

Pion 기반 프로젝트들


5장 · mediasoup — Node.js의 표준 SFU 라이브러리

mediasoup은 Node.js 진영의 SFU 라이브러리다. 자체 데몬이 아니라 Node 프로세스에서 임포트하는 라이브러리 형태라는 점이 중요하다. Worker는 C++로 짜져 있고, JS는 그걸 조종한다.

왜 mediasoup인가

mediasoup의 단점

mediasoup은 "팀에 미디어 인프라를 깊게 이해하는 엔지니어가 있다"는 전제일 때만 권한다. 사실상 매니지드/LiveKit이 채울 자리에 mediasoup을 직접 짜면 6개월 정도가 비용으로 나간다.


6장 · Janus — C로 짠 OG SFU

Janus는 2014년 출시된 C 기반 SFU다. WebRTC 인프라의 OG이고, 플러그인 아키텍처가 트레이드마크다.

Janus의 위치


7장 · Jitsi — 풀스택 OSS 미팅 솔루션

Jitsi는 OSS 풀스택 미팅 솔루션이다. 한 번 다운로드하면 Jitsi Meet(웹 UI) + Videobridge(SFU) + Jicofo(시그널링) + Prosody(XMPP) 묶음이 통째로 굴러간다.

대안 사용 사례


8장 · 매니지드 진영 — Daily, 100ms, Twilio Video, AWS Chime SDK

매니지드 비디오 API의 큰 패턴은 비슷하다. SDK + 서버 SDK + 매니지드 SFU + 녹화 + 분석. 다만 강점이 갈린다.

Daily.co

100ms

Twilio Video

AWS Chime SDK

Cloudflare Realtime / Calls


9장 · WHIP/WHEP — RTMP를 대체하는 새 표준

라이브 송출은 오래 RTMP의 자리였다. 2002년 어도비가 만든 프로토콜. H.264 코덱·Flash 시대에 만들어졌고, 결정적인 약점이 셋이었다.

WHIP(WebRTC-HTTP Ingestion Protocol)와 WHEP(WebRTC-HTTP Egress Protocol)이 답이다. IETF 표준 절차.

WHIP의 작동 흐름

  1. 송출자가 SDP offer를 HTTP POST로 서버에 던진다.
  2. 서버가 SDP answer를 200 OK로 돌려준다.
  3. DTLS·SRTP 협상이 끝나면 미디어가 흐르기 시작.

이게 전부다. 시그널링이 HTTP 한 번. WebSocket·시그널링 서버 별도 구축이 필요 없다.

WHIP 송출 클라이언트 — 가장 단순한 fetch 한 줄

// whip-publisher.js — 마이크/카메라를 WHIP으로 송출
async function publishWHIP(endpoint, token) {
  const pc = new RTCPeerConnection({
    iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  });

  // 로컬 미디어 추가
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: { width: 1280, height: 720 },
  });
  stream.getTracks().forEach((track) => pc.addTrack(track, stream));

  // SDP offer 생성
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  // ICE gathering 완료까지 대기(간소화)
  await new Promise((resolve) => {
    if (pc.iceGatheringState === 'complete') return resolve(null);
    pc.addEventListener('icegatheringstatechange', () => {
      if (pc.iceGatheringState === 'complete') resolve(null);
    });
  });

  // WHIP 엔드포인트로 SDP POST
  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}`);
  }

  // 서버의 answer로 RemoteDescription 설정
  const answer = await response.text();
  await pc.setRemoteDescription({ type: 'answer', sdp: answer });

  return pc;
}

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

WHIP/WHEP가 채택된 곳

WHIP/WHEP가 RTMP를 대체하는 이유


10장 · SFU vs MCU vs P2P — 토폴로지 결정

WebRTC 인프라의 토폴로지가 결정의 큰 축이다.

토폴로지어떻게 굴러가는가적합 상황
P2P 메시모든 참가자가 다른 모두에게 직접 연결2~3인. 매우 작음.
P2P 스타호스트 하나가 다른 참가자에게 송출1대N 스트리밍. 호스트 업로드 비대.
SFU서버가 인입 스트림을 받아 다른 참가자에게 그대로 포워딩미팅·웨비나·라이브. 사실상 표준.
MCU서버가 모든 스트림을 디코드·믹스·재인코드해서 하나로 송출전화 컨퍼런스. 클라이언트 부하 최저.

SFU가 표준이 된 이유

MCU의 자리

P2P의 자리


11장 · 코덱 풍경 — Opus, VP8, VP9, AV1, H.264, H.265

WebRTC의 의무 코덱은 오디오 Opus, 비디오 VP8·H.264다. 나머지는 선택.

오디오

비디오

시뮬캐스트와 SVC

결정


12장 · 매니지드 vs 자가 호스트 결정 매트릭스

큰 결정 한 번. 이 매트릭스가 가이드.

상황추천이유
MVP, 6개월 안에 출시매니지드 (LiveKit Cloud, Daily, 100ms)미디어 인프라에 시간을 쓰지 마라
음성 에이전트 중심(LLM·STT·TTS)LiveKit (Cloud 또는 OSS)Agents 프레임워크가 기다리고 있음
회사 내부 미팅 솔루션Jitsi 자가 호스트"솔루션" 그대로 떨어짐
WHIP 라이브 송출LiveKit Ingress 또는 Cloudflare RealtimeWHIP 일급 지원
글로벌 분산, 엣지 라우팅Cloudflare Realtime 또는 LiveKit Cloud엣지 위 SFU
인프라 비용 최소화(중간 규모)LiveKit OSS 자가 호스트매니지드 분당 비용 안 냄
시그널링·라우팅을 완전 통제mediasoup라이브러리 형태, 모든 결정이 내 것
AWS 생태계 깊게 통합AWS Chime SDKIAM·S3·CloudWatch 동기화
전화 게이트웨이(PSTN) 통합Twilio Voice + LiveKit SIPTwilio Voice는 살아있음
인도·동남아 시장 가격100ms가격 경쟁력

매니지드 → 자가 호스트로 이주 시그널

자가 호스트의 숨은 비용


13장 · 클라이언트 사이드 라이브러리

서버만큼이나 클라이언트가 결정의 절반이다.

표준 RTCPeerConnection

LiveKit Client SDK

Daily의 call-frame

mediasoup-client

Janus의 JS 어댑터

simple-peer


14장 · 운영 — TURN, NAT, 모니터링

운영의 절반은 시그널링·NAT·관측성에 들어간다.

STUN과 TURN

getStats()로 보는 WebRTC 관측성

통화 품질 지표


15장 · 라이브 스트리밍 시나리오

라이브 송출은 WebRTC 인프라의 별도 영역으로 굳어졌다. 시나리오별 권장.

시나리오송출라우팅수신
강연자 한 명 → 1만 명 시청OBS WHIP 송출LiveKit/Cloudflare Realtime SFUHLS 트랜스코드 후 HLS 시청자
강연자 한 명 → 100명 인터랙티브OBS WHIP 송출LiveKit SFUWHEP 수신
다자간 미팅 녹화 → 시청자에 송출LiveKit RoomLiveKit EgressHLS 트랜스코드
게임 플레이 송출 → 인터랙티브 채팅OBS WHIPCloudflare RealtimeWHEP 또는 HLS

WebRTC 라이브가 RTMP 라이브를 대체하는 한계


16장 · 보안·DRM·E2EE

WebRTC는 기본적으로 DTLS-SRTP 암호화다. 미디어 패킷은 클라이언트와 서버 간에 항상 암호화된다. 다만 SFU 모드에선 SFU가 평문으로 라우팅 결정을 한다(코덱 정보·시뮬캐스트 레이어 선택 등).

E2EE — Insertable Streams

DRM


17장 · 케이스 스터디 — AI 음성 에이전트 한 개 풀스택

위 도구들이 한 데 모이면 어떻게 굴러가는가. 가장 보편적인 시나리오.

[사용자 브라우저]
    |
    | WebRTC 오디오 송수신
    v
[LiveKit Server]
    |
    | LiveKit Agents Worker가 룸에 자동 합류
    v
[Agents Worker (Python)]
    |
    +-- Deepgram STT(스트리밍)
    +-- OpenAI gpt-4o-mini(LLM)
    +-- ElevenLabs TTS(스트리밍)
    +-- Silero VAD(턴 결정)
    |
    | TTS 오디오를 LiveKit 룸으로 송출
    v
[사용자 브라우저 — 즉시 재생]

지연 분해(목표 700ms 미만)

합계: 500~1000ms. 사람이 "대화처럼 느끼는" 한계가 이 정도다.

OpenAI Realtime + WebRTC 직결 모드

위 그림에서 Deepgram·OpenAI·ElevenLabs가 한 모델로 합쳐진다. 지연 200~400ms.

[사용자 브라우저]
    |
    | WebRTC 오디오 직결
    v
[OpenAI Realtime 엔드포인트]
    |
    | 모델이 오디오 입출력 자체를 처리
    v
[사용자 브라우저 — 응답 오디오]

이 모드의 트레이드오프

대다수 프로덕션은 둘을 함께 굴린다. 빠른 대화는 Realtime, 도구 호출·맞춤 TTS는 일반 LLM + 별도 STT/TTS.


18장 · 흔한 안티 패턴

운영에서 자주 봤다.

  1. P2P 메시로 4인 이상을 굴리려 함 — 5명에서 무너진다. 처음부터 SFU로 가라.
  2. TURN 서버 없이 출시 — 회사 네트워크 뒤 사용자가 들어오는 순간 통화 실패율이 30% 찍힌다.
  3. 시뮬캐스트를 끄고 한 해상도만 송출 — 10명 룸에서 누군가 모바일 4G면 모두가 끊긴다.
  4. getUserMedia 권한을 한 번 받고 끝났다고 생각 — 권한은 페이지·세션 단위로 바뀐다. 매번 다시 확인.
  5. WebSocket 시그널링 한 개로 SFU 자체를 굴리려 함 — 시그널링은 시그널링이고 미디어는 미디어다. 한 프로세스로 묶지 마라.
  6. WebRTC 통계 수집을 안 함 — 사용자 한 명이 "끊겨요" 신고하면 재현 못 한다. getStats() 1분당 1회 수집.
  7. 녹화·트랜스코드를 SFU 같은 프로세스에 박음 — 인코딩 1개가 SFU 전체를 멈춘다. 별도 워커로 분리.
  8. AI 음성 에이전트에서 VAD를 약하게 잡음 — 사용자 말이 끝나기 전 모델이 끼어든다. 또는 끝났는데 모델이 안 답한다.
  9. WHIP·RTMP·SRT 중에서 RTMP만 받는다 — 2026년에 AV1·VP9 송출은 RTMP로 못 한다. WHIP를 옵션으로 넣어라.
  10. 자가 호스트인데 모니터링이 PromQL 메트릭 5개로 끝 — 미디어 서버의 관측성은 일반 웹 서버보다 한 단계 더 깊다.

19장 · 큰 그림 — 무엇이 표준이 됐는가

2026년 5월 기준 정리.

결정 체크리스트

안티 패턴 요약

  1. P2P 메시로 4인 이상.
  2. TURN 없이 출시.
  3. 시뮬캐스트 끔.
  4. WebRTC getStats() 미수집.
  5. 한 프로세스에서 시그널링·SFU·녹화·트랜스코드.
  6. AI 에이전트에서 VAD 약함.
  7. RTMP만 받음(WHIP 미지원).
  8. 큰 룸에 MCU 강제.
  9. 매니지드와 자가 호스트 결정 없이 둘을 섞음.
  10. E2EE를 켰는데 서버 사이드 녹화를 기대.

다음 글 예고

다음 글 후보: LiveKit Agents 깊게 — 토큰 단위 스트리밍·도구 호출·인터럽션 처리, WHIP/WHEP 인제스트 한 달 운영기 — OBS·Cloudflare·LiveKit 비교, WebRTC getStats() 100개 메트릭 — 무엇을 보고 무엇을 무시할까.

"WebRTC는 표준이 아니라 표준들의 묶음이다. 묶음을 운영할 줄 아는 팀만큼 멀리 간다."

— WebRTC 미디어 인프라 2026, 끝.


참고 / References

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다