Chrome拡張機能 タブ間WebRTC用シグナリングサーバーシミュレーター

WebRTCのサンプルコード(クライアント)などを試したいとき、シグナリングサーバーを用意する必要があり少々面倒です。
そこで、シグナリングサーバーの代わりをやってくれる拡張機能を作ってみました。
Chromeでかつタブ間での通信というかなり限られた環境用となりますが、シグナリングサーバーを用意する手間が省けます。
(ルーム機能などは一切ありません。)
[シグナリングサーバーシミュレーター](https://www.dropbox.com/s/w61p8jch7xpmrvm/SignalingServerSim.crx)

##使用方法
以下のコードを、コードに追加します。

```js
var SignalingChannelSim = function () {
    var btnSender = document.createElement('input');
    btnSender.type = 'button';
    btnSender.style.display = 'none';
    btnSender.id = 'btnRTCSender';
    btnReceiver = document.createElement('input');
    btnReceiver.type = 'button';
    btnReceiver.style.display = 'none';
    btnReceiver.id = 'btnRTCReceiver';
    btnReceiver.onclick = (function () {
        var evt = { data: btnReceiver.value };
        this.onmessage && this.onmessage(evt);
    }).bind(this);
    document.body.appendChild(btnSender);
    document.body.appendChild(btnReceiver);
    this.send = function (message) {
        btnSender.value = message;
        btnSender.click();
    }
};
```

コードを見るとわかるとおり、ボタンを使って拡張機能を通して他のタブにメッセージのやり取りを行うというものです。

##使用例

```html
<!DOCTYPE html>
<html>
<head>
    <title>シグナリングサーバーシミュレーター使用例</title>
    <meta charset="utf-8" />
</head>
<body>
    <video id="selfView" autoplay></video>
    <video id="remoteView" autoplay></video>
    <input type="button" onclick="start()" value="接続" />
    <script>
        var SignalingChannelSim = function () {
            var btnSender = document.createElement('input');
            btnSender.type = 'button';
            btnSender.style.display = 'none';
            btnSender.id = 'btnRTCSender';
            btnReceiver = document.createElement('input');
            btnReceiver.type = 'button';
            btnReceiver.style.display = 'none';
            btnReceiver.id = 'btnRTCReceiver';
            btnReceiver.onclick = (function () {
                var evt = { data: btnReceiver.value };
                this.onmessage && this.onmessage(evt);
            }).bind(this);
            document.body.appendChild(btnSender);
            document.body.appendChild(btnReceiver);
            this.send = function (message) {
                btnSender.value = message;
                btnSender.click();
            }
        };
    </script>
    <script>
        // WebRTCサンプルコード

        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        window.RTCPeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
        var signalingChannel = new SignalingChannelSim();
        var configuration = { "iceServers": [{ "url": "stun:stun.example.org" }] };
        var pc;

        function start() {
            pc = new RTCPeerConnection(configuration);
            pc.onicecandidate = function (evt) {
                evt.candidate && signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
            };
            pc.onnegotiationneeded = function () {
                pc.createOffer(localDescCreated, logError);
            }
            pc.onaddstream = function (evt) {
                remoteView.src = URL.createObjectURL(evt.stream);
            };
            navigator.getUserMedia({ "audio": false, "video": true }, function (stream) {
                selfView.src = URL.createObjectURL(stream);
                pc.addStream(stream);
            }, logError);
        }

        function localDescCreated(desc) {
            pc.setLocalDescription(desc, function () {
                signalingChannel.send(JSON.stringify({ "sdp": pc.localDescription }));
            }, logError);
        }

        signalingChannel.onmessage = function (evt) {
            !pc && start();
            var message = JSON.parse(evt.data);
            message.sdp && pc.setRemoteDescription(new RTCSessionDescription(message.sdp), function () {
                (pc.remoteDescription.type == "offer") && pc.createAnswer(localDescCreated, logError);
            }, logError);
            message.candidate && pc.addIceCandidate(new RTCIceCandidate(message.candidate), function () { }, logError);
        };

        function logError(error) {
            console.log(error);
        }
    </script>
</body>
</html>
```