ネットワーク●●●●○

WebRTC

WebRTC ・ うぇぶあーるてぃーしー

ブラウザ同士が NAT を越えて直接つながり、音声・映像・データを送り合うための標準技術。

✦ 30秒で試す — 航海家のルーターの内側どうしなのに、外を経由せずに直結できるつながるまでに、サーバの手助けは要る?予想してみる

概要

WebRTC(Web Real-Time Communication)は、ブラウザ同士がサーバを経由せずに直接つながり、音声・映像・任意のデータをリアルタイムに送り合うための標準技術です。プラグインのインストールなしに、JavaScript からブラウザの API(RTCPeerConnection など)を呼ぶだけで、カメラやマイクの映像を相手のブラウザへ届けられます。Google Meet や Discord の通話など、ブラウザで動くビデオ会議・音声通話の多くが WebRTC の上に成り立っています。

最大の特徴は P2P(ピアツーピア)、つまり「端末同士の直接通信」を基本とすることです。ふつうの Web の通信はクライアントがサーバに要求して応答をもらう形ですが、WebRTC ではあなたのブラウザと相手のブラウザが直接パイプを結び、映像や音声のパケットが(うまくいけば)端末の間を最短経路で流れます。会話は遅延(レイテンシ)に敏感なので、再送で待たされる TCP ではなく、届かなかったものは諦めて先へ進める UDP を土台にしている点も、Web のほかの技術とは一線を画すところです。

ただし、家庭やオフィスの端末はたいてい NAT の内側にいて、外から直接話しかけることができません。WebRTC の仕組みの大半は、この壁をどう越えるかに費やされています。

なぜ生まれたか

WebRTC 以前、ブラウザでビデオ通話をするには Flash などのプラグインに頼るか、専用アプリを配るしかありませんでした。通信の方式の面でも、映像と音声をすべてサーバで中継すると、参加者が増えるほどサーバの帯域の費用が膨らみ、中継のぶんだけ遅延も増えます。会話は 200〜300 ミリ秒の遅延でも不自然に感じるため、「サーバを一往復余計に経由する」こと自体が体験の敵でした(レイテンシとスループットの話でいえば、レイテンシが主役の用途です)。

そこで Google が2010年に買収した音声・映像技術(GIPS)を2011年にオープンソースとして公開し、通話に必要な技術一式 — 音声・映像のコーデック、暗号化、NAT 越え — をブラウザに標準で積んで、端末同士を直接つなぐ仕様として WebRTC の標準化が始まりました(W3C と IETF の仕様は2021年に正式な標準になっています)。P2P にすれば中継サーバの帯域の費用が消え、経路も最短になって遅延が減る。「リアルタイム通信をプラグインなしの Web 標準にする」ことと、「サーバ中継の遅延と費用をなくす」ことを同時に狙った技術です。

詳細

最大の壁 — NAT 越えと STUN・TURN・ICE

P2P の理想は単純ですが、現実のインターネットには大きな障害があります。家庭やオフィスの端末はルータの NAT(プライベートな IPアドレスをグローバルなアドレスに書き換える仕組み)の内側にいるため、端末自身は「外から見た自分の住所」を知りません。しかも NAT は、内側から始めた通信の帰りしか通さないので、外から内側の端末へいきなり接続を張ることもできません。互いに NAT の内側にいる2台をどうやって直接つなぐか — これが WebRTC 最大の難所で、STUN・TURN・ICE という3つの仕組みで解決します。

ブラウザANATの内側ブラウザBNATの内側NATNATSTUNサーバ外から見た住所を教える穴どうしが合えば直結(最短経路)両側から同時に送って穴をあけるTURNサーバ直結できないとき中継予備の経路 — 遅延と中継の帯域の費用が増える
NAT 越えの構え — STUN で外から見た住所を知り、両側から穴をあけて直結する。直結できなければ TURN が中継する

STUN(Session Traversal Utilities for NAT)は「外から自分がどう見えているか」を教えてくれる軽いサーバです。端末が STUN サーバにパケットを送ると、STUN サーバは届いたパケットの送信元 — つまり NAT が書き換えた後のグローバルな IP アドレスとポート番号 — をそのまま返してくれます。NAT は、内側からパケットを一度出すと、その相手からの戻りを通す「穴」(変換テーブルの行)を開けます。そこで、互いに STUN で知った住所を交換し、双方から相手の住所へ向けてパケットを撃ち合うと、両側の NAT に相手へ向けた穴が開いて、直結が成立します。これをホールパンチングと呼びます。たいてい最初の1発は相手の NAT に捨てられますが、その1発が自分の側の穴を開けるので、反対側からの1発が通るようになるのです。

ところが、この穴あけが通らない NAT があります。代表がシンメトリック NAT です。シンメトリック NAT は、同じ端末の同じポートからでも、送る相手が変わるたびに別の外側ポートを割り当てます。すると、STUN サーバとの通信で知った番号(STUN 用の穴)と、相手へ撃ったときに実際に開いた番号がずれてしまい、相手はいつまでも外れた番号を狙うことになります。携帯回線の NAT や企業の NAT、厳しいファイアウォールで UDP 自体が止められている環境でも直結はできません。

その保険が TURN(Traversal Using Relays around NAT)で、開き直って「中継サーバ経由で転送する」仕組みです。どちらの NAT も「内側から TURN サーバへ出ていく通信」なら通すので、確実につながります。P2P の利点(最短経路・中継費用ゼロ)は失われます。そして全体の指揮をとるのが ICE(Interactive Connectivity Establishment)です。内側のアドレス(host)、STUN で得たアドレス(server reflexive)、TURN の中継アドレス(relay)という複数の「経路候補」を集め、優先度の高い組み合わせから順に疎通を確かめて、つながる中で最良の経路を選びます。実際のサービスでも、環境によっては少なくない割合の接続が TURN の中継に落ちるため、TURN サーバを用意しておくことは WebRTC の運用の定番の費用です。

NAT の種類を切り替えながら、実際に穴をあけて確かめてください。STUN に聞いたあと、片方の「相手へ撃つ」を相手の NAT へ運び、反対側からも撃つと、変換テーブルの行(穴)どうしが向かい合って直結します。片方をシンメトリックにすると、穴がずれる様子が表に出ます。

⚡ 体験: NAT に穴をあけて、ブラウザ同士を直結する
NAT A
NAT B
A の LAN — ポート制限コーンB の LAN — ポート制限コーンICE の候補(上から順に試す)1. host(内側の住所どうし)…2. srflx(STUN で知った住所)…3. relay(TURN の中継)予備STUN外から見た住所を返すTURN直結できないとき中継ブラウザ A192.168.1.10:5000ブラウザ B10.0.0.20:5000NAT A203.0.113.5NAT B198.51.100.20NAT の変換テーブル(この相手からなら通す)NAT外側の住所送った相手まだ行はないパケットのヘッダがここに出ます送信元—宛先—
見つけたこと 0 / 4: まだ

2台のブラウザが、それぞれ別の NAT の内側にいます。まず「STUN に聞く」を押して、2台が「外から見た自分の住所」を知るところから始めましょう。

シグナリングは仕様の外 — WebSocket の出番

もう1つ意外な設計が、「最初の待ち合わせの方法を WebRTC は決めていない」ことです。P2P を張るには、互いの経路候補や対応するコーデックといった情報(SDP と呼ばれる自己紹介文)を前もって交換する必要がありますが、まだつながっていない相手にどうやって渡すのか。この交換をシグナリングと呼び、WebRTC はその手段をアプリに任せました。既存の仕組みを自由に使えるようにするための割り切りで、実際にはシグナリング用のサーバを立てて WebSocket で中継するのが定番です。

ブラウザBシグナリングサーバブラウザAブラウザBシグナリングサーバブラウザAICE が候補の組を順に試し、STUN で疎通を確かめる接続の提案 OfferOffer を転送応答 AnswerAnswer を転送経路候補を見つけしだい送る経路候補を転送経路候補を見つけしだい送る経路候補を転送P2P 接続が確立し、以後は直接通信

候補を全部集め終わるのを待たず、見つかったものから順に送る方式(Trickle ICE)が一般的で、これにより接続までの時間が短くなります。確立した後はシグナリングサーバの役目は終わり、映像も音声もデータも端末の間を直接流れます。

暗号化は「任意」ではなく「必須」

WebRTC には平文のモードがありません。メディアは SRTP(Secure RTP)で、データは DTLS(TLS の UDP 版)で必ず暗号化され、鍵の交換も DTLS のハンドシェイクで行われます。カメラやマイクを使う API(getUserMedia)も、HTTPS で配信されたページからしか呼べません。Web で使われる HTTPS が「推奨から必須へ」と時間をかけて移行したのに対し、WebRTC は最初から「暗号化なしの選択肢を仕様上つくらない」設計を採りました。P2P ではどんなネットワークが間に挟まるか制御できないので、この割り切りは合理的です。

メディアと DataChannel

WebRTC が運べるのは音声・映像だけではありません。カメラやマイクの映像・音声を運ぶ MediaStream とは別に、DataChannel という、任意のバイナリやテキストを P2P で送れる汎用の通信路があります。信頼性(再送するかどうか)と順序の保証を用途に応じて緩められるのが特徴で、「多少落ちてもいいから最新の値を速く」というゲームの位置の同期も、「確実に全部届ける」ファイル転送も、同じ API で書けます。

なお、多人数のビデオ会議で全員と P2P を張ると、自分の映像を人数分アップロードすることになって破綻します。そのため実際のサービスは、各参加者の映像を選んで転送する中継サーバ(SFU)を挟む構成が主流です。それでも端末と SFU の間の通信そのものは WebRTC で行われており、「1対1は純粋な P2P、多人数は WebRTC を使った中継」という使い分けがいまの実務の標準形です。

試問

2台のブラウザ A・B が、それぞれ別の NAT(家庭や会社のルーターの住所の付け替え装置)の内側にいます。「STUN に聞く」で外から見た自分の住所を知り、「相手へ撃つ」をつかんで相手の NAT へ運ぶと、自分の NAT に穴(変換テーブルの行)が開きます。A の NAT は、送る相手ごとに新しいポートを割り当てるシンメトリック型に固定されていて、B の NAT の型は上の欄で選べます。

✦ 命題挑戦中

A の NAT がシンメトリック型でも、B の NAT を選び直して、中継サーバを使わずにブラウザ同士を直結せよ

  • 2台が STUN に聞いて、外から見た自分の住所を知る
  • NAT A はシンメトリックのまま、TURN の中継を使わずに直結する
⚡ 体験: NAT に穴をあけて、ブラウザ同士を直結する
NAT A
NAT B
A の LAN — シンメトリックB の LAN — ポート制限コーンICE の候補(上から順に試す)1. host(内側の住所どうし)…2. srflx(STUN で知った住所)…3. relay(TURN の中継)予備STUN外から見た住所を返すTURN直結できないとき中継ブラウザ A192.168.1.10:5000ブラウザ B10.0.0.20:5000NAT A203.0.113.5NAT B198.51.100.20NAT の変換テーブル(この相手からなら通す)NAT外側の住所送った相手まだ行はないパケットのヘッダがここに出ます送信元—宛先—
見つけたこと 0 / 4: まだ

2台のブラウザが、それぞれ別の NAT の内側にいます。まず「STUN に聞く」を押して、2台が「外から見た自分の住所」を知るところから始めましょう。