WebRTCのシグナリングサーバーにMilkcocoaを使って見るメモ #webrtcjp #mlkcca




![](https://i.gyazo.com/1fddbe942fc6f9be52d91c3e985b35e2.png)

---

こんにちは、WebRTCのハンズオンイベントを受けていてMilkcocoaとつなげてみたくなったのでやってみました。(眠い中まとめてて表現おかしいところあるかも...)

> イベントページ: [WebRTCハンズオン勉強会](http://connpass.com/event/35114/)
> [React(ES2015)とMilkcocoaでリアルタイムチャットを作ってみる #reactnative_meetup #mlkcca](http://qiita.com/n0bisuke/items/a4493d941fbd238043a4)
> [AndroidからMilkcocoaを使って見るメモ #mlkcca](http://qiita.com/n0bisuke/items/2680938a3ce9fd70ce88)

こちらのハンズオンは@yusuke84さんと@massie_gさんが講師をやってくれました。また、@massie_gさんが過去にアドベントカレンダーで[milkcocoaでWebRTCのシグナリングをやってみた](http://qiita.com/massie_g/items/25ee1dfef3f5818ad539)という記事を書いていたのを思い出してイベント後半でチャレンジしていました。

---

## WebRTCハンズオンでやった内容

[WebRTCハンズオン資料 INDEX](http://qiita.com/yusuke84/items/de9f0f6d221acec6fc07)が当日利用した資料です。
個人的には、 **この資料ものすごく分かりやすいと思いました！**

ざっくりの流れはこんな感じ

* 単語や仕組み説明
* [STEP1]とりあえず動画撮影とかを試して見る 
* [STEP2]手動シグナリングで通信の仕組みを学ぶ 
* [STEP3,4] シグナリングサーバーを立ててシグナリング 
* メディアレコーダーで動画を扱ってみる

---

### とりあえずの動作 [STEP1]

ボタンクリックすると接続してるカメラの映像を再生できます。

ソースコードは[こちら](https://github.com/yusuke84/webrtc-handson-2016/blob/handson_step1/client/webrtc.js)です。

![](https://embed.gyazo.com/f661da17b73f0e9f3d8fc253c74f7a03.gif)


このハンズオンの資料はブランチごとにステップが分かれているので、途中でついていけなくなっても挽回できるやさしい設計です。

---

### 手動シグナリング [STEP2]

手動シグナリングのソースコードは[こちら](https://gist.github.com/n0bisuke/6f664eeeecb60320d9b509797c525ea5)になります。

![](https://embed.gyazo.com/2290ab3996823f7ca768d161f886bdbb.gif)

SDP情報を相手に渡すシグナリングをSDP情報のテキストをコピペして相手側のブラウザにペーストする **手動シグナリング**を体験してみます。

これが仕組みを覚える上ではかなり重要に感じました。
SDPのやりとりとかは大体シグナリングサーバー経由で隠蔽されているので、接続開始までの知らぬ間にやりとりが発生していることがわかります。

---

### Node.js上のWSサーバーでシグナリング [STEP3,4]

Node.js上のWSサーバーでシグナリングをするソースコードは[こちら](https://gist.github.com/n0bisuke/904997957304cd0a8edfa9c3edaeeced)です。

![](https://embed.gyazo.com/70fa4485f9eeec976314d9c3601eb76f.gif)

手動シグナリングではSDPをコピペしてテキストを送ってましたが、WebSocket経由で接続してるクライアントを読み取ってシグナリングしてくれます。

---

## Milkcocoaをシグナリングサーバーにしてみる

※ここからが本題

ここまででやったて思ったのが、テキスト送るだけならWebSocketでやりとりしてるソースコードを全てMilkcocoaに置き換えられそうってことでした。

---

* https://mlkcca.com/
* 複数プラットフォームをつなげるバックエンドサービス。リアルタイムにテキストやりとりができるのでシグナリングにも使える。

![](https://i.gyazo.com/8ee252e4f8f71ee56cf5bcdda85b7f49.png)

実際にMilkcocoaに書きかえたコードは[こちら](https://gist.github.com/n0bisuke/9a46a4f1455882d8263c9520f23c56b6)になります。

---

![](https://i.gyazo.com/775b6dddd5e43a8f00671822a907dc94.png)

---

### wsをMilkcocoaに書き換え

* SDP情報を送る際のsendSdp()
* ICE candidate生成し送信する際のsendIceCandidate()

などでws.send()してる箇所をds.send()に差し替えます。
**これでMilkcocoaのsendメソッド経由で相手にSDP情報を送れます。**

* ws.onmessageでメッセージの受信監視をしている箇所

この部分をds.on()に変更しMilkcocoaのsendメソッドを監視するようにします。

---

* これだけだとうまくいかず、エラーに

```
webrtc.js:281 setRemoteDescription(answer) ERROR:  DOMException: Failed to set remote answer sdp: Called in wrong state: STATE_INPROGRESS
```

```
ncaught (in promise) DOMException: Error processing ICE candidate
```

などのエラーがでました。

---

懇親会のときの@massie_gさんの話によると、SDPを送る際にMilkcocoaだと自分にも情報が送られてきてしまうらしく、そこをハンドリングしないといけません。

socket.ioだと一つのクライアントが情報を送信したら、送信元には送られずに接続してる別のクライアントに対して送ってくれるらしいです。WebSocketも自分自身に情報が送られてしまいうまくいかないときがあるみたいです。

---

Milkcocoaの場合も同様でds.send()した場合は自分自身にも送られてきてしまいます。 エラーを消すためには **自分自身には情報が送られてこないようにする必要があります**

---

* アクセスごとにUUIDを付与して自分自信への情報は省くように

UUIDを生成して定数化しておきます。

```app.js
const UUID = uuid();

    ・
    ・(省略)
    ・

function uuid() {
  var uuid = "", i, random;
  for (i = 0; i < 32; i++) {
    random = Math.random() * 16 | 0;

    if (i == 8 || i == 12 || i == 16 || i == 20) {
      uuid += "-"
    }
    uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
  }
  return uuid;
}

```

---

情報を送る時はこのUUIDを付与してMilkcocoaに送ります。

```app.js
    ・
    ・(省略)
    ・
 ds.send({text:message,uuid:UUID});
    ・
    ・(省略)
    ・
```

---

ds.on()でsendイベントを監視し、送られてきたUUIDと自分自身のUUIDが同じ場合は何もしないという処理を追加しました。

```app.js
ds.on('send', function(sended){
    if(!sended.value.text) return;
    if(sended.value.uuid === UUID) return;
    ・
    ・(省略)
    ・

```

---
これで試すと...相手の顔が！

![](https://i.gyazo.com/70cc6225cc4bf2ec4f80d1da006d3d8b.gif)

無事にMilkcocoaでシグナリングができたようです。
仕組みがわかるとけっこう楽しいですね！

WebRTCConfとかに参加してても分からなかった内容が一気に解決した気がします。

---

## まとめ

こんな感じで無事にMilkcocoaをシグナリングサーバーにすることができました。

テキストを送り合うだけなのでシグナリングでも色々なやり方が考えられそうですね笑

Lチカシグナリングが出てくるのを密かに期待してます。

11/1に[WebRTC入門者LT会](http://connpass.com/event/39679/)もあるので何か発表してみようかな...