WebRTCの簡易シグナリング

## WebRTCのシグナリング
WebRTCでは、Peer-to-Peer通信を始める前に、お互いの情報を交換するための[シグナリング](http://html5experts.jp/mganeko/5181/)と呼ばれる処理があります。その過程で2種類の情報をやり取りします。

* SDP: Peerの情報
* ICE Candidate: 通信経路の情報

![sdp_ice.png](https://qiita-image-store.s3.amazonaws.com/0/19403/68d5df59-f41a-fc56-19e5-5c0e6be960b1.png)


通常はこの2つは異なるイベントをトリガーにしてやり取りします。

* SDPの送信： PeerConnection.createOffer() / PeerConnection.createAnswer() のコールバック （1回ずつ）
* ICE Candidateの送信： PeerConnection.onicecandidate() イベントハンドラ （複数回）

そのため最低2往復、場合によっては4往復以上のやり取りがあります。
とこが、これを簡略化して1往復で済ませてしまう方法があるようです。

## 簡易シグナリングの仕組み
通常のシグナリングの流れは、次のようにSDPと、ICE Candidateを別々にやり取りします。
![normal_signaling.png](https://qiita-image-store.s3.amazonaws.com/0/19403/c28174c1-d2db-7f9d-251d-4e14a5335e84.png)

* Peer AからcreateOffer()で生成された Offer SDP をPeer Bに送信
* Peer Bでは、createAnswer()で Answer SDP を生成し、Peer Aに返信
* それぞれのPeerで、onicecandidate()イベントハンドラに渡されたICE Candidateを、相手に送信（複数回）

createOffer()/createAnswer()で生成されるSDPは、次のような内容になっています。

```js:
sdp: "v=0 o=- 3336702409326257609 2 IN IP4 127.0.0.1 ...以下略... "
type: "offer"  // <-- または "answer" 
```

この sdp の部分の文字列が、実際のPeerの情報です。これを相手に送るのですが、同時にPeerConnection.setLocalDescription()に渡して自分でも覚えます。覚えたsdpの値は次の属性値として取得することができます。

```js:
PeerConnection.localDescription.sdp
```

その後、複数回 onicecandidate()イベントが発生しますが、発生するたびに PeerConnection.localDescription.sdpの値が変化していきます。 最初と最後の差分を取ってみると、次の行が増えています。

```js:
< m=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126
---
> m=audio 64980 RTP/SAVPF 111 103 104 0 8 106 105 13 126
> a=candidate:2999745851 1 udp 2122260223 192.xxx.xxx.xxx 64980 typ host generation 0
> a=candidate:2999745851 2 udp 2122260223 192.xxx.xxx.xxx 64980 typ host generation 0
> a=candidate:2747735740 1 udp 2122194687 192.xxx.xxx.xxx 64981 typ host generation 0
> a=candidate:2747735740 2 udp 2122194687 192.xxx.xxx.xxx 64981 typ host generation 0
> a=candidate:1606961068 1 udp 2122129151 10.xxx.xxx.xxx 64982 typ host generation 0
> a=candidate:1606961068 2 udp 2122129151 10.xxx.xxx.xxx 64982 typ host generation 0
> a=candidate:1435463253 1 udp 2122063615 192.xxx.xxx.xxx 64983 typ host generation 0
> a=candidate:1435463253 2 udp 2122063615 192.xxx.xxx.xxx 64983 typ host generation 0
> a=candidate:4233069003 1 tcp 1518280447 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:4233069003 2 tcp 1518280447 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:3980714572 1 tcp 1518214911 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:3980714572 2 tcp 1518214911 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:290175836 1 tcp 1518149375 10.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:290175836 2 tcp 1518149375 10.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:453808805 1 tcp 1518083839 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:453808805 2 tcp 1518083839 192.xxx.xxx.xxx 0 typ host tcptype active generation 0

< m=video 1 RTP/SAVPF 100 116 117 96
---
> m=video 64980 RTP/SAVPF 100 116 117 96
> a=candidate:2999745851 1 udp 2122260223 192.xxx.xxx.xxx 64980 typ host generation 0
> a=candidate:2999745851 2 udp 2122260223 192.xxx.xxx.xxx 64980 typ host generation 0
> a=candidate:2747735740 1 udp 2122194687 192.xxx.xxx.xxx 64981 typ host generation 0
> a=candidate:2747735740 2 udp 2122194687 192.xxx.xxx.xxx 64981 typ host generation 0
> a=candidate:1606961068 1 udp 2122129151 10.xxx.xxx.xxx 64982 typ host generation 0
> a=candidate:1606961068 2 udp 2122129151 10.xxx.xxx.xxx 64982 typ host generation 0
> a=candidate:1435463253 1 udp 2122063615 192.xxx.xxx.xxx 64983 typ host generation 0
> a=candidate:1435463253 2 udp 2122063615 192.xxx.xxx.xxx 64983 typ host generation 0
> a=candidate:4233069003 1 tcp 1518280447 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:4233069003 2 tcp 1518280447 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:3980714572 1 tcp 1518214911 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:3980714572 2 tcp 1518214911 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:290175836 1 tcp 1518149375 10.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:290175836 2 tcp 1518149375 10.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:453808805 1 tcp 1518083839 192.xxx.xxx.xxx 0 typ host tcptype active generation 0
> a=candidate:453808805 2 tcp 1518083839 19.xxx.xxx.xxx 0 typ host tcptype active generation 0
```

増えているのは全て a=candidate の行です。つまり、ICE Candidateの情報がSDPの中に追加されて保持されています。 ここまで出揃ったら、初めてSDPを相手に渡します。戻るAnswer SDPも、ICE candidateが出揃ってから送り返します。 すると、1往復ですべての情報が揃い、Peer-to-Peer通信が始まります。

![easy_signaling.png](https://qiita-image-store.s3.amazonaws.com/0/19403/ca93245a-2a3c-8350-5406-145051a2461e.png)


※ICE Candidateが出そろったという判断は、onicecandidate()イベントハンドラに渡される引数で判定しています。

## 簡易シグナリングの特徴
この方式の特徴は次の通りです。

* 利点：やりとりがシンプルになる
* 欠点：すべてのICE candidateが出そろうまでは、Peer-to-Peer通信が始まらない。（※通常の手順なら、やり取りの途中で通信可能な経路が発見された時点で、Peer-to-Peer通信が開始される）

この裏ワザ(?)は、[Kurentoの調査](http://www.slideshare.net/mganeko/nodekurento)を行う過程でソースを読んで発見しました。やはりソースを読むのが一番の勉強になりますね。
※前日の記事 [歴史で振り返るWebRTC ](http://qiita.com/stwhabout/items/33ed2fe44aa2f7beb12e)を読んだら、もともとはSDPの中にcandidateも含んでいたことを知りました。今回の簡易シグナリングは先祖がえりなのですね。

## サンプル
サンプルを使って、実際に手動シグナリングで試すことができます。

* [2017年の新サンプル](https://mganeko.github.io/webrtcexpjp/basic2016/hand_signaling_track.html) ... Chrome, Firefox, Safari 11 (Max OS X) 対応
* [2014年の旧サンプル](https://lab.infocom.co.jp/demo/webrtc-hand-signaling-easy.html) ... Chrome のみ


カメラをお持ちの人は、Chromeで2つのウィンドウで開いて試してみてください。手順はこの図の通りです。

![easy_signaling_step.png](https://qiita-image-store.s3.amazonaws.com/0/19403/a667bb67-02cb-c487-2445-794792678695.png)