このページの目次

WebRTC

ブラウザ間での直接な音声・動画の転送——WebRTC は SDP でメディアパラメータを交渉し、ICE で NAT トンネリングを行い、DTLS-SRTP で暗号化転送を行います。P2P の「サーバーを経由しない」ことはパフォーマンス上の利点であると同時に、デバッグの悪夢でもあります。

概要

WebRTC(2011年)はブラウザに組み込まれたリアルタイム通信の標準規格であり、プラグインなしでビデオ通話、画面共有、P2P データ転送を実現します。複数のプロトコルを組み合わせており、SDP がメディアの交渉、ICE が NAT 穿透、DTLS-SRTP がメディアの暗号化、SCTP がデータチャネルを担当します。WebRTC の接続確立は非同期で行われ、candidate が一つずつ到着し検証されます。Trickle ICE を使用することで、接続時間を大幅に短縮できます。

アーキテクチャスタック

WebRTC アーキテクチャスタック: ブラウザAPIから下層の転送プロトコルへ Browser JS API(RTCPeerConnection, RTCDataChannel) WebRTC C++ stack(libwebrtc, Google) SDP メディア交渉 (offer/answer) ICE NAT 穿透 (STUN + TURN) DTLS 鍵交換 → SRTP 鍵の派生 SRTP 暗号化された RTP ストリーム SCTP データチャネル UDP(優先) TCP(フォールバック) 5つのプロトコルが「トランスポート層」を構成する——SDP/ICE が接続確立の交渉を担当し、DTLS/SRTP がメディアのセキュリティを管理し、 SCTP がデータチャネルを管理する。すべては UDP 上で動作し、接続できない場合にのみ TCP にフォールバックする。

シグナリング: 意図的に空白とされた一环

WebRTC はシグナリングを規定していません⁠——両端が SDP と ICE candidate をどのように交換するかは標準では一切規定されず、WebSocket/HTTP/任意のチャネルを使って自分で実装する必要があります。これは意図的な設計です。メディアパスは P2P である必要がありますが、「まだ接続していない2人がどのように最初に接触するか」は、双方が到達可能なサードパーティを必要とします。

シグナリングは仲介を担当し、メディア/データは P2P 直結で流れる シグナリングサーバー(自前構築、任意のプロトコル) SDP offer/answer + ICE candidate の交換 Peer A Peer B (交渉完了後) SRTP メディア / SCTP データ —— P2P 直結 シグナリングは「両端がどのように互いを見つけるか」だけを担い、プロトコルは限定されない(WebSocket/HTTP どちらでも可、標準は介入しない)。 一度 offer/answer と candidate の交換が完了すると、メディアとデータはサーバーを完全に迂回して直結する。

まずシグナリングによって offer/answer を渡す必要があり、そうして初めて ICE が接続可能な candidate を持つことができる——これが WebRTC の「鶏が先か卵が先か」の問題である。

SDP 交渉

Caller → Callee (Offer):
  v=0
  o=- 1234567890 2 IN IP4 192.168.1.100
  s=-
  t=0 0
  a=group:BUNDLE audio video data     ← 同一の転送パス上でマルチプレクス
  m=audio 49170 UDP/TLS/RTP/SAVPF 111 103
  c=IN IP4 192.168.1.100
  a=rtpmap:111 opus/48000/2
  a=rtcp-mux                           ← RTP と RTCP は同一ポート
  a=ice-ufrag:8sdf7g
  a=ice-pwd:asd88fg
  a=fingerprint:sha-256 AB:CD:...      ← DTLS 証明書ハッシュ

Callee → Caller (Answer):
  m=audio 49180 UDP/TLS/RTP/SAVPF 111  ← 選択されたポート + コーデック
  ...

  → 双方の交渉完了 → ICE 接続チェック開始

ICE

各ピアは3種類の candidate を収集する:

  1. host: ローカル IP:port
  2. srflx (server reflexive): STUN サーバーから返されるパブリック IP:port
  3. relay (relayed): TURN サーバーが割り当てる中継アドレス

各 (ローカル candidate + リモート candidate) のペアに対して接続チェック (STUN binding) を実行し → 最適な利用可能なペアを選択する(優先度は host > srflx > relay、つまり「直結可能なら中継を使わない」)。

STUN と TURN の役割分担⁠: STUN は単に「自分のパブリックマッピングを問い合わせてくれる」だけで、メディアを転送せず、ほぼコストゼロです。しかし、両端が対称型 NAT の背後にあり、ホールパンチングに失敗した場合、TURN 中継に退避する必要があります——すべてのメディアがそれを介して転送され、帯域幅のコストが高くなります。これがデプロイにおいて唯一避けられないサーバーコストです。本番環境での経験則では、約 10〜20% の接続が最終的に TURN に落ちます。

Trickle ICE: すべての candidate の収集が完了するのを待ってから offer を送信する必要はありません。candidate は発見次第シグナリングを通じて相手側に送信され、接続チェックが行われます。これにより、接続確立時間を「最も遅い candidate を待つ」状態から「最初の利用可能なペアが準備できるまで」に圧縮します——これが WebRTC の高速な接続確立の鍵です。

DTLS-SRTP

DTLS ハンドシェイク (UDP 上の TLS 1.2 に類似) → ハンドシェイク完了後、双方は DTLS から SRTP 鍵を派生します(追加の交換は不要):

DTLS ハンドシェイク: ClientHello から SRTP 鍵の派生へ ClientHello ServerHello Certificate ServerKey- Exchange ClientKey- Exchange ChangeCipher- Spec Finished DTLS-SRTP 拡張: どの SRTP 暗号スイートを使用するかを交渉 双方は DTLS master_secret から SRTP 鍵を派生 SRTP keys = SRTP_KDF(DTLS master_secret) SRTP 鍵は個別に転送されない——今回の DTLS ハンドシェイクで生成された master secret から直接派生され、 今回のハンドシェイクと自然にバインドされ、追加の鍵交換ラウンドが不要になる。

Data Channel

DTLS 上に覆いかぶさる SCTP (Stream Control Transmission Protocol):

TCP との比較:
  - 複数ストリーム (HOL blocking が発生しない)
  - メッセージ境界を保持
  - 設定可能: 信頼性あり (reliable) / 部分的信頼性 (timed reliability)

適した用途: ファイル転送、ゲームステート、チャット

輻輳制御と Simulcast

リアルタイムメディアは TCP のようにパケット損失と再送に依存できません——1フレームのタイムリミットはわずか十数ミリ秒であり、再送を待っていると確実にタイムアウトします。WebRTC は GCC (Google Congestion Control) を使用します: RTP パケットの到着に基づくレイテンシー勾配で輻輳を予測し(キューが増加中 → 早めにレート降下)、実際にパケットが損失する前に検知し、送信側はこれに基づいてエンコーディングレートを動的に調整します。

Simulcast / SVC は、マルチユーザー会議における異種帯域幅の問題を解決します: 1つのカメラ入力から同時に複数の品質レベル⁠(例: 180p/360p/720p)をエンコードし、中間サーバーが各受信者のネットワーク状況に応じて適切なレベルを選択して配信します——これが、以下の SFU が「ユーザーごとにレベルを選択できる」前提条件です。

SFU / MCU / Mesh — マルチユーザートポロジ

WebRTC は本来 P2P ですが、マルチユーザーの場合、P2P はスケーラビリティに欠けるため、サーバーの導入が必須です。3つのトポロジ(ストリーミングプロトコルにおける配信のトレードオフと同根):

マルチユーザートポロジの選択: Mesh / SFU / MCU Mesh N人が両々直結 → 各人のアップロードは N-1 ストリーム 3〜4人のみ利用可能、サーバー不要 SFU 選択的転送: サーバーはデコードせずに転送のみ、各人のアップロードは1ストリーム、必要に応じて配信 (simulcast と併用) → メインストリーム、スケーラブル、サーバーのCPU負荷が軽い(トランスコード不要) MCU ミキシング: サーバーが全ストリームをデコード + 1つのストリームに合成して配信 → 受信側のダウンロード/計算リソースを節約できるが、サーバーのCPUコストが非常に高い SFU はデコードせずに転送のみを行い、スケーラビリティとサーバーコストのバランスが取れた、マルチユーザー会議の主流ソリューションである。 Mesh は超小規模向けのみ、MCU はサーバーの計算リソースでクライアントの軽量さを引き換えるが、コストが最も高い。

なぜ WebRTC が HLS のように CDN で展開しにくいのか⁠: 各接続には状態がある(ICE/DTLS/SRTP のコンテキスト + リアルタイムの輻輳フィードバック)ため、キャッシュ可能なファイルではありません。大規模展開はエッジキャッシュではなく、SFU のカスケードによってのみ可能——これが「サブ秒のリアルタイム性」がもたらす根本的な代償です。

参考

  • webrtc.org: webrtc.googlesource.com
  • ツール⁠: chrome://webrtc-internals

Keywords: WebRTC, signaling, SDP, ICE, Trickle ICE, STUN, TURN, DTLS-SRTP, SCTP, Data Channel, GCC, simulcast, SVC, SFU, MCU, mesh, Opus