yagisukeのWebなブログ

フロントエンドとサーバーサイドをさまようエンジニア

第5話: WebRTC の雑多なメモ 〜 REAL WORLD HTTP第7章より 〜

yagisuke.hatenadiary.com

の第5話です。

WebRTC(Web Real-Time Communication)

WebRTCはブラウザ/サーバー間の通信だではなく、ブラウザとブラウザのP2P通信で使用します。 RTCは「リアルタイムコミュニケーション」の略で、テレビ電話などのリアルタイムコミュニケーションを 実現するための基盤として設計されています。

実現したいアプリケーションも他のプロトコルとは大きく異なるため、使われる機能群も大きく変わります。 通信の基盤に使うトランスポート層は、再送処理の面倒を見てくれるTCPではなく、 エラー処理や再送処理を行わないUDPをメインで使います。

またP2P通信なので、相手もブラウザを探すシグナリングルーター内部のプライベートアドレスしか 持たないコンピューターで動いているブラウザのため、NATを超えてプライベートアドレスだけで通信 できるような技術も使われています。

RTCPeerConnection

WebRTCの技術要素について説明していきますが、 ブラウザから使われるAPIという観点で説明していきます。

  • RTCPeerConnection: 通信経路の確保とメディアチャンネルのオープン
  • mediaDevices.getUserMedia: カメラ、マイクと動画・音声のハンドリング
  • RTCDataChannel: データチャンネルの通信

WebRTCのベースになっているのはIP電話です。 IP電話で使われている技術を一つにまとめ、JavaScriptAPIを定めたものです。 NAT超えなどの基礎をなすプロトコルはどれも古くからあるものです。

IP電話についてはこちら: http://www.pc-master.jp/internet/ip-denwa.html

P2P通信を確立するまで

ブラウザ間でP2P通信を行うには、相手のIPアドレスを知らなくてはなりませんし、 動的に割り振られるUDPのポート番号も知る必要があります。 また、その通信でやり取りできる内容についても、お互い合意しておく必要があります。 そのためP2P通信が確立するまでに、WebRTCではいくつかの情報をやり取りしています。

ICE(Interactive Connectivity Establishment)

ICEはNATを超えてP2P通信の接続を確立する手法です。 STUNとTURNのどちらかのサーバーを利用します。

(今回はSTUNで説明します)

NATを越えてP2P通信するには、シグナリング処理でお互いに自分の知らないグローバルの情報を 交換する必要があります。

f:id:yagi_suke:20180126011807p:plain

画像: https://html5experts.jp/mganeko/20618/

自分で知らない情報は、誰かから教えてもらうしかありません。 それを可能にするのがSTUNです。

STUNの仕組みはシンプルです。 NATで変換されたIPアドレス/ポートを、外側にいるSTUNサーバーに教えてもらいます。 先ほどの例で言えば、このようになります。

f:id:yagi_suke:20180126011818p:plain

画像: https://html5experts.jp/mganeko/20618/

自分のグローバル情報が分かったら、それをシグナリングサーバー経由で相手に渡します。 STUNサーバーから得られた情報は、シグナリングの過程でICE Candidateとして取得できます。 これをシグナリングサーバーなどを経由して相手に送ることができ、P2P通信が実現しています。

f:id:yagi_suke:20180126011812p:plain

画像: https://html5experts.jp/mganeko/20618/

SDP(Session Description Protocol: セッション記述プロトコル)

SDPはP2Pネゴシエーション時に互いのIPアドレストポート、双方で利用できるオーディオや動画の コーデック情報を共有するためのものです。

コーデック (Codec) は、符号化方式を使ってデータのエンコード(符号化)とデコード(復号)を双方向
にできる装置やソフトウェアなどのこと。 また、そのためのアルゴリズムを指す用語としても使われている。

参照: https://ja.wikipedia.org/wiki/コーデック

WebRTCでは「自分が使えるコーデック情報やIPアドレスなどをSDPというプロトコルのフォーマットで 記述して相手に渡し、相手からも互いに利用可能なコーデック情報のレスポンスをもらう」という手続きを 定めていますが、「相手に渡す」手段は定めていません。

渡す手段とかはこちらを参照すると良いとのことです。
https://html5experts.jp/mganeko/19814/

メディアチャンネルとgetUserMedia

相手との通信が確立したら、実際に通信を行います。 音声やビデオを取り扱うのがメディアチャンネルです。

navigator.mediaDevices.getUserMedia()

ビデオ会議などで使うウェブカメラやオーディオデバイスの、設定と取得を行うブラウザAPIです。

カメラは解像度、フレームレート、フロントカメラ/リアカメラなどを指定することもできます。 取得されたものはストリームという名前で呼ばれます。 このAPIは単独でも使うことができ、HTMLのvideoタグ上にカメラの映像を表示できます。
APIについて: https://developer.mozilla.org/ja/docs/Web/API/MediaDevices/getUserMedia

オーディオはWeb Audio APIを利用することで高度な制御やモニタリングが行えます。 ステレオの音位の指定やミキシング、ボリューム調整などができます。 Audio Workerを利用すると音声信号をJavaScriptで分析できるようになるため、 しゃべっている人の検出なども可能となります。
Web Audio APIについて: https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API

DTLS

WebRTCのデータ通信には、メディアチャンネルとデータチャンネルの2つがあります。 どちらも、DTLS上の通信となっています。

DTLSについてはこちら
参考: http://www.nttpc.co.jp/yougo/DTLS.html

メディアチャンネル

音声・動画を伝送するWebRTC Mediaチャンネルです。 WebRTC MediaチャンネルはDTLS上のSRTPというプロトコルをつかっています。

音声や動画のストリーミングで情報が入れ替わってしまうのは問題なので、 順序の整列機能だけをUDPに追加しています。

データチャンネル

データチャンネルは音声以外のデータをP2Pで送受信するためのものです。 ユースケースにはファイルをチャットの相手に送信したり、 通信対戦のゲームの捜査情報を共有するのに使用していました。 データチャンネルはDTLSの上でSCTP(Stream Control Transmission Protocol)という プロトコルを載せています。

データのユースケースは映像・音声よりも多少幅があります。 データファイルのデータが途中で消失してしまったり、一部欠落すると困ることもあれば、 それより応答性が損なわれる方が問題になることもあります。

そこでSCTPではパフォーマンスとトレードオフで信頼性を設定できるようになっています。 UDP側に寄せるか、TCP側に寄せるか、選べるようになっています。

  TCP UDP SCTP
信頼性 到達保証あり 到達保証なし 変更可能
配送順序 順序付けあり 順序つけなし 変更可能
転送方式 バイト指向 メッセージ指向 メッセージ指向
輻輳制御 あり なし あり

データチャンネルの初期化は以下のように行います。 2つ目の引数が特性を制御するパラメータです。 省力時はTCP同等の配送順序保証の高信頼性モードになります。 このサンプルコードは順序を保証せず、再送もしないというUDP互換のモードを設定しています。 maxRetransmitTimeかmaxRetransmitsのどちらかを設定し、再送方式を手動にすると非信頼モードになります。

const connection = new RTCPeerConnection()

const dataChannel = connection.createDataChannel('data channel', {
  orderd: false,        // 順序保証?
  maxRetransmitTime: 0, // 再送し続ける期間
  maxRetransmits: 0     // 再送回数
})

ファイル送信などのユースケースであればデフォルトの高信頼性モードが適しています。 例えば、画像ファイルやEXCELファイルのデータの一部が変えたり順序が入れ替わってしまったら、 ファイルとして用をなさないからです。 ゲームのステータスで、UDPの1パケットに治るサイズであれば、少なくとも順序保証はありません。

参考になりそうなサイト: https://www.html5rocks.com/ja/tutorials/webrtc/datachannels/

引用元や参考情報