SkyWayを使ってWebRTC開発【入門ハンズオン】

この記事では、SkyWayを使ったWebRTC開発について公式チュートリアルを参考に実例も含め開発の流れを解説します。

JavaScript SDK チュートリアル – SkyWay – Enterprise Cloud WebRTC Platform

WebRTCとは

WebRTCとはW3Cが提唱するリアルタイムコミュニケーション用のAPIの定義で、プラグイン無しでブラウザ間のビデオ通話や音声通話、チャット、ファイルの共有ができる技術です。

WebRTCの通信モデルと技術

これまでのWebでの通信はサーバを経由した通信でしたが、WebRTCはP2Pでやり取りするので、サーバーを介さず直接ブラウザ上で通信が可能になっています。

しかし、通信をするにはお互いのIPアドレス/ポート番号等の情報を教え合わなければなりません。

WebRTCでは、P2Pに必要な情報をお互いに交換するための仕組みのシグナリングや、クライアント同士がP2Pでネットワークを介して繋がるために必要な仕組みのICEなど難しい技術を多く必要とします。しかし、SkyWayを利用することでこれらのほとんどを知らなくてもWebRTCを利用することが出来ます。

参考

WebRTCの事例

  • Maydayボタン(Amazon)
    Kindle Fireタブレットの使い方をビデオ通話と画面共有を使って教えてもらえます。

  • ネット保険デスク(楽天)
    ビデオ通話・テキストチャットシステムを使って、専任アドバイザーに生命保険についてのご相談や楽天生命の商品・手続きについて問い合わせができるサービスです。

  • Skype for Web(Microsoft)
    SkypeのWeb版はRTC技術を利用して提供しています。

  • appear.in
    ブラウザから簡単にビデオ通話やチャット、画面共有が出来多くの人に使われています。

SkyWayとは

SkyWayとはNTT Communicationsが提供するWebRTCアプリ開発者向けプラットフォームです。
SkyWayを利用すると、WebRTCに必要なサーバ構築・運用をすることなく、手軽にビデオ通話や音声通話、データの共有が出来ます。

SkyWayのプロダクト例

  • SkyWay Conference
    アプリのインストールをしないで、ブラウザだけでビデオ通話が可能。
  • BestieBox(サービス終了)
    グループ向けコミュニケーションアプリの無料ビデオ通話機能を採用。ラインのようにチャットが出来スタンプも使える。

開発する前に

まずローカル環境でWebサーバを利用するための準備をしましょう。

live-serverのインストール

お使いのPCにNode.jsがインストールされていることを前提に進んでいきます。

Webサーバをローカル環境で利用するためのアプリはいくつかありますが今回は「live-server」を利用します。

ターミナル又はコマンドプロントで以下のコマンドを実行してください。

$ npm install -g live-server

live-serverの起動方法は、ターミナル又はコマンドプロントで作業ディレクトリに移動し「live-server」と実行することで起動できます。

SkyWayのAPIキーの発行

まずは、SkyWayの開発者登録をしましょう。

SkyWay Community Editionの新規登録

登録が完了した方はダッシュボードにログインし、アプリケーションを作成してAPIキーを取得してください。

ソースコードのダウンロード

プロジェクトを作成するにあたって、今回はチュートリアルのソースコードを利用します。

$ git clone https://github.com/skyway/skyway-js-sdk-tutorial.git
$ cd skyway-js-sdk-tutorial

完成版を確認したい方は、 gh-pages にブランチをチェックアウトしてください。

$ git checkout gh-pages

構成は、以下のようになっています。

.
├── README.md
├── index.html
├── script.js
└── style.css

以降では script.js に追記するコードを解説していきます。

開発開始

今回は、チュートリアルに沿って簡単な発着信の出来るビデオ通話アプリを開発していきます。

それでは開発していきましょう。

カメラ映像,マイク音声の取得

カメラ映像・マイク音声を取得する処理を追記してください。Webブラウザでカメラ映像、マイク音声を取得するためには、getUserMediaというAPIを利用します。
getUserMediaで取得した、Streamオブジェクト(自分のカメラ映像)を表示用のvideo要素にセットします。

let localStream = null;

navigator.mediaDevices.getUserMedia({video: true, audio: true})
    .then(function (stream) {
        // Success
        $('#my-video').get(0).srcObject = stream;
        localStream = stream;
    }).catch(function (error) {
        // Error
        console.error('mediaDevice.getUserMedia() error:', error);
        return;
    });

getUserMediaのConstraints({video: true, audio: true})に以下のような指定をすることも可能です。

  • 例:カメラ映像のみ取り込み、マイク音声は取り込まない
    {video: true, audio: false}
  • 例:カメラ映像のサイズの設定例
    { audio: true, video: { width: 640, height: 480 } }
  • 例:カメラ映像のフレームレートの設定例
    { audio: true, video: { frameRate: { min: 10, max: 15 } } }

SkyWayサーバーへの接続

SDKのインポート

以下のとおりscript要素でSDKをインポートします。
今回はチュートリアルのソースコードを利用するのでindex.htmlに追記済みです。

<script type="text/javascript" src="https://cdn.webrtc.ecl.ntt.com/skyway-latest.js"></script>

Peerオブジェクトの作成

Peerオブジェクトを作成するための処理を追記してください。
apikeyには先程ダッシュボードで発行したAPIキーを指定してください。
debugではログ出力レベルを指定します。3の場合は、開発用に全てのログを出力します。

let localStream = null;
let peer = null;
let existingCall = null;

navigator.mediaDevices.getUserMedia({video: true, audio: true})
    // 省略
});

peer = new Peer({
    key: 'apikey',
    debug: 3
});

Peerオブジェクトで指定可能なその他のオプションについては、APIリファレンスをご覧ください。

接続成功・失敗・切断の処理

Peerオブジェクトに必要なイベントリスナーを追記してください。

openイベント

SkyWayのシグナリングサーバと接続し、利用する準備が整ったら発火します。 SkyWayのすべての処理はこのイベント発火後に利用できるようになります。
PeerIDと呼ばれるクライアント識別用のIDがシグナリングサーバで発行され、コールバックイベントで取得できます。 PeerIDはクライアントサイドで指定することもできます。
以下の処理では、PeerIDが発行されたら、その情報をUIに表示する処理を行っています。

peer.on('open', function(){
    $('#my-id').text(peer.id);
});

errorイベント

何らかのエラーが発生した場合に発火します。エラーが発生したら、警告ダイアログでその内容を表示できるようにします。

peer.on('error', function(err){
    alert(err.message);
});
closeイベント

Peer(相手)との接続が切れた際に発火します。チュートリアルでは特に処理は行いません。

peer.on('close', function(){
});

disconnectedイベント

シグナリングサーバとの接続が切れた際に発火します。チュートリアルでは特に処理は行いません。

peer.on('disconnected', function(){
});

発振・切断・着信の処理

発信、切断、着信をするための処理を追記してください。

発振処理

発信ボタンをクリックした場合に相手に発信します。

peer.call() で相手のPeerID、自分自身のlocalStreamを引数にセットし発信します。
接続するための相手のPeerIDは、別途何らかの方法で入手する必要があります。
発信後はCallオブジェクトが返ってくるため、必要なイベントリスナーをセットします。
setupCallEventHandlersの中身については後ほど説明します。

$('#make-call').submit(function(e){
    e.preventDefault();
    const call = peer.call($('#callto-id').val(), localStream);
    setupCallEventHandlers(call);
});

切断処理

切断ボタンをクリックした場合に、相手との接続を切断します。
call.close()で該当する接続を切断します、発信処理で生成したCallオブジェクトはexistingCallとして保持しておきます。
オブジェクト保持は発信処理のsetupCallEventHandlers()の中で実行します。

$('#end-call').click(function(){
    existingCall.close();
});

着信処理

相手から接続要求がきた場合に応答します。
相手から接続要求が来た場合はcallが発火します。 引数として相手との接続を管理するためのCallオブジェクトが取得できるため、call.answer()を実行し接続要求に応答します。
この時に、自分自身のlocalStreamをセットすると、相手にカメラ映像・マイク音声を送信することができるようになります。
発信時の処理と同じくsetupCallEventHandlersを実行し、 Callオブジェクトのイベントリスナーをセットします。

peer.on('call', function(call){
    call.answer(localStream);
    setupCallEventHandlers(call);
});

Callオブジェクトに必要なイベント

今回作るアプリでは既に接続中の場合は一旦既存の接続を切断し、後からきた接続要求を優先します。 また、切断処理等で利用するため、CallオブジェクトをexistingCallとして保持しておきます。
この処理はアプリの仕様次第です。
更に、相手のカメラ映像・マイク音声を受信した際に発火します。
取得したStreamオブジェクトをvideo要素にセットします。
addVideo()setupEndCallUI()の中身については後ほど説明します。

function setupCallEventHandlers(call){
    if (existingCall) {
        existingCall.close();
    };

    existingCall = call;

    call.on('stream', function(stream){
        addVideo(call,stream);
        setupEndCallUI();
        $('#their-id').text(call.remoteId);
    });
    // 省略
}

call.close()による切断処理が実行され、実際に切断されたら発火します。このイベントは、call.close()実行した側、実行された側それぞれで発火します。call.peerで切断した相手のPeerIDを取得できます。
切断時にはvideo要素の削除とUI関連の処理をを削除します。removeVideo()setupMakeCallUI()の中身については後ほど説明します。

function setupCallEventHandlers(call){
    // 省略
    call.on('close', function(){
        removeVideo(call.remoteId);
        setupMakeCallUI();
    });
}

UIセットアップ

video要素の再生

VIDEOを再生するための処理を追記してください。

video要素のsrcObjectプロパティにStreamオブジェクトをセットすることで再生できます。 削除する処理のことを考えて、idプロパティにcall.peer(PeerID)をセットします。

function addVideo(call,stream){
    $('#their-video').get(0).srcObject = stream;
}

video要素の削除

切断された(した)相手のvideo要素を削除するための処理を追記してください。 PeerIDを元に削除します。

function removeVideo(peerId){
     $('#' + peerId).remove();
}

ボタンの表示・非表示切り替え

発信ボタン、切断ボタンの表示を切り替えるための処理を追記してください。

function setupMakeCallUI(){
    $('#make-call').show();
    $('#end-call').hide();
}

function setupEndCallUI() {
    $('#make-call').hide();
    $('#end-call').show();
}

動作

まずは、ダッシュボードの確認をします。
今回はlive-serverを使うのでドメインに 127.0.0.1 を追加してください。

自身の環境に合わせてドメインは変えてください。

$ live-server .

live-serverを起動したらコードの入っているフォルダを選択することで、アプリを立ち上げられます。

外部に公開したい

ローカル環境でサーバーを立ち上げてだけでは、外部のネットワークからアクセスできず、開発したビデオチャットを実用的に試せません。
外部に公開したい場合は、外部からアクセス可能なWEBサーバー上にファイルを設置し、HTTPSで公開する必要があります。

サーバを用意するのは手間でお金もかかりますが、「GitHub Pages」や「Firebase Hosting」などのサービスを使うと、無料で公開できます。

もっと手軽に外部に公開したい場合は、「ngrok」を使うのがオススメです。ローカル環境を以下のようなコマンド一発で、外部に公開することができます。

$ ngrok http 8080(ローカル環境のポート番号)
外部に公開する際は、SkyWayの設定画面からドメインを追加する必要があります。

参考

より高度な開発がしたい人向けに

今回解説したビデオチャットの基本的な機能以外に、応用として付け加えることのできる機能としては、以下のようなものがあります。
参考にしてみてください!