Open18

Skywayチュートリアルコードの解析

SanQSanQ

実行環境(ブラウザ)・・・Google Chrome
実行結果

SanQSanQ

表示画面を構成するHTML

  1 <html lang="ja">                                                                                                                          
  2         <head>
  3                 <meta charset="UTF-8">
  4                 <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5                 <title>WebRTC Test</title>
  6                 <script src="https://cdn.webrtc.ecl.ntt.com/skyway-4.4.1.js"></script>
  7         </head>
  8         <body>
  9                 <video id="my-video" width="400px" autoplay muted playsinline></video>
 10                 <p id="my-id"></p>
 11                 <textarea id="their-id"></textarea>
 12                 <button id="make-call">発信</button>
 13                 <button id="call-end">通話終了</button>
 14                 <video id="their-video" width="400px" autoplay muted playsinline></video>
 15                 <script src="./rtc.js"></script>
 16         </body>
 17 </html>

(通話終了は独自に作成したものなので、取り扱わない。)

SanQSanQ

ブラウザのカメラ、音声を取得するJSコード

  1 //音声、カメラの取得                                                                                                                      
  2 let localStream; //このファイル内のグローバル変数
  3
  4 navigator.mediaDevices.getUserMedia({video: true, audio: true})
  5 .then( stream => {
  6         const videoElm = document.getElementById('my-video');
  7         videoElm.srcObject = stream;
  8         videoElm.play();
  9
 10         localStream = stream;
 11 }).catch( error => {
 12         console.error('mediaDevice.getUserMedia() error:', error);
 13         return;
 14 });
 15
SanQSanQ

navigatorはブラウザのJS(javascriptを以降はこのように省略する)を取り扱うエンジンによってあらかじめ定められたグローバルなプロパティ。このプロパティを呼び出すことにより、アプリのユーザーが使用するブラウザの状態や情報(ブラウザが使用するメディアの情報、そのブラウザが動いているデバイスの位置情報など)をアプリ側が取得できる。
参考記事
https://developer.mozilla.org/ja/docs/Web/API/Navigator

SanQSanQ

navigatorが所有する読み取り専用プロパティであるmediaDevicesはブラウザのカメラやマイクなどのメディア入力装置へのアクセスを提供するmediaDeviceオブジェクトを返す。
mediaDeviceが返された後、このオブジェクトが有する関数であるgetUserMediaが実行される。このメソッドはブラウザのメディア入力の許可をユーザーに求め、最終的にPromiseオブジェクトを返し、ユーザーが許可した場合、thenメソッドの引数(今回はstream)からMediaStreamオブジェクトが利用できるようになる。
getUserMediaメソッドの引数からmediaStreamにて扱うメディア入力の種類(トラック)を制約するMediaStreamConstraintsオブジェクトが作成(?)され、もしユーザーの音声と映像が取得したい場合は、その引数は{ audio: true, video: true }となる。audiovideoの両オブジェクトの値を変えることで映像の解像度を指定するなどのさらなる制約を付け加えることもできる。

参考記事
https://developer.mozilla.org/ja/docs/Web/API/Navigator/mediaDevices
https://developer.mozilla.org/ja/docs/Web/API/MediaDevices
https://developer.mozilla.org/ja/docs/Web/API/MediaDevices/getUserMedia
https://developer.mozilla.org/ja/docs/Web/API/MediaStreamConstraints

SanQSanQ

Promiseオブジェクトのthenメソッドを見る。
まずはid="my-video"で指定されたvideo要素のオブジェクトを変数videoElmに代入し、そのオブジェクトが有するsrcObjectプロパティにMediaStreamオブジェクトを代入する。srcObjectプロパティはメディアが利用できるHTMLElement(<video>など)に含まれるプロパティであり、HTMLElementで利用するメディアソースを提供するオブジェクトが入る。ここに入るオブジェクトの種類は、MediaStreamMediaSourceBlobFileがあるが注釈を見ると2017年11月のブラウザはMediaSrreamのみしかサポートしていないため、srcObjectに何かを代入するときはMediaStreamオブジェクトのみにした方がよさそう。

参考記事
https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/srcObject

SanQSanQ

変数videoElmplayメソッドを実行し、先ほどsrcObjectに代入されたメディアソースが再生される。playメソッドはHTMLElementにあらかじめ含まれているメソッドであり、最終的にPromiseを返すので、今回は実装していないがcatchメソッドを用いて失敗時の処理を実装することもできる。ちなみに<video src="流したい動画">に対してplayメソッドを使用すると流したい動画を再生させることができる。つまりこのメソッドによりHTMLMediaElement.srcプロパティにあるメディアソースも再生される。

参考記事
https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/play
https://developer.mozilla.org/ja/docs/Web/API/HTMLMediaElement/src

SanQSanQ

最後にMediaStreamオブジェクトをグローバル変数であるlocalStreamに代入し、次の処理へ移る。
もし処理が失敗していた場合は、catchメソッド以降の処理へ移り、失敗を告げるコンソール出力とともにすべての処理をここで終える。

SanQSanQ

次はSkyWayを使用してほかのユーザーと通信を行う処理についてみていく。
まずはここから

 //Peer idの取得
 17 const peer = new Peer({
 18         key: '各々Skywayで登録したAPI',
 19         debug: 3
 20 });
 21 peer.on('open', () => {
 22         document.getElementById('my-id').textContent = peer.id;
 23 });

ちなみにこれ以降の処理はSkyWayをCDNなどでアプリ上で利用できる状態でないと作動しない。

SanQSanQ

PeerクラスはSkyWayを使用するうえで必要不可欠なクラス。このクラスはnew Peer(id, option)またはnew Peer(option)の二つから呼び出し可能で、今回は後者で呼び出している。idはユーザーがほかのユーザーと通信を行う際に必要なPeer IDというもので、指定しない場合は自動で作成される。optinonはSkywayの接続時のオプションを指定するオブジェクトで、keyにアプリ製作者がSkyWayを利用するために作成したAPIキーを代入しないと通信ができない。debugは通信時にブラウザのコンソールに何を出力するのか決められるもので、今回は通信時の情報の全てを出力するように指定している。

参考記事
https://webrtc.ecl.ntt.com/api-reference/javascript.html#peer

SanQSanQ

onメソッドはPeerクラスに含まれるもので、第一引数のイベント(今回はopen)の実行時に実行される。openイベントとはPeerインスタンスの生成時にシグナリングサーバとの接続が鵜なくいった際に発生するイベントであり、今回は他のユーザーと通信する際に必要なPeer IDをブラウザ上の決まった要素へ表示するようにしている。
シグナリングサーバとは、SkyWayが提供している、通信するユーザー同士のIPアドレスなどの通信に必要な情報をそのユーザー間で交換する機能を持つサーバである。

参考記事
https://skyway.github.io/js-reference/Peer.html
https://webrtc.ecl.ntt.com/skyway/overview.html#_1-シグナリングサーバ

SanQSanQ

次はSkyWayの発信処理を見る。

 25 //発信処理
 26 document.getElementById('make-call').onclick = () => {
 27         const theirId = document.getElementById('their-id').value;
 28         const mediaConnection = peer.call(theirId, localStream);
 29         setEventListener(mediaConnection);
 30 };
SanQSanQ

id='make-call'の要素をクリックした場合、以下の三つを実行する。

  • id="their-id"の要素の値を変数theirIdへ代入
  • Peerインスタンスのcallメソッドの結果を変数mediaConnectionへ代入。callメソッドは接続を管理するMediaConnectionインスタンスを返すメソッドであり、第一引数に接続先の他のユーザーが所有するPeer IDを、第二引数にブラウザのストリームの音声・映像の情報を有するMediaStreamオブジェクトが入り、第三引数に発信時のオプションを入れることもできる。
  • 独自に作成したsetEventListenerメソッドに変数mediaConnectionを引数にとったものを実行する。このメソッドは次に説明する

参考記事
https://webrtc.ecl.ntt.com/api-reference/javascript.html#members

SanQSanQ
 32 setEventListener = mediaConnection => {                                                                                                  
 33         mediaConnection.on('stream', stream => {
 34                 const videoElm = document.getElementById('their-video');
 35                 videoElm.srcObject = stream;
 36                 videoElm.play();
 37         });
 38 }
SanQSanQ

setEventListenerメソッドの処理は以下の通り。
引数のmediaConnectionオブジェクトのイベントを発火するメソッドであるonメソッドにの第一引数に'stream'を指定して実行。もし'stream'を指定した場合、MediaStreamを受信した場合に第二引数のクロージャを実行する。ここで使用するクロージャの引数streamにはあとで見ていく着信処理の中のmediaConnectionオブジェクトのanswerメソッドから送られてきたMediaStreamオブジェクトが入る。その後の処理は先ほど見ていったブラウザに自分のストリームを表示する処理と同じ。

参考記事
https://webrtc.ecl.ntt.com/api-reference/javascript.html#methods-2

SanQSanQ

最後に着信処理

 41 //着信処理
 42 peer.on('call', mediaConnection => {
 43         mediaConnection.answer(localStream);
 44         setEventListener(mediaConnection);
 45 });
SanQSanQ

この処理は着信側のみが行い、送信側は行わない。
Peerインスタンスが入っているpeerオブジェクトのonメソッドはmediaConnectionオブジェクトと同様にイベントメソッドで、第一引数にcallが指定された場合にはpeer.call()の実行時に第二引数のMediaConnectionのインスタンスが代入されたmediaConnectionオブジェクトを引数にとったクロージャが実行される。mediaConnectionオブジェクトのanswerメソッドはPeerIDを持ったほかのユーザーが自分のPeerIDへ接続があった場合に実行するもので、第一引数のMediaStreamオブジェクト(今回はlocalStream)を接続元のPeer IDを持つブラウザへ送信する。第二引数に応答時のオプションを指定することもできる。最後に送信元からのMediaStreanオブジェクトを含んだmediaConnectionオブジェクトを引数にとり、送信側と同様にsetEventListenerメソッドを実行し、送信元のストリームを受信側のブラウザにも映す。

参考記事
https://webrtc.ecl.ntt.com/api-reference/javascript.html#events
https://webrtc.ecl.ntt.com/api-reference/javascript.html#members-2