LabHub

ブログ

WebRTC メディアインフラ 2026 — LiveKit·Pion·Daily·100ms·mediasoup·Janus·Cloudflare Realtime と WHIP/WHEP 徹底解剖

한국어English日本語

プロローグ — WebRTC は 90% がインフラ選定だ

2018 年の WebRTC は「ブラウザで P2P ビデオ通話をどう書くか」の問題だった。STUN/TURN サーバ 1 台、RTCPeerConnection のコード 200 行、ビデオ 2 枠のデモページ。以上。

2026 年の WebRTC は別の問題になっている。

本稿は「WebRTC のコード 200 行」ではなく「本番のメディアインフラをどこでどう動かすか」を扱う。この一回の判断が、半年後のインフラ費用・遅延・運用負荷を決める。

要約: 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)PionWebRTC を Go で書けるようにしたライブラリ。
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 ピア断片

1 人の発信者トラックを受け取り、別の参加者にそのまま流す最小形。実際の SFU 構築にはトラックルーティング・simulcast・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 のみで、simulcast(多解像度トラック)は受けず、シグナリングも入っていない。それでも Pion の直接さは伝わる。

Pion ベースのプロジェクト


5 章 · mediasoup — Node.js の標準 SFU ライブラリ

mediasoup は Node.js 陣営の SFU ライブラリ。自身がデーモンではなく Node プロセスから import するライブラリ形態である点が肝。Worker は C++ で書かれ、JS がそれを操る。

なぜ mediasoup か

mediasoup の短所

「チームにメディアインフラを深く理解するエンジニアがいる」前提のときだけ勧める。LiveKit やマネージドが埋める席に mediasoup を自前で書くと半年ぶんが費用に化ける。


6 章 · Janus — C で書かれた OG SFU

Janus は 2014 年公開の C ベース SFU。WebRTC インフラの OG で、プラグインアーキテクチャがトレードマーク。

Janus の立ち位置


7 章 · Jitsi — フルスタック OSS 会議ソリューション

Jitsi は OSS のフルスタック会議ソリューション。一度ダウンロードすれば Jitsi Meet(Web 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 年に Adobe が作ったプロトコル。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サーバが全ストリームをデコード・ミックス・再エンコードし 1 本に電話会議。クライアント負荷最小。

SFU が標準になった理由

MCU の出番

P2P の出番


11 章 · コーデックの風景 — Opus, VP8, VP9, AV1, H.264, H.265

WebRTC の必須コーデックはオーディオ Opus、ビデオ VP8・H.264。それ以外は選択。

オーディオ

ビデオ

simulcast と SVC

判断


12 章 · マネージド vs セルフホストの決定マトリクス

大きな判断 1 回。このマトリクスがガイド。

状況推奨理由
MVP, 半年以内に出荷マネージド(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 人 → 1 万人視聴OBS WHIP 配信LiveKit/Cloudflare Realtime SFUHLS トランスコード後 HLS 視聴
講演者 1 人 → 100 人インタラクティブOBS WHIP 配信LiveKit SFUWHEP 受信
多人数会議録画 → 視聴者配信LiveKit RoomLiveKit EgressHLS トランスコード
ゲームプレイ配信 → インタラクティブチャットOBS WHIPCloudflare RealtimeWHEP または HLS

WebRTC ライブが RTMP ライブを置き換える境界


16 章 · セキュリティ・DRM・E2EE

WebRTC は基本的に DTLS-SRTP で暗号化されている。メディアパケットはクライアント-サーバ間で常に暗号化される。ただし SFU モードでは SFU が平文でルーティング判断をする(コーデック情報・simulcast レイヤ選択など)。

E2EE — Insertable Streams

DRM


17 章 · ケーススタディ — AI ボイスエージェントのフルスタック

上のツールが集まるとこう動く。最も一般的なシナリオ。

[ユーザのブラウザ]
    |
    | WebRTC オーディオ送受信
    v
[LiveKit Server]
    |
    | LiveKit Agents ワーカーが自動でルームに参加
    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 が 1 モデルにまとまる。遅延 200〜400ms。

[ユーザのブラウザ]
    |
    | WebRTC オーディオ直結
    v
[OpenAI Realtime エンドポイント]
    |
    | モデルがオーディオ入出力を直接扱う
    v
[ユーザのブラウザ — 応答オーディオ]

このモードのトレードオフ

多くの本番では両方を併走させる。素早い会話は Realtime、ツール呼び出し・カスタム TTS は通常 LLM + 別 STT/TTS。


18 章 · よくあるアンチパターン

運用で何度も見た。

  1. P2P メッシュで 4 人以上を回そうとする — 5 人で崩れる。最初から SFU。
  2. TURN サーバ無しで出荷 — 社内ネットワーク背後のユーザが入る瞬間、通話失敗率 30% に到達。
  3. simulcast を OFF にして 1 解像度のみ配信 — 10 人ルームで誰かがモバイル 4G だと全員が切れる。
  4. getUserMedia の許可を 1 回取れば終わりと思う — 許可はページ・セッション単位で変わる。毎回確認。
  5. WebSocket シグナリング 1 個で SFU まで回そうとする — シグナリングはシグナリング、メディアはメディア。1 プロセスにまとめない。
  6. WebRTC statistics 収集をしない — ユーザが「切れます」と言っても再現できない。getStats() を 1 分に 1 回。
  7. 録画・トランスコードを SFU と同一プロセスに詰める — エンコード 1 本で SFU 全体が止まる。別ワーカーへ。
  8. AI ボイスエージェントで VAD を弱く構える — 発話の途中でモデルが割り込む、または終わってもモデルが返さない。
  9. WHIP・RTMP・SRT のうち RTMP だけ受ける — 2026 年に AV1・VP9 配信は RTMP では不可。WHIP を選択肢に。
  10. セルフホストで監視が PromQL メトリクス 5 本で終わる — メディアサーバの観測性は通常 Web サーバより一段深い。

19 章 · 大きな絵 — 何が標準になったか

2026 年 5 月時点のまとめ。

判断チェックリスト

アンチパターン要約

  1. P2P メッシュで 4 人以上。
  2. TURN 無しで出荷。
  3. simulcast OFF。
  4. WebRTC getStats() 未収集。
  5. シグナリング・SFU・録画・トランスコードを 1 プロセス。
  6. AI エージェントで VAD が弱い。
  7. RTMP のみ受信(WHIP 未対応)。
  8. 大きなルームに MCU を強要。
  9. マネージドとセルフホストを未決定のまま混在。
  10. E2EE を ON にしてサーバ側録画に期待。

次回予告

次回候補: LiveKit Agents 深掘り — トークン単位ストリーミング・ツール呼び出し・割り込み処理WHIP/WHEP インジェストの 1 か月運用記 — OBS・Cloudflare・LiveKit 比較WebRTC getStats() 100 メトリクス — 何を見て何を捨てるか

「WebRTC は単一標準ではなく標準の束だ。束を運用できるチームほど遠くへ行く。」

— WebRTC メディアインフラ 2026、おわり。


参考 / References

コメント

まだコメントはありません。

ログインするとコメントできます