リアルタイム通信 — WebSocket・gRPC ストリーミング・WebRTC
WebRTC — シグナリングは自分で作る
一言でいうと
WebRTCは、接続を結ぶ方法を決めていないので、SDPを渡すシグナリングを自分で作り、ICEで道を探し、DTLSで鍵を共有したあと、SRTPでメディアを、SCTPでデータチャネルを運びます。
なぜ必要なのか
2つの機器が直接話せるようにするには、解くべき問題が3つあります。互いのアドレスと能力をどう知らせるか(シグナリング)、両方がNATの後ろにあるときにどの道で届くか(ICE・STUN・TURN)、その道の上のデータをどう守るか(DTLS-SRTP)です。RFC 8825が概説するWebRTCは、あとの2つは決めましたが、1つ目はわざと空けておきました。JSEP(RFC 9429)は、ブラウザーがSDPのオファーとアンサーを作る方法を決めるだけで、それを相手にどう渡すかは、アプリケーションに任せます。そのため、ほとんどすべてのサービスが、WebSocketのような小さなシグナリングサーバーを別に置きます。
どう動くのか
SDPのオファーとアンサー: オファーする側は、何を送るか(オーディオトラック、データチャネル)を決めてから、createOfferでSDPを作ります。送るものを決めないと、m=行のない空のオファーになります。SDPには、メディアごとのm=行、コーデック(a=rtpmap)、ICEの資格情報(a=ice-ufrag・a=ice-pwd)、DTLS証明書のフィンガープリント(a=fingerprint)、DTLSの役割(a=setup:actpass・active・passive)、そして候補(a=candidate)が入ります。アンサーする側は、受け取ったオファーをsetRemoteDescriptionに入れて、createAnswerで答えます。
ICE候補: ICE(RFC 8445)は、可能なアドレスをすべて集め(候補の収集)、ペアにして接続確認を試し、動くペアのうち1つを選びます。候補は3種類です。
| 種類 | どこから来るか | 意味 |
|---|---|---|
| host | 自分のインターフェース | 同じネットワークの中なら、これで十分です |
| srflx | STUNサーバーが見たアドレス | NATが変えてくれた外側のアドレスです |
| relay | TURNサーバーが貸してくれたアドレス | 直接届かないときに、サーバーが代わりに運びます |
STUN(RFC 8489)サーバーは、Bindingリクエストに「私が見たあなたのアドレス」をXOR-MAPPED-ADDRESSで返すだけで、データは運びません。対称NATやUDPが塞がれた網では、そのアドレスでも届かないので、TURN(RFC 8656)サーバーが、リレーアドレスを貸してくれて、すべてのデータを代わりに運びます。TURNは帯域のコストがかかりますが、なければ、一部のユーザーはまったく接続できません。UDPが塞がれた場所のために、TCP・TLS 443でもTURNを開きます。候補をすべて集めたあとでSDPを送る方式と、集まったそばから別に送るtrickle ICEがあります。ラボのaiortcは前者の方式なので、届かないSTUNサーバーを設定すると、その応答を待つために、オファーが数秒遅れます。
DTLS-SRTPとSCTP: 道が決まると、その上でDTLSハンドシェイクを行います。相手が見せた証明書のハッシュが、シグナリングで受け取ったa=fingerprintと同じでなければならず、これが中間者攻撃を防ぎます。RFC 8827は、すべてのメディアを暗号化するよう求めていて、メディアの鍵は、DTLSハンドシェイクから取り出してSRTPに使います(RFC 5764)。データチャネルは、DTLSの上のSCTPで流れ(RFC 8831)、チャネルごとに、順序保証の有無と、再送の上限(maxRetransmits)や寿命(maxPacketLifeTime)を、別々に決められます。音声フレームのように、20ms後には役に立たないデータは、順序なし、再送なしで送るほうがよいです。
メディアトラック: オーディオはRTPで流れます。RFC 7874は、WebRTCが必ず実装するオーディオコーデックとして、OpusとG.711を定め、RFC 7587は、Opusを、入力のサンプリングレートに関係なく、SDPにopus/48000/2と書かせます。
現場での姿
ジッターと損失: 音声は、再送を待つ余裕がないので、受け取る側がジッターバッファーで到着間隔の揺れを吸収し、失ったフレームは、前後の音で埋めます(損失の隠蔽)。バッファーが大きければ、途切れは減りますが、すべての音がその分遅れます。ITU-T G.114は、片方向のレイテンシが150ms以下なら、ほとんどの会話に支障がないとみなしています。「会社のネットワークでだけ接続できない」は、たいてい、UDPが塞がれているのにTURNがない、またはTURNがUDPでしか開いていない場合で、「接続まで5秒」は、届かないSTUNを待っている場合です。
次のラボですること
WebSocketシグナリングサーバーを作り、aiortcでアンサーのピアとオファーのピアを作って、基準ピアとデータチャネルでメッセージをやり取りします。チャネルを順序なし・再送なしのものに変え、同じPodの中のSTUNサーバーでsrflx候補ができる様子と、塞がれたSTUNが収集を遅らせる様子を測ります。