Raspberry Pi + Node.jsでSkyWayを動かしてみる


Raspberry PiでSkyWayが動作する[skyway-webrtc-gateway](https://github.com/skyway/skyway-webrtc-gateway)というSDK(?)をNode.jsで使ってみます。

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

先日、ハンズオンが行われたのですが、 **ラズパイにつないだLEDをWebから制御しつつ、その様子を接続したカメラでWebから監視する仕組み**を作りました。

**リモートLチカ監視**ですね。

* イベントページ: [WebRTC初心者歓迎！WebRTC Gatewayハンズオン@NIFcLounge](https://skyway.connpass.com/event/101506/)

* ハンズオン資料: [SkyWay WebRTC Gatewayハンズオン](https://qiita.com/nakakura/items/faeb4f6df82677139761)

> <img src="https://camo.qiitausercontent.com/cdd4d7c47adf9dcaab2381a7693f37d563690580/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3130343435312f35333338653034652d656439382d626438372d326161392d6665346432636638386561332e706e67" width="500">

こんな感じです。

> <img src="https://i.gyazo.com/7edeab4b7144f5f4a98f1495094b35d3.gif" width="500">

当日はRubyで実装を試したのですが、個人的にはNode.jsでやりたいのでNode.jsで動かしてみました。

## Raspberry Piの準備

Raspberry PiのOSのインストールなどは各自やっておきましょう。
ちなみにハードウェアはRaspberry Pi 3 B+を使います。zeroだと動きませんでした。

また、 Node.jsのインストールもしておきましょう。
今回はNode.js v11.0を使っています。

## 関連ソフトウェアの準備

skyway-webrtc-gatewayを利用するにあたりラズパイに関連ソフトウェアをインストールしておきましょう。

```
$ sudo apt install autoconf automake libtool
$ sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
```

```
$ git clone git@github.com:thaytan/gst-rpicamsrc.git
$ cd gst-rpicamsrc
$ ./autogen.sh --prefix=/usr --libdir=/usr/lib/arm-linux-gnueabihf/
$ make
$ sudo make install
```

npmパッケージの[skyway-gateway](https://www.npmjs.com/package/skyway-gateway)を使ってみます。

```
$ npm i skyway-gateway
```

## ハローワールド

### Raspberry Pi側

* app.jsを作成

```app.js
'use strict';
const SkyWay = require('skyway-gateway');
 
const options = {
    apikey: `My SkyWay API Key`,
    peerid: process.argv[2]
}
 
const skyway = new SkyWay(options);
(async () => {
    await skyway.init()
    await skyway.start()
})();
```

* 実行

```
$ node app.js hogehoge
```

peeridというコネクションを識別するためのIDを指定して実行します。このサンプルコードと実行例だとhogehogeがpeeridになります。

### 接続を確認する母艦側

今回は母艦はMacになります。

Macのブラウザで↓のWebサイトを開いて、Raspberry Piのカメラ映像を受け取ります。

```
<!DOCTYPE html>
<html>
    <head lang="ja">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>SkyWay JS SDK Tutorial</title>
    </head>
 
    <body>
        <input type="text" id="target_id_box" />
        <button id="call_button">call</button>
        <br />
        <input type="text" id="chat_box" />
        <button id="chat_button">send message</button>
        <br />
        <video id="remote_video" muted="true" autoplay playsinline="true"></video>
 
        <script src="https://cdn.webrtc.ecl.ntt.com/skyway-latest.js"></script> 
        <script>
            'use strict';
            // Get Parametersを取得するやつ
            function getQueryParams() {
                if (1 < document.location.search.length) {
                    const query = document.location.search.substring(1);
                    const params = query.split('&');
 
                    const result = {};
                    for(var param of params) {
                        const element = param.split('=');
                        const key = decodeURIComponent(element[0]);
                        const value = decodeURIComponent(element[1]);
                        result[key] = value;
                    }
                    return result;
                }
                return null;
            }
 
            window.onload = ()=> {
                const query = getQueryParams();
                // api keyはGet Parameterから取る
                // これは演習で簡単に設定するための雑な処理で推奨ではない
                const key = query["key"];
                //peer idもGet Parameterから取る
                const peer_id = query["peer_id"]
                const peer = new Peer(peer_id, {
                    key: key,
                    debug: 3
                });
 
                peer.on('open', function (a) {
                    console.log(a);
                    // SkyWay Serverに自分のapi keyで繋いでいるユーザ一覧を取得
                    let peers = peer.listAllPeers(peers => {
                        //JavaScript側で入れたやつとRuby側で入れたやつが出てくればよい
                        console.log(peers);
                    });
                });
                peer.on('error', (err) => alert(err.message));
 
                document.getElementById("call_button").onclick = ()=>{
                    const target_id = document.getElementById("target_id_box").value;
 
                    const call = peer.call(target_id, null, {videoReceiveEnabled: true });
                    call.on('stream', (stream) => {
                        document.getElementById("remote_video").srcObject = stream;
                        console.log(call)
                        setTimeout(() => {
 
                        },1000 * 10);
                    });
 
                    const connection = peer.connect(target_id, {serialization: "none"});
                    connection.on('data', (data) => console.log(data));
 
                    document.getElementById("chat_button").onclick = ()=> {
                        const message = document.getElementById("chat_box").value;
                        console.log(message);
                        connection.send(message);
                    };
                };
            };
        </script> 
    </body>
</html>
```

* ローカルサーバーを起動

```
$ python -m SimpleHTTPServer 8080
```

## GPIOを利用

GPIO利用の場合は[onoff](https://www.npmjs.com/package/onoff)というモジュールを使うのが個人的にはオススメです。
他のモジュールはsudo実行が必要だったりと権限周りでこけました苦笑

```
$ npm i onoff
```

```
'use strict';
const SkyWay = require('skyway-gateway');
 
const options = {
    apikey: `My SkyWay API Key`,
    peerid: process.argv[2]
}
 
const skyway = new SkyWay(options);
(async () => {
    await skyway.init()
    await skyway.start()
})();
 
const Gpio = require('onoff').Gpio;
const led = new Gpio(21, 'out');
 
skyway.dataListen((msg, rinfo) => {
  const mes = msg.toString('ascii', 0, rinfo.size);
  console.log(`data len: ${rinfo.size} data: ${mes}`);
 
  if(mes === 'on'){
    led.writeSync(1)
  }else{
    led.writeSync(0)
  }
});
```

* 配線

以下のように21番ピンに配線します。

> <img src="https://camo.qiitausercontent.com/f53b73ef553705220cae21af3f82eaec50a0eb64/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3130343435312f61653431363733352d393137312d353230392d333866642d3862656166306564343132352e706e67" width="400">
> 参考: [SkyWay WebRTC Gatewayハンズオン Chapter0](https://qiita.com/nakakura/items/9d5fb1ff43c40c97c244)

これで実行することで、最初のGIFのようにフォームからonって送るとLEDがついて、offって送るとLEDが消えます。

> <img src="https://i.gyazo.com/7edeab4b7144f5f4a98f1495094b35d3.gif" width="400">

## 所感

ちょっとまだ挙動が不安定な気がするけどとりあえずは動きました。
不安定なところ解消しつつNode.jsプロセスの永続化なども試して知見公開していきたいです。

npmページのREADMEもご確認ください〜

> https://www.npmjs.com/package/skyway-gateway