Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
WebRTC DataChannel コトハジメ

WebRTC DataChannel コトハジメ

更新:2021-05-12
作者:@voluntas
バージョン:2021.6
URL:https://voluntas.github.io/

目的

WebRTC DataChannel は複雑すぎるため、資料がとても少ない。 実際に DataChannel を 1 から実装していることもあり資料としてまとめることにした。

この資料で学べること

最低限の WebRTC 知識は必要になるため、もし WebRTC をあまり知らない人は以下の資料を読んでから、こちらの資料を読んでほしい。

WebRTC DataChannel の紹介

基本

DataChannel とは WebRTC で音声と映像 以外 を送受信する仕組み。といってもどのようなデータでも送ることができるので DataChannel で音声や映像を送っても問題ない。

利用できるデータは文字列とバイナリの2つで、JavaScript 的には String と ArrayBuffer/Blob となる。これらを双受信することができる。

プロトコル的には UDP を利用しており、さらに暗号化のために DTLS を利用している。DTLS はデータグラム向け TLS だ。

つまり DataChannel も MediaChannel 同様、常に暗号化された状態でデータのやり取りが行われる。

UDP は到達保証や順序保証が一切ない。 そのため DataChannel では SCTP というプロトコルを DTLS 上に構築することにより、到達保証や順序保証を実現している。

SCTP はかなりマニアックなプロトコルで、UDP と TCP のいいとこ取りのプロトコルだ。ではなぜ SCTP をそのまま使わないのか。 それは一般家庭で利用されるブロードバンドルータなどの NAT 機能は知らないプロトコルを破棄してしまう。 つまりインターネットでは TCP と UDP のプロトコルしか利用できないためだ。

そこで UDP 上に DTLS で暗号化されたトンネルをつくり、その上で SCTP を実現している。 さらに DataChannel では SCTP 上で DataChannel 拡張を用意することで、 DataChannel を SCTP のストリームと結びつける仕組みを実現している。

SCTP には Label といった機能はないが、 SCTP 上に DataChannel 確立プロトコルを使い、 SCTP 上に複数のストリームを実現している。

DataChannel で実現できる事

DataChannel の魅力はなんと行っても全て暗号化された状態で、超低遅延でストリーム事に HoL Blocking するデータを双方向でやりとりできることだ。

繰り返しになるが UDP 上でやり取りしているため到達保証や順序保証を SCTP を利用して実現している。

順序保証はその名の通りだが、到達保証はつまりリトライをどこまで頑張るかという話になる。 DataChannel ではかなり細かいところまでリトライの仕組みを指定できる。この指定はストリーム事で指定できるため、順序と信頼性を保証するストリームと保証しないストリームを一つの RTCPeerConnection 上に実現できる。

  • 絶対に諦めない、つまり TCP と同じ
  • 指定した回数だけはリトライする仕組み
  • 指定した時間だけはリトライする仕組み

つまり、リトライの諦めを時間と回数で指定できる。これらは排他的でどちらかしか有効にならない。

DataChannel で定義されているのは以下の 6 種類だ。

  • DATA_CHANNEL_RELIABLE
    • 信頼性: 保証する
    • 順序: 保証する
  • DATA_CHANNEL_RELIABLE_UNORDERED
    • 信頼性: 保証する
    • 順序: 保証しない
  • DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT
    • 信頼性: 部分的に保証する
    • 順序: 保証する
    • 指定回数内の再送
  • DATA_CHANNEL_PARTIAL_RELIABLE_REXMIT_UNORDERED
    • 信頼性: 部分的に保証する
    • 順序: 保証しない
    • 指定回数内の再送
  • DATA_CHANNEL_PARTIAL_RELIABLE_TIMED
    • 信頼性: 部分的に保証する
    • 順序: 保証する
    • 指定時間内の再送
  • DATA_CHANNEL_PARTIAL_RELIABLE_TIMED_UNORDERED
    • 信頼性: 部分的に保証する
    • 順序: 保証しない
    • 指定時間内の再送

再送の回数や時間は用途に応じて自分で指定することができる。 さらにチャネルごとに指定可能なので、信頼性も順序も保証するチャネルと 1000 ミリ秒だけは再送するがあとはすぐ諦めて、 さらに順序を保証しないチャネルを 1 つの RTCPeerConnection で実現することができる。

DataChannel のクローズ処理

1 DataChannel は SCTP 上の 1 ストリームになる。SCTP にはこの SCTP ストリームを閉じるという仕組みがないため、SCTP 拡張である Reconfig を利用し、指定したストリームをリセットするという仕組みを利用し、DataChannel のクローズを実現している。

ちなみにこのクローズ処理をせずに RTCPeerConnection を突然 close すると DataChannel の onerror で Transport channel closed というエラーが起きるので、終了するときは必ず全ての DataChannel を終了させてからにするべきだ。

DataChannel の切断検知

DataChannel において切断検知は DTLS Close Notify 以外は一切対応していないので、異常終了に気付けない場合がある。

本来 SCTP であればエンドポイント障害検出を利用する事で相手側の切断を検知する仕組みがあるが、 DataChannel の SCTP では数分経過しても相手の切断に気付くことはない。

そのため「切断を検知できない」という前提で利用する必要がある。

DataChannel は今後どうなるのか

libwebrtc では usrsctp を使わず独自の dcsctp という実装が進められている。DataChannel は今まで脆弱性の対応が主だったが、 ここに来て既存ライブラリを使わないという対応が進めている。

DataChannel の置き換えとして WebTransport が候補になる。 とはいえ DataChannel は WebRTC にべったりくっついたプロトコルのため、 既存のブラウザ全てで動作するし libwebrtc にも組み込まれている。

なにより SDP や ICE/TURN プロトコルとの組み合わせが前提とされているため、 WebRTC MediaChannel との相性も良い。

特に ICE/TURN プロトコルに対応しているため UDP が通らないが TCP や TLS は通るという経路でも何か特別な仕組みを用意する必要はない。

DataChannel が突然使えなくなるということはほとんどないと考えた方がいい。 あと 5 年は DataChannel はなくならないと考えて良いだろう。

そのため、DataChannel を採用するのは遅すぎると言うことはない。

DataChannel の検討をすべき所

シグナリング

シグナリングには WebSocket などが利用されることが多い。特にマルチストリームを利用している場合は参加や離脱の通知が必須になる。ただ WebSocket は HoL Blocking があったりといろいろ WebRTC との相性が悪い。

メッセージング

基本的には WebSocket を利用するべきだが、HoL Blocking が気になる場合のみ採用しても良いと思う。 SFU/MCU といったものに DataChannel が搭載されている場合は使いたくなるだろう。実際に Google Duo for Web では通知周りは全て DataChannel が採用されていた。

TCP ではなく UDP を利用して HoL Blocking を避けたいメッセージングがあるのであれば採用するべきだ。

エンドツーエンドなメッセージング

ルーティングとしてのみメッセージを利用した場合には DataChannel を利用するのはお勧めしたい。

アプリレイヤーで再送や順番を管理したい

順序保証も到達保証もいらず、とにかく UDP を暗号経路、かつ複数ストリームで利用したい場合は採用を検討しても良い。

DataChannel を使ってはいけないところ

リップシンクしたいデータを送る

Insertable Streams API を利用すべき。

WebRTC Insertable Streams - Chrome Platform Status

HoL Blocking してもよいデータを送る

WebSocket を利用するべき。

データベースに記録したいデータ

サーバ経由でメッセージを送るべき。

資料

DataChannel

SCTP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment