概要
WebRTCとは「Web Real-Time Communication」の略で、APIを経由してウェブブラウザやモバイルアプリでリアルタイム通信を実現することができる技術です。
この技術により、プラグインのインストールを行うことなく、Webブラウザ経由で音声や映像をリアルタイムでやり取りすることが可能となり、コロナ渦におけるリモートワーク作業やオンライン会議などでも多く活用されています。
OSやキャリア、ブラウザなどのアプリケーション環境が限定されず、既存のデバイスをそのまま使えることもメリットとなります。
今回、WebRTCおよびLaravel関連機能に関する技術調査レポートをご紹介していきます。
WebRTCのアーキテクチャ
W3C策定のAPI仕様によると、下記の2つから成り立っています。(2019年12月時点)
参考:https://www.w3.org/TR/2019/CR-webrtc-20191213/
- カメラ/デバイスへのアクセス(Media Capture and Stream)
- ビデオ/オーディオ/データ通信(WebRTC 1.0: Real-time Communication Between Browsers)
出典:http://www.webrtc.org/reference/architecture
WebRTCの通信プロトコルスタック
WebRTCにおける通信環境では下記のようなプロトコルスタックを使用します。
DTLS (Datagram Transport Layer Security)
UDPでは許容されているパケットロスがTLSでは許容されていません。
これを防ぐために、内部ではシーケンス番号とフラグメントオフセット、タイムアウト、再送の仕組みを提供しています。TCPに近い仕組みです。
WebRTCではUDP通信の暗号化のために公開鍵をサーバから取得するため、UDPのパケットロスによって公開鍵の取得を失敗しないためという目的もあります。
SRTP (Secure Realtime Transport Protocol)
映像音声をリアルタイムに送受信するプロトコル。RTPはUDPにタイムスタンプ、シーケンス番号を不可しただけですが、SRTPではペイロード部を暗号化します。暗号化に使う鍵はDTLSで取得します。
SCTP (Stream Control Transmission Protocol)
元はVoIP用に開発されたプロトコル。高次の信頼性と速度が求められていたこともあり、TCPとUDPで差がある到達保証、順序保証、フロー/輻輳制御、マルチストリームを両方サポートしています(選ぶことができます)。
参考:https://wingbeats.hateblo.jp/entry/2015/01/07/110227
WebRTCの通信手順
WebRTCでは、映像/音声/アプリケーションデータなどをリアルタイムにブラウザ間で送受信します。これを実現する技術が「RTC PeerConnection」です。
RTCPeerConnectionには3つの特徴があります。
① Peer-to-Peer(P2P)の通信 → ブラウザとブラウザの間で直接通信する
② UDP/IPを使用 → TCP/IPのようにパケットの到着は保障しないが、オーバーヘッドが少ない
③ PeerとPeerの間で暗号化通信を行う → P2P通信の前に鍵の交換を行う
特徴:
・多少の情報の欠落があっても許容する替わりに、通信のリアルタイム性を重視する。
・UDPのポート番号は動的に割り振られ、49152 ~ 65535の範囲が使われる。
参考:https://html5experts.jp/mganeko/19814/
WebRTCのP2P接続
P2P接続を開始するまでの情報のやり取りを「シグナリング」と言います。
WebRTCではシグナリングのプロトコルは規定されていないため、自由に選択が可能です。WebRTCのP2P接続ではアプリケーションが後述のトランスポートとプロトコルを選択して使うことが一般的です。
ブラウザ間でP2P通信を行うには、相手のIPアドレスを知る必要があります。
また、動的に割り振られるUDPのポート番号も知る必要があります。さらに、その通信でやり取りできる内容についても、お互いが合意する必要があります。
この様にP2P通信が確立するためには、WebRTCではいくつかの情報をやり取りし許可していかなければなりません。
SDP (Session Description Protocol)
P2Pで接続するメディアの種類(音声、映像)やメディアの形式(コーデック)、転送プロトコル、自身のIPアドレスやUDPポート番号等を記した文字列を、P2P接続するブラウザ同士で交換するセッション記述用プトロコル。
呼び出し元がシグナリングサーバを介してSDPをOfferし、呼ばれる側がシグナリングサーバを介してSDPをAnswerするというOffer/Answerモデルで通信を行います。
SDPは一部変わっただけでも全ての情報を送らなければなりません。
このため、SDP情報の一部を送れるようにしたTrickle-ICEやSDPを使わないORTCが出てきています。
ICE (Interactive Connectivity Establishment)
通信経路を定めるための仕組みであり、その通信経路の候補が「ICE Candidate」になる。WebRTCの通信の開始前には、可能性のある候補がリストアップされる。
P2Pで接続するブラウザの通信経路を示した文字列(ICE Candidate)を交換し、ネットワーク的に最短の通信経路を探し出し、その上にP2P接続を確立します。
この通信経路を探す際、社内LANなど、環境によってはNATやファイアウォールなどで直接的にPC同士の情報を渡せないことがあります。
このため、STUNサーバやTURNサーバを用いて通信経路を見出し、それらの経路候補をICE Candidateとしてブラウザ間で共有する必要です。
接続候補のサーチ手順は以下の通りです。候補が見つかったら順次通信を試み、最初につながった経路が採用されます。
①P2Pによる直接通信
②NATを通過するためのSTUNサーバーから取得したポートマッピング
③Firewallを越えるための、TURNによるリレーサーバーを介した中継通信
STUN (Simple Traversal of UDP through NATs) サーバ
NAT配下にあるPCがNATの外側から見た自身のIPアドレスを知るためのもの。
NAT配下にPCがある場合、P2P通信で相手に伝える必要がある自身のIPアドレスを知ることができない。このため、P2PではSTUNサーバを経由することで、外側から見たIPアドレスの取得が可能となり、Peer同士がそのアドレス宛に通信する。
TURN (Traversal Using Relay NAT) サーバ
PC同士の間に立って、データの中継をしてくれることでNAT越えを実現するサーバ。
NAT配下でP2P通信を実現するために、すべてのパケットを代理で相手PCに届けます。多段NAT等によりSTUNで解決できない経路の場合、TURNサーバがUDPパケットをRelayする。
なお、使用する際はTURNサーバ用のポートを開く必要がある。
参考:https://qiita.com/daitasu/items/ae21b16361eb9f65ed43
P2P通信の確立手順については、下記記事などで詳細に説明がされています。
参考:https://qiita.com/daitasu/items/ae21b16361eb9f65ed43
接続形態のバリエーション
WebRTCの技術を使ってアプリを構成する場合では、1対1での接続か、複数端末での接続(=マルチパーティ接続)かによって検討のポイントが大きく変わってくきます。
1対1型
1対1であれば、端末同士で直接ストリーミングデータのやり取りをしても問題ありませんが、多対多の場合は、端末同士で直接やり取りしようとすると必要なネットワークの帯域が大きくなる。
そのため、それぞれの構成のメリット、デメリットを理解したうえで、構成を検討する必要がある。
メッシュ型
マルチパーティ接続の形態には大きく分けて フルメッシュ型、SFU型、MCU型 の3つのパターンがあります。
1つ目はメッシュ型です。「P2P型の接続」であるため仲介者としてのサーバを経由しないものとなります。
P2P型の接続を、端末の数だけ繰り返す方式であり、他の全ての端末にストリームデータを送信する。このため、参加する端末数に比例して、通信量が増大し、各端末への負担が大きくなる。
(例)10名でのオンライン会議の場合、10名への個別接続が必要となる。
SFU型(Selective Forwarding Unit)
2つ目のSFU型は、サーバを介してストリームデータを送信します。
このとき、サーバは受信したストリームデータを接続されている他の全ての端末に送信する。そのため各端末の送信量は端末数が増えても変わらないというメリットがあります。※その一方で、受信量は端末数に比例して大きくなる。
回線によっては、上り帯域が狭く、下り帯域は広いものがあるため、メッシュ型と比較して、SFU型の方が大幅に通信が安定します。
MCU型(Multipoint Control Unit)
3つ目のMCU型は、SFU型と同様にサーバを介してストリームデータを送信しますが、SFU型と違い、サーバでストリームデータを合成します。
例えば、3拠点の映像をサイズを縮小して1枚の映像に合成する…また音声もミキシングして、他の2拠点の音声を1拠点分のデータ量に削減する…
これにより、接続端末数が増えても、各端末の送受信量は変わらないというメリットが得られます。
一方で、映像や音声の合成には相当なCPU負荷がかかるため、端末の増加に伴い、サーバスペックが問題となり、サーバコストが大幅に大きくなるデメリットがある。
またサーバの処理能力が不足すると音声の乱れや遅延につながることになります。
参考:https://webrtc.smagai.com/category/kurento/
WebSocket について
WebSocketは、サーバー側とユーザー側を常時接続状態にしておき、双方向通信を可能とする技術です。これにより、例えばチャットアプリやTV会議などに必要な「リアルタイム双方向通信」が行えるようになります。
WebRTCではこのWebsocketプロトコルを使用して、双方向通信を行っています。
Websocketプロトコルについての詳細は下記を参照。
— WebSocketについて
https://qiita.com/south37/items/6f92d4268fe676347160
— RFC 6455, The WebSocket Protocol
https://triple-underscore.github.io/RFC6455-ja.html
Laravel Broadcast
現在のWebアプリケーションでは、リアルタイムでライブ更新されるユーザーインターフェイスを実装するために、WebSocketが使用されており、サーバ上で何らかのデータが更新されると、通常はWebSocket経由でメッセージが送信され、クライアントにより処理されます。これは、サーバ側の変更を(クライアント側から)ポーリングし続ける方法よりも、強固かつ、効率的になります。
こうしたタイプのアプリケーション構築のために、LaravelではWebSocket接続経由でイベントを簡単に「ブロードキャスト」する機構「Laravel Broadcast」が提供されています。
Laravel Breadcastにより、 ブラウザを更新せずに、Webアプリや他の利用者からの通知を受け取ることができるようになります。
ただし、Websocketサーバについては、Laravelのフレームワークに含まれていないため、別途用意をする必要があります。LaravelのBroadcasting では、このWebsocketサーバとしてPusherとRedisという2つ方法が標準で準備されています。
参考:https://readouble.com/laravel/8.x/ja/broadcasting.html
Pusher.com
Pusher.comプッシャーは、簡単かつ安全にウェブやモバイルアプリまたは他の任意のインターネット接続デバイスに、WebSocketを介して、リアルタイムの双方向機能を統合するためのシンプルなAPIサービスです。
Laravelには標準サービスとして組み込まれており、親和性が高いものとなっています。
Laravel Echo
「Laravel Echo」はリアルタイム双方向通信において、クライアント側のリスナーとして機能するものです。
Laravelフレームワーク内の、resources/assets/js/bootstrap.js内に初めから定義が実装されており(コメントアウトされている)、これを有効にすることで、Pusherとの連携の準備が行えるようになっています。
参考資料
— webrtc本家
https://webrtc.github.io/webrtc-org/architecture/
— Qiita
https://qiita.com/daitasu/items/ae21b16361eb9f65ed43
–WebRTCマルチパーティ接続
https://webrtc.smagai.com/category/kurento/
— WebRTC入門2016
https://html5experts.jp/series/webrtc2016/
— WebRTC SFUとは?
https://www.freshvoice.net/basic/what_web_meeting/20190807/
— hateblo WebRTC
— Laravel EchoとPusherでリアルタイムチャット