ブラウザの BroadcastChannel を使ってシグナリング

# はじめに

これは [WebRTC入門者LT会 #2](https://webrtc.connpass.com/event/58506/) の発表資料です

## 自己紹介

- @massie_g / がねこまさし
- インフォコム（株）所属
- WebRTC Meetup Tokyo スタッフ
- WebRTC Beginners Tokyo スタッフ

---

# WebRTCに欠かせないシグナリング

- WebRTCでは、SDPやICE candidateを交換する「シグナリング」が欠かせない
- 実験や画面のプロトタイプでは、なるべく簡単に行いたい
    - できれば、シグナリングサーバーを立てずにやりたい

## 1対1の場合

<!--
![1to1.png](https://qiita-image-store.s3.amazonaws.com/0/19403/26802c5b-431a-97c0-a1b2-4428e4787240.png)
-->

- [ハンズオン Step2](http://qiita.com/yusuke84/items/43a20e3b6c78ae9a8f6c#step2)のように手動シグナリングが可能

## でも複数人の場合は？

- 手動では大変
- → 普通はシグナリングサーバーを用意

---

# シグナリングサーバー

## 複数人、単一ルームの場合

- WebScoketによるシグナリングが定番
    - [ハンズオン Step3](http://qiita.com/yusuke84/items/43a20e3b6c78ae9a8f6c#step3)など

![multi_member.png](https://qiita-image-store.s3.amazonaws.com/0/19403/c2fbeb4e-d5e4-2a85-e4e6-e4984557db3f.png)

---

## 複数人、複数ルームの場合(1)

![multi_room.png](https://qiita-image-store.s3.amazonaws.com/0/19403/4bb321ab-92c2-8a5d-ef1a-67da0dce6886.png)

---

## 複数人、複数ルームの場合(2)

- WebSocketに自分でルーム機能を追加するのも一つの手
- Socket.ioを使うと、複数ルームのシグナリングが作りやすい
    - [シグナリングを拡張して、複数人で通信してみよう ーWebRTC入門2016](https://html5experts.jp/mganeko/20112/)
- [Firebase](https://firebase.google.com/?hl=ja)や、[Milkcocoa](https://mlkcca.com/)のようなリアルタイム通信サービスを使うことも可能
    - [Firebaseで楽々シグナリング──WebRTC入門2016番外編](https://html5experts.jp/mganeko/20273/)
    - [WebRTCシグナリング over milkcocoa](http://qiita.com/massie_g/items/fb07fbe26aa51ac9cb54)

※でも、もっと簡単にやりたい！

---

# そこでBroadcastChannel

## BroadcastChannel とは？

- Chrome, Firefox で利用可能
- 同一マシン上のWindow/Tab/Frame/iframe/Web Worker の間でメッセージをやり取り
    - 同一オリジン同志で、やりとり可能

[MDN のBroadcast Channel APIの説明](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API)から引用

![BroadcastChannel.png](https://mdn.mozillademos.org/files/9945/BroadcastChannel.png)

※BroadcastChannelについては @gtk2k さんに教えてきただきました。どうもありがとうございます！

---

## BroadcastChannelの使い方

```js
// 接続
let channelName = 'myroom';
let broadcast = new BroadcastChannel(channelName);

// メッセージのハンドリング
broadcast.onmessage = function(evt) {
  let messageObject = JSON.parse(evt.data);

  // ... メッセージに応じた処理 ...
}

// メッセージの送信
let messageString = JSON.stringify(messageObject);
broadcast.postMessage(messageString );

// 切断
broadcast.close();
```

---

## デモ

- GitHub pageで試す
    - https://mganeko.github.io/webrtcexpjp/basic2016/multi_bc.html?room1
    - https://mganeko.github.io/webrtcexpjp/basic2016/multi_bc.html?room2
- GitHubでソースを見る
    - https://github.com/mganeko/webrtcexpjp/blob/master/basic2016/multi_bc.html

---

##　BroadcastChannelをシグナリングに使う場合の注意

- 同じチャネル（ルーム）に接続している相手全部にメッセージが届く
    - 特定の相手だけに届けることはできない
- シグナリングは、相手ごとに違う内容のSDP/ICE Candidateを交換しなけばならない
    - 特定の相手だけ、区別して送信したい
- 対策
    - Window/TabごとにユニークなIDを振る
        - 今回は[uuid](http://qiita.com/psn/items/d7ac5bdb5b5633bae165)を利用
    - メッセージにIDを含めて送る
        - from(送信元) ... 自分のID
        - to(送信先) ... 相手のID
    - メッセージを受け取った時、自分以外のID宛てだったら無視する


※他のリアルタイムメッセージサービスを使う場合も、同様の対策が必要

---

## 特定ユーザ宛てのメッセージ

![broadcast_msg.png](https://qiita-image-store.s3.amazonaws.com/0/19403/5b9cd6f1-b654-7577-7c7f-1c402f563a12.png)

---

## 全員宛てのメッセージもあり

![broadcast_all.png](https://qiita-image-store.s3.amazonaws.com/0/19403/88182a37-43db-e578-a5cf-913bae278b12.png)

---
## 参考：複数の相手には複数のPeerConnection

![peer_dup_ng.png](https://qiita-image-store.s3.amazonaws.com/0/19403/30545e44-c85a-4e6e-f835-82e5fbed0911.png)

![peer_for_each.png](https://qiita-image-store.s3.amazonaws.com/0/19403/3807cf0d-45fc-5daa-2079-155dc8b75f83.png)

---

## 参考：複数の相手には個別のSDP

![sdp_for_each.png](https://qiita-image-store.s3.amazonaws.com/0/19403/98e46f1c-06f7-7b26-6442-16b6dc099a5d.png)

---

## まとめ

- 手軽にWebRTCのシグナリングを試すには、BroadcastChannelが便利
- 1対1だけでなく、どんどん複数人のアプリのプロトを作ろう
    - そして、今回の様なLTでの発表をお待ちしています！