LoginSignup
4
2

More than 3 years have passed since last update.

SkyWayをNoodl上で使ってビデオ通話をしてみた

Last updated at Posted at 2020-05-15

概要

前回はSkyWayサンプルプログラムを使ってP2Pのビデオ通話システムを構築しました。
ですが、その時はNoodlを簡易Webサーバとして利用しただけで、Noodl本来のビジュアルプログラミング部分は活用できていませんでした。
今回はSkyWayのサンプルプログラムをNoodl上のJavascriptノードに実装することができたので、その内容をまとめておきます。

1. 完成画面とサンプルデータ

今回は下記のような画面を作ります。

今回の完成画面イメージ

img0008_result.png

ほぼサンプルと同じデザインです。画面下のメッセージボックスはMQTTを使ったシンプルなメッセンジャとなっています。
左の送信BOXに入力した内容をパブリッシュ。右の受信BOXでサブスクライブしています。
ビデオ通話を開始する前に相手と確認を行ったり、どちらかのPeerIDを送る用途で使えます。

サンプルデータ

プロジェクトファイルはこちらからCloneできます。デモサイトも用意しています。

※デモサイトはAPIキー、MQTTサーバの設定をしていないためそのまま使用することはできません。
プロジェクトファイルを自身の環境で使う場合には、Cloneしたフォルダのにある/Noodl2_WebRTCDemoのフォルダをImportしてください。

また、JavascriptノードのSKYWAY_KEYにSkyWayのサイトで取得したAPIキーを入力してください。

2. SkyWayのセットアップ

まずはSkyWayのサンプルを作るための事前準備を行います。SkyWayを利用するためには使用するドメインの設定とAPIキーの取得が必要です。下記手順でAPIキーの取得まで実施してください。

  1. SkyWayのサイトでアカウントを作成
  2. アプリケーションの作成:アプリを利用可能とするドメイン追加
  3. APIキーの取得

詳しくは前回の記事を参照ください。

3. Noodlで画面を作る

Noodlを起動して2つのコンポーネントを作ります。今回は2つ作りました。

  1. Button :ボタンのコンポーネント
  2. Main :今回作成した画面コンポーネント

img0003_result.png

開発方針としては、UI部分はNoodlを使い。WebCamの操作含めビデオ通話にかかわる部分は丸ごと1つのJavascriptノードに入れています。流用するときはこのJavascriptノードだけをコピペすれば使えるイメージです。

Buttonコンポーネント

画面で使うボタン部品を作成します。ボタンを押すと色が変わりclick信号を発火する機能を持っています。
各ノードの設定はサンプルプロジェクトを確認してください

Noodlでノード設定後、下図のようにつなぎます。

img0005_result.png

Mainコンポーネント

メインとなる画面コンポーネントを作成します。
各ノードの設定はサンプルプロジェクトを確認してください。
ここでは通信にかかわるMessageノードとJavascriptノードを説明します。

Messageノードの設定

MQTTメッセンジャを作るためSend Messageノード、Recive MessageノードをText Inputノードに接続します。

img0002_result.png

送信したメッセージが受取れるよう、MessageノードのTopix:p2pMedia(任意)を合わせ、PAYLOADにポートを追加します。今回はmsg(任意)を追加しました。
また、Send MessageはSend On Changeのチェックを付けて、 ポート変更時に送信するようにしています。
img0040_result.png

MQTTサーバを設定します。丸と丸がつながったようなアイコンがMESSAGE BROKERSの設定となります。デフォルトではNoodl上の簡易MQTTサーバが設定されています。Noodlで実験する場合はこのままでOKです。
img0042_result.png

外部のMQTTサーバを使うときにはパネル下部にあるCREATE NEW BROKERボタンから外部MQTTサーバの説明、URLを設定してください。
img0043_result.png

現状のNoodl2.0はWorkSpaceを共有しているため、作成したMQTTサーバの設定まで共有してしまいます。
最終的にDeployする直前にだけMQTTサーバの設定を行って。Deploy後は設定を削除しておきましょう。

Javascriptノードの設定

ビデオ通話部分のJavascriptノードには下記スクリプトをコピペします

Javascriptノード
define({
  inputs: {
    mySignal: 'signal',
    SKYWAY_KEY: 'string',
    callTrigger: 'signal',
    closeTrigger: 'signal',
    localVideo: 'domelement',
    remoteVideo: 'domelement',
    remoteId: 'string',
  },

  outputs: {
    localId: 'string',
  },

  //const mediaConnection;
  closeTrigger: function (inputs, outputs) {
    mediaCon.close(true);
  },

  callTrigger: function (inputs, outputs) {
    console.log("call");
    if (!peer.open) {
      return;
    }

    const mediaConnection = peer.call(inputs.remoteId, localStr);
    mediaCon = mediaConnection;

    mediaConnection.on('stream', async stream => {
      // Render remote stream for caller
      inputs.remoteVideo.srcObjec = stream;
      inputs.remoteVideo.playsInline = true;
      await inputs.remoteVideo.play().catch(console.error);
      console.log("--StartPlay");
    });

    mediaConnection.once('close', () => {

      inputs.remoteVideo.srcObject.getTracks().forEach(track => track.stop());
      inputs.remoteVideo.srcObject = null;
    });
  },

  // All signal inputs need their own function with the corresponding name that
  // will be run when a signal is received on the input.
  mySignal: function (inputs, outputs) {
    let Peer = window.Peer;
    let self = this;

    (async function main() {
      const localStream = await navigator.mediaDevices
        .getUserMedia({
          audio: true,
          video: true,
        })
        .catch(console.error);
        localStr=localStream;

      // Render local stream
      inputs.localVideo.muted = true;
      inputs.localVideo.srcObject = localStream;
      inputs.localVideo.playsInline = true;
      await inputs.localVideo.play().catch(console.error);
      const peer = (window.peer = new Peer({
        key: inputs.SKYWAY_KEY,
        debug: 3,
      }));
      pee=peer;

      // Register callee handler
      peer.once('open', id => {
        outputs.localId = id;
        self.flagOutputDirty("localId");
        //self.runNextFrame();
      });

      // Register caller handler
      peer.on('call', mediaConnection => {
        mediaCon = mediaConnection;
        mediaConnection.answer(localStream);

        mediaConnection.on('stream', async stream => {
          // Render remote stream for callee
          inputs.remoteVideo.srcObject = stream;
          inputs.remoteVideo.playsInline = true;
          inputs.remoteVideo.playsInline = true;
          await inputs.remoteVideo.play().catch(console.error);
        });

        mediaConnection.once('close', () => {
          inputs.remoteVideo.srcObject.getTracks().forEach(track => track.stop());
          inputs.remoteVideo.srcObject = null;
        });
      });

      peer.on('error', console.error);

    })();
  },

  // This function will be called when any of the inputs have changed
  change: function (inputs, outputs) {
    // ...
  }
})

let mediaCon;
let localStr;

Javascriptノードの解説

基本的にはSkyWayのサンプルコードのままです。
Noodl向けに変えたところは

  1. Javascriptノードの入出力を作っているところ。
  2. ボタンイベントでaddEventListener('click'となっていたところをsignalに変更
  3. 非同期で変更された出力をNoodlに反映させるためにflagOutputDirty("outputName") の追加

ノードの接続

Noodlでノードを設定しつなぎます。
上からVideo部分、PeerID表示、接続・切断ボタン部分、MQTTチャット部分となっています。

node.png

ビデオ通話に関連するJavascriptノードの入出力は下記のようになっています。

Javascriptノードの入力:
- RemoteVideo:Dom Element を Javascript:remoteVideoに接続
- LocalVideo:Dom Element を Javascript:localvideoに接続
- 相手のPeerIDが入るTextInput:TextをJavascript:remoteIdに接続
- CallボタンButton:clickをJavascript:callTriggerに接続
- closeボタンButton:clickをJavascript:closeTriggerに接続
- 外部ライブラリ読込完了を通知するためScriptDlonloader:LoadedをJavascript:mySignalに接続

Javascriptノードの出力:
- 自分のPeerID表示用にJavascript:localIdをTextInput:Textに接続

最後に、JavascriptのSKYWAY_KEYにはSkyWayで取得したAPIキーを入力しておきます。これで完成です。

4. 実行

最後に動作チェックをします。
まずはNoodlの簡易Webサーバを使って確認しましょう。

Webcamはセキュリティの問題でlocalhostへのHTTP通信かHTTPS通信のサイトでなければ実行できません。
そのためURLはlocalhostと書き換えてアクセスしてください。

http://localhost:8574/external/viewer/index.html?device=Main

初めてサイトにアクセスすると、カメラ・マイクへのアクセス許可確認のダイアログが表示されます。許可にして完了ボタンを押せばカメラの映像が表示されるはずです。
img0009_result.png

img0039_result.png

まとめ

これでSkyWayをNoodl上で使い、P2Pのビデオ通信を行うことができました。
・・・と言いたいのですが、実は上記内容は不具合があります。相手からの受信は問題なくできるのですが。こちらから呼び出しをした場合、相手側のWebCamの映像を受取れないのです。相手にはこちらの画像は見えていますが、こちらの画面には相手が見えません。
非同期処理の書き方でどこかが悪いのですが、理解できていないところがあり修正できませんでした。解決策わかりましたら続報します。

さらに、SkyWayにはSkyWay WebRTC Gatewayと言うものもありました。
こちらではブラウザ上での通信だけでなく、IoT機器との通信をサポートしているそうです。

4
2
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
4
2