WebRTCについて調べる

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」<br/>NATで割り当てられたグローバルIPアドレスとポート番号の情報を、NATの外側に用意されたSTUNサーバから返すため、ブラウザがローカルネット内で外から見た情報（グローバルIPアドレスとポート番号）を知ることができる。
ここで得た情報をシグナリングサーバー経由で通信相手に渡す。
STUNでNATを越えられないときはTURNを使う。

- ファイアウォール越え
Firewallが設置されているケースでは外部と通信できるポートも制限され、STUNサーバーを使用しても通信を行うことができない。P2Pに代わって、TURNサーバが通信を仲介（リレー）することで通信を可能にする。
  - TURNサーバ
  「Traversal Using Relay around NAT」<br/>NATの外側にデータをリレーする。端末同士は直接通信せずに、リレーサーバ経由で通信する。P2P通信ではなくなるためネットワーク負荷が高くなりやすい。

  - ICE
  「Interactive Connectivity Establishment」　<br/>STUN」および「TURN」の２つの技術を組み合わせてNAT越えを行う。

- SFUサーバ
「Selective Forwarding Unit」
多人数通話や映像配信を実現する。3人以上で通信する際に端末のエンコード負荷と上り帯域幅や通信量を削減できるため、Mesh方式（※）より多人数での通信が可能になる。

# Skywayについて
WebRTCに必要な４つのサーバをAPI経由で利用可能にするSDK。
- シグナリングサーバ
- STUNサーバ
- TURNサーバ
- SFUサーバ

###### 1) シグナリングサーバと接続する
new Peerを実行
```javascript
// デバッグ情報を最大(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を作成。
```javascript
// 自身の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インスタンスを生成する。
```javascript
// 単にDataChannelを接続する場合(デフォルトで信頼性有り)
const DataConnection = peer.connect("peerId");

// metadata付きでconnectする場合
const DataConnection = peer.connect("peerId", {
  metadata: {
    hoge: "foobar",
  },
});

```

###### 3) ルームに参加する（joinRoomメソッド）
メッシュ接続のルーム、または SFU 接続のルームに参加する。
```javascript
// 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)
```

# 参考
https://jp.vcube.com/sdk/blog/webrtc-general-server-configuration-signaling-turn-sfu.html

https://amnimo.com/column/021/

https://qiita.com/yusuke84/items/13fab1d0f97c466e4d4b

https://qiita.com/A-Kira/items/b26b82ee488384b302ad