LoginSignup
17
16

More than 5 years have passed since last update.

PeerJSを用いたリモート監視システムのサンプル

Posted at

WebRTCとNode.jsを用いたリモート監視システムのサンプルを書きました。

WebRTCを自力実装するのは結構面倒なため、PeerJSを利用しています。
またシグナリングサーバもPeerJSが提供するpeerjs-serverを利用しました。

利用したライブラリ

  • peer:0.2.5
  • express:4.2.0
  • node:0.10.28

動作検証した環境

  • Google Chrome 35.0.1916.153 / Mac OS X 10.7.5 / Macbook Air Mid 2011
  • Google Chrome for Android 35.0.1916.141 / Android 4.2.2 / HTL22
  • Google Chrome for Android 35.0.1916.141 / Android 4.0.4 / Vuzix M100

Vuzix M100

Vuzix M100は、Vuzix社が販売する片眼非透過型のスマートグラスです。Android4.0系で動作しており、カメラ・マイク・スピーカーやGPS/3軸センサーなど、ひと通りのセンサー類が搭載されています。

ただし残念なことに、Vuzix M100にデフォルトインストールされている標準ブラウザではWebRTCが動作しません。またGoogle Playも導入されていないため、Play StoreからWebRTCが動作するブラウザをインストールすることもできません。

そこで今回は、別のAndroidデバイスからGoogle Chrome for AndroidのAPKファイルをadb pullし、Vuzix M100にadb installすることで、Vuzix M100上でGoogle Chromeを利用できるようにしました。
(Vuzix M100のVendorIDは "0x1bae" です)

コア部分

PeerJSを使いP2Pでカメラ映像や音声の交換、及びイベント送受信を行う部分です。CoffeeScriptで書かれています。

全体構造

remote-monitor.coffee
ns = do ->
  exports = {}

  host = 'xxx.xxx.xxx.xxx' #シグナリングサーバのホスト名(or IPアドレス)'
  port = 0000 #シグナリングサーバを動作させているポート番号
  path = '/remote-monitor' #シグナリングサーバのPATH
  debug = 3

  class exports.RemoteMonitor
    ...

  exports

Globalにはnsという変数のみを公開し、これを今回のアプリの名前空間とします。hostやport等の変数は即時関数内のみ利用可能で、ns名前空間に公開するのはRemoteMonitorコンストラクタ関数のみとしています。

以下のJavascriptコードと同じです。

remote-monitor.js
var ns = (function() {
  var exports = {};
  var host = 'xxx.xxx.xxx.xxx';
  ...
  function RemoteMonitor() {...}
  exports.RemoteMonitor = RemoteMonitor;
  return exports;
})();

RemoteMonitor

remote-monitor.cofee
  class exports.RemoteMonitor
    constructor: ->
      # peerオブジェクトの作成
      # シグナリングサーバへの接続実施
    initialize: (video, initializing, waiting) ->
      # WebRTCを用いてカメラとマイクのmediastreamを取得
      # stream取得成功後、マイクは一旦OFFにする
    onOpen: (peerIDsetting) ->
      # peerの'open'イベントリスナを登録する
      # シグナリングサーバとの接続が確立すると'open'イベントが発火し、接続元ごとのユニークIDが採番される
    onError: (showError, waiting) ->
      # peerの'error'イベントリスナを登録する
    onConnection: ->
      # peerの'connection'イベントリスナを登録する
      # 別のpeerからconnect要求が発行されると発火する
    onCall: (video, connecting, waiting) ->
      # peerの'call'イベントリスナを登録する
      # 別のpeerからcall要求が発行されると発火する
      # call要求元へ初期化済みのMediaStreamをanswerする
    makeCall: (callto, video, connecting, waiting) ->
      # calltoで指定したpeerへcall要求を送る
    closeCall: ->
      # 確立済みのcallを閉じる
    toggleMIC: ->
      # 自分自身のマイクのON/OFFをトグルする
      # 接続済みのpeerに対し、connect要求を発行して'mic-on','mic-off'メッセージを送信する
    terminate: ->
      # 全ての接続を破棄し、peerオブジェクトを無効化する

    __connect: (call, video, waiting) ->
      # 接続してきたリモートpeerに対し、MediaStreamが確立した場合のイベントハンドラとリモートpeerが切断された場合のイベントハンドラを登録する

WebRTC関連処理を実装したコンストラクタ関数です。device.htmlとmonitor.htmlから利用されます。

処理の流れ

モニター側

初期化

  1. constructor実行により、シグナリングサーバとの接続する
  2. peerのerrorイベントリスナを登録する
  3. シグナリングサーバとの接続が確立するとpeerのopenイベントが発火する
  4. initialize実行により、ローカルカメラ・マイクのMediaStreamを取得する
  5. MediaStream取得に成功すると、monitor.htmlから渡されたwaitingコールバック関数を呼び出す(接続したいpeerのIDを入力するフォームが画面に表示される)

デバイスへ接続

  1. 画面から接続するデバイスのIDを入力し、CALLボタンを押す
  2. makeCall関数が起動し、指定したpeerへcall要求を送る
  3. call要求が成功すると、接続したデバイスのMediaStreamをラップするMediaConnectionオブジェクトが得られる
  4. monitor.htmlから渡されたconnectingコールバック関数を呼び出す(デバイスのカメラ映像が画面に表示される)

デバイスへMIC ON要求

  1. 画面上のMIC ONボタンを押す
  2. toggleMIC関数が起動し、ローカル(モニター側)のマイクをONにする
  3. 接続したpeerへconnect要求を送る
  4. connectionが確立した後、得られたDataChannelへ'mic-on'メッセージをsendする

デバイスを切断

  1. 画面上のEND CALLボタンを押す
  2. closeCall関数が起動し、接続時に得られたMediaConnectionオブジェクトをcloseする

デバイス側

初期化

  1. constructor実行により、シグナリングサーバとの接続する
  2. peerのopen, error, connection, callイベントリスナを登録する
  3. シグナリングサーバとの接続が確立するとpeerのopenイベントが発火し、ユニークIDが採番される
  4. initialize実行により、ローカルカメラ・マイクのMediaStreamを取得する
  5. MediaStream取得に成功すると、device.htmlから渡されたwaitingコールバック関数を呼び出す(自身のIDが画面に表示される)

モニター側から接続

  1. モニター側からのcall要求が届くとpeerのcallイベントが発火し、モニター側のカメラとマイクのMediaStreamが得られる
  2. device.htmlから渡されたconnectingコールバック関数を呼び出す(デバイスのカメラ映像が画面に表示される)

モニター側からのMIC ON要求

  1. モニター側からconnect要求が届くとpeerのconnectionイベントが発火し、モニターとデバイス間でDataChannelが確立する
  2. DataChannelを通じてデータが届くとconnectionのdataイベントが発火する
  3. 届いたdataが'mic-on'の場合、自身のマイクをONにする

モニター側からの切断

  1. モニター側から切断されるとcallのcloseイベントが発火し、waitingコールバック関数を呼び出す(カメラ映像が消え、自身のIDが再び画面に表示される)
17
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
16