WebRTCの技術について調べ、SkyWayを触ってみる。
WebRTCとは
「Web Real-Time Communication」の略称。WebRTCはビデオ会議などリアルタイムでの通信を実現する仕組み。
用語
-
シグナリングサーバ
通信相手に関する情報を得る役割のサーバ。 -
P2P
「Peer to Pee」の略。サーバーを介さず、端末同士が直接通信できるようにする。 -
NAT
ネットワークアドレスを変換する機能。インターネットにつながっているIPアドレスを複数の端末で利用する方法。
ファイアウォールの機能の一部。 -
NAT越え
NATによってプライベートIPアドレスに外部から直接アクセスすることはできない(グローバルIPを介する必要がある)。「NAT越え」技術を活用すると、プライベートIPアドレスしか持たないデバイス同士を、インターネットを通じて通信することが可能になる。
①STUNサーバーから情報を得る
→②シグナリングサーバ経由で通信相手に情報を渡す
→③得た情報によりポートをマッピングし、直接P2P通信を行う- STUNサーバ
「Session Traversal Utilities for NATs」
NATで割り当てられたグローバルIPアドレスとポート番号の情報を、NATの外側に用意されたSTUNサーバから返すため、ブラウザがローカルネット内で外から見た情報(グローバルIPアドレスとポート番号)を知ることができる。
ここで得た情報をシグナリングサーバー経由で通信相手に渡す。
STUNでNATを越えられないときはTURNを使う。
- STUNサーバ
-
ファイアウォール越え
Firewallが設置されているケースでは外部と通信できるポートも制限され、STUNサーバーを使用しても通信を行うことができない。P2Pに代わって、TURNサーバが通信を仲介(リレー)することで通信を可能にする。-
TURNサーバ
「Traversal Using Relay around NAT」
NATの外側にデータをリレーする。端末同士は直接通信せずに、リレーサーバ経由で通信する。P2P通信ではなくなるためネットワーク負荷が高くなりやすい。 -
ICE
「Interactive Connectivity Establishment」
STUN」および「TURN」の2つの技術を組み合わせてNAT越えを行う。
-
-
SFUサーバ
「Selective Forwarding Unit」
多人数通話や映像配信を実現する。3人以上で通信する際に端末のエンコード負荷と上り帯域幅や通信量を削減できるため、Mesh方式(※)より多人数での通信が可能になる。
Skywayについて
WebRTCに必要な4つのサーバをAPI経由で利用可能にするSDK。
- シグナリングサーバ
- STUNサーバ
- TURNサーバ
- SFUサーバ
1) シグナリングサーバと接続する
new Peerを実行
// デバッグ情報を最大(3)にして接続する場合
const peer = new Peer('some-peer-name', {
key: "<YOUR-API-KEY>"
debug: 3,
});
// TURNサーバを強制利用する場合
const peer = new Peer({
key: "<YOUR-API-KEY>"
config: {
iceTransportPolicy: 'relay',
},
});
- 対象のサーバをディスパッチャーサーバに問い合わせる
- 認証サーバの認証情報の検証
- PeerIDの生成
- TURNサーバ接続用の認証情報取得
- 定期的にping/pongを実施
- openイベントが発火
2) 1対1の発信処理(callメソッド)
指定した Peer にメディアチャネル(音声・映像)で接続して、MediaConnectionを作成。
// 自身のlocalStreamを設定して、相手に発信する場合
const MediaConnection = peer.call("peerID", localStream);
// 自身のlocalStreamおよびmetadataを設定して、相手に発信する場合
const MediaConnection = peer.call("peerID", localStream, {
metadata: {
foo: "bar",
},
});
// 映像コーデックとしてH264を利用する場合
const MediaConnection = peer.call("peerID", localStream, {
videoCodec: "H264",
});
// 音声のみ接続先から受信する設定で、相手に発信する場合
const MediaConnection = peer.call("peerID", null, {
audioReceiveEnabled: true,
});
2) データの送信(connectメソッド)
指定した Peer にデータチャネルで接続して、DataConnectionインスタンスを生成する。
// 単にDataChannelを接続する場合(デフォルトで信頼性有り)
const DataConnection = peer.connect("peerId");
// metadata付きでconnectする場合
const DataConnection = peer.connect("peerId", {
metadata: {
hoge: "foobar",
},
});
3) ルームに参加する(joinRoomメソッド)
メッシュ接続のルーム、または SFU 接続のルームに参加する。
// Mesh接続を利用する場合
const room = peer.joinRoom("roomName", {
mode: "mesh",
stream: localStream,
});
// SFU接続を利用する場合
const room = peer.joinRoom("roomName", {
mode: "sfu",
stream: localStream,
});
// ルームが接続されたときに発生
room.on("open", () => {});
// ルーム内に存在する各Peerとの間のRTCPeerConnectionを取得(キーがpeerId、値がRTCPeerConnectionのオブジェクト)
const pcs = room.getPeerConnections();
// ルームに新しい Peer が参加したときに発生
room.on("peerJoin", (peerId) => {
// ...
});
// 新規に Peer がルームを退出したときに発生
room.on("peerLeave", (peerId) => {
// ...
});
// データを送信
room.send(data);
// 更新
room.replaceStream(stream)
参考