実験用に自前でWebRTCのコードを書いていたら、こうなってしまった

## はじめに

身も蓋もない話を先にしておきますと、**WebRTC、自分で色々試すのはかなり面倒なので、ライブラリやクラウドサービスの力を借りた方が安全だと思います。**

とはいえ、自前で触ってみないと学べない技術や仕組みは色々ありますし、もっと他にこうしたいとか、**自由に柔軟にあれこれ試せるようになるためには、中身を知るということが結構大事**なのはありますので、興味のある人や、ビデオ会議のような典型的なWebRTCのユースケース以外にも試してみたいことがある人は、素のWebRTCを自分で分解して触ってみることは結構いい勉強になるのではと思います。

さて、本記事では、筆者が研究開発での実験や自身のスキル向上のために実際にWebRTCを触ってみた体験談とその後について語ってみます。

## 最初は、わけがわからなかった

もう何年前のことかも忘れてしまいましたが、Chromeでカメラが使えるらしいぞ、ビデオチャットができるようになるらしいぞ、といった話題が耳に入ってくるようになり、それどうやってやるんだ、ということで、まずは触ってみようと思ったのですが...

当時はあまりサンプルコードがなく、英語や日本語の限られたサンプルコードを探したり、W3CのWebRTCの仕様書を読んだり、と、何をやるにもとにかく手探りでした。

もちろん、[PeerJS](http://peerjs.com)のようなライブラリも早くから登場していたので、それを使うほうが手っ取り早いのは間違いないのですが、**WebRTC等でとりあえずデモを動かす時に、自分側の長ったらしいIDをいちいち相手側のブラウザにコピペして入力してつなぐのが面倒なので、何とかならないか**と思ったため、まだよく理解できていないうちからWebRTCのコードを自分でも書いてみる、という方向に舵を切った、というわけです...

### 大まかに分解してみる

まずは、ステップごとに分解して、順を追って流れを理解することから始めました。WebRTCのストリームの流れを分解してみると、

|送信側|受信側|
|:--|--:|
|カメラ・マイクをキャプチャ<br>(getUserMedia)|&lt;video&gt;, &lt;audio&gt;要素で再生|
|↓|↑|
|RTCPeerConnectionに入力|RTCPeerConnectionから出力|
|↓|↑|
|ブラウザがストリーミング送信 →|→ ブラウザがストリーミング受信|

といった感じになるのですが、**ブラウザはwebサーバのアドレスがわかっていてもWebRTCで相手(ピア)に送信する送信先(IPアドレスとポート)がわからないので、いきなりストリーミングの送受信はできない**、ということに気づかないと先に進めない、というわけです。

### シグナリングはテキストチャットの仕組みで

更に調べてみると、そのためのパラメータ(SDPやICE Candidateと呼ばれるもの)をやり取りするのにwebサーバが必要、ということを学ぶことになりました。この手順を、シグナリング、と呼ぶわけです。(詳細は@massie_gさんの記事「[WebRTCの簡易シグナリング](https://qiita.com/massie_g/items/f5baf316652bbc6fcef1)」あたりが参考になると思います。)

ということは、SDPもテキストなので、**SDPやICE Candidateの交換はテキストチャット同じ仕組みで対応できる**ということがわかったため、テキストチャットを応用すればWebRTCシグナリングサーバが作れる、ということが理解できました。

この時、筆者はたまたま、Androidアプリを他のブラウザから制御するデモを作ったことがあったため、その時のWebSocketサーバ([Jetty](http://www.eclipse.org/jetty/index.html)を使って実装していました)のコードを使いまわしたりして、気がついたら自作WebRTCシグナリングサーバが完成していました。無論、Node.jsを使える人は[socket.io](https://socket.io)等を使っても良いわけですが。

## 作ってみたものの...

これで自作シグナリングサーバが動くようになり、自前のサーバ環境でWebRTCがある程度動くようになりました。しかし、これだけではまだ「相手のIDが長すぎてデモが面倒」問題が解決していません。

一方、シグナリングサーバが自作なので、そのシグナリングサーバのログイン手順も自前で好きに改造できます。そこで、例えば、FacebookアカウントやGoogleアカウントでログインする、といった実装もOAuthの要領さえわかれば自前で追加できたりします。さらに、外部アカウントと内部IDの紐付け等を実装するために、MySQLなりMongoDBなりといったデータベースをサーバ側でも活用していくこととなっていきます。

その後、実験目的で色々と社内向けにデモを作るのに自前サーバを使いまわしていくのですが...

### シグナリングサーバが肥大化

その後、IoTブームが始まり、P2P通信を利用したデモの試作は一つに限らず、ユースケースが増えていくにつれて色々と作るようになっていきます。そうすると、例えば、Gecko(Firefoxのブラウザエンジン)で動作するIoTプロトタイピングボードである[CHIRIMEN](https://chirimen.org)のように、**IoTでは画面があるものや画面のないもの、入力デバイス(キーボードやマウス)のないものなど、色々なパターンが出てくる**ため、ログイン手順やリモート制御の方法なども多様化し、**ユースケースに合わせてどんどんシグナリングサーバを拡張**していくこととなります。

そうなると、実験用にとりあえず作ってみたシグナリングサーバのコードがどんどん肥大化し、気がつくと、**一人でメンテナンスしていくにはかなり面倒なことに**なってしまっていました。新しいデモアプリ向けにサーバを拡張したら別のアプリが動かなくなった、なんてことも頻発するようになっていました。

また、そもそも高々実験やプロトタイピング用に自前でサーバを開発するとなると、運用やセキュリティなど、元々の目的以上の何倍もの手間が増えてしまい、本来の目的である「やりたいことを手軽に自前で」が手軽でなくなっていく可能性がちらついてきあのもあります。

## アーキテクチャを見直した

ちょうどその頃、mBaaS (Mobile Backend as a Service)が広く使われるようになり、**サーバロジックを自前で実装しなくても、ある程度サーバ側を設定すれば、あとはブラウザ側のコードだけでwebアプリのリアルタイム連携ができるように**なりました。(WebRTCでの使い方の例としては、HTML5Experts.jpの記事「[Firebaseで楽々シグナリング──WebRTC入門2016番外編](https://html5experts.jp/mganeko/20273/)」あたりが参考になります。)

そこで、シグナリング用のテキストチャット部分とデータベース、ログイン機能をmBaaSに置き換えることで、それ以外のWebRTCやブラウザ間通信、スクリーンや入力デバイスのないIoTデバイス対応といった、本来デモやプロトタイピングで作りたい部分にコーディングを集中できるようにしました。

<img width="781" alt="Screen Shot 2017-10-03 at 14.34.02 .png" src="https://qiita-image-store.s3.amazonaws.com/0/48556/37fe2f2b-a674-3421-7614-13f505b35a10.png">

### この機会にオープンソース化してみた

この仕組みは、あくまでもプロトタイピングで使い回しが効くものを、という意図で作ったものですので、より幅広く使いまわして、様々なユースケースに応用できるよう、全てのコードをGitHubのレポジトリで公開することにしました。MITライセンスです。

> ito - a JavaScript library for browser-to-browser communication
> https://kddi-research-wot.github.io/ito
> https://github.com/kddi-research-wot/ito

> (ちなみに、コードネームの**ito**は**IoT**のアナグラムとモノをつなぐ「**糸**」をかけたものです)

こちらはmBaaSとしてFirebaseあるいはKii Cloudの開発者アカウントとの組合せで動作する仕組みになっています。

### 「サーバ自作はメンテナンスが大変」問題はどうなった?

itoでは、ログインアカウントの管理やデータベース機能、WebRTCシグナリングを含むリアルタイム連携をmBaaSの機能によって実装しています。**大半のロジックがブラウザ側のクライアントJavaScriptコードで実装されている**ため、機能の追加や変更も大半がJavaScriptコードの修正で対応できるようになっています。

一方で、セキュリティやプライバシーを考慮して、Firebaseではデータベースルール、Kii CloudではServer CodeとACLを利用して、アカウント単位のパーミッション管理に対応しています。ある程度のサーバ側の設定やカスタマイズが必要ですが、いずれも**無料(試用)の範囲で対応している機能を使ってできる**内容で、自前サーバ実装に比べても手間が大幅に減っているのは確かだと実感しています。

さらに、FirebaseやKii Cloudの管理者コンソールによって、ログイン状態や、シグナリング等のメッセージがどのような状態にあるかが把握しやすくなるのも便利に感じています。実験目的の自前サーバでそこまでリッチなコンソールを用意するのは作業時間の面でもさすがにやり過ぎになってしまいますので...

### 「相手のIDが長すぎてデモが面倒」問題はどうなった?

itoでは、mBaaS側でアカウントの管理を行うことにしました。具体的には、FirebaseやKii Cloudのユーザアカウントに加え、GoogleアカウントとFacebookアカウントとの連携も可能にしました。また、主にIoTデバイス向けに、ランダムでIDを割り振り、サインアウトによってアカウントが無効化される匿名(anonymous)アカウントにも対応しています。これらによって、ログインしたり相手を指定したりする手順に色々と選択肢が広がることとなりました。

さらに、データベース連携を活用して**ペアリング(友達アカウント)**の機能を導入してみました。これにより、一定時間だけ有効な短いパスコードを設定したり、長いパスコードを設定してQRコードで読み取るようにしたりすることで、簡単な操作で相手アカウントとペアリングすることが可能になります。

<img width="1680" alt="Screen Shot 2017-10-03 at 14.46.23  copy.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/48556/38dacc8b-ca3a-66ec-371b-2381397cce4e.jpeg">

## おわりに

少々長くなりましたが、自前でWebRTCのコードを書いて様々な経験を積み重ねていくと、WebRTCに加えてmBaaSなど様々なweb技術のトレンドと出会う機会に恵まれたのが大きな収穫になったと個人的には感じています。

確かにWebRTCを「実運用で」使えるようにしていくのは非常に骨の折れる話だと痛感しましたが、一方で、**webの仕組みでこれだけのパワフルな機能が使えると、P2Pビデオチャット以外にもユースケースが大きく広がる**ことも新たに気づくことができたと思っています。

最後に、非常に雑なコードですが、コードをオープンソース化してみましたので、興味のある方は色々とお試しくだされば幸いです。機会があれば、こちらを使った簡単なアプリの使い方等をご紹介できればと思います。