Skywayチュートリアルコードの解析
解析するコードが記載された記事
SkyWay Javascript SDK
実行環境(ブラウザ)・・・Google Chrome
実行結果
表示画面を構成する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>
(通話終了は独自に作成したものなので、取り扱わない。)
ブラウザのカメラ、音声を取得する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
navigator
はブラウザのJS(javascriptを以降はこのように省略する)を取り扱うエンジンによってあらかじめ定められたグローバルなプロパティ。このプロパティを呼び出すことにより、アプリのユーザーが使用するブラウザの状態や情報(ブラウザが使用するメディアの情報、そのブラウザが動いているデバイスの位置情報など)をアプリ側が取得できる。
参考記事
navigator
が所有する読み取り専用プロパティであるmediaDevices
はブラウザのカメラやマイクなどのメディア入力装置へのアクセスを提供するmediaDevice
オブジェクトを返す。
mediaDevice
が返された後、このオブジェクトが有する関数であるgetUserMedia
が実行される。このメソッドはブラウザのメディア入力の許可をユーザーに求め、最終的にPromise
オブジェクトを返し、ユーザーが許可した場合、then
メソッドの引数(今回はstream
)からMediaStream
オブジェクトが利用できるようになる。
getUserMedia
メソッドの引数からmediaStream
にて扱うメディア入力の種類(トラック)を制約するMediaStreamConstraints
オブジェクトが作成(?)され、もしユーザーの音声と映像が取得したい場合は、その引数は{ audio: true, video: true }
となる。audio
、video
の両オブジェクトの値を変えることで映像の解像度を指定するなどのさらなる制約を付け加えることもできる。
参考記事
Promise
オブジェクトのthen
メソッドを見る。
まずはid="my-video"
で指定されたvideo要素のオブジェクトを変数videoElm
に代入し、そのオブジェクトが有するsrcObject
プロパティにMediaStream
オブジェクトを代入する。srcObject
プロパティはメディアが利用できるHTMLElement(<video>など)
に含まれるプロパティであり、HTMLElement
で利用するメディアソースを提供するオブジェクトが入る。ここに入るオブジェクトの種類は、MediaStream
、MediaSource
、Blob
、File
があるが注釈を見ると2017年11月のブラウザはMediaSrream
のみしかサポートしていないため、srcObject
に何かを代入するときはMediaStream
オブジェクトのみにした方がよさそう。
参考記事
変数videoElm
がplay
メソッドを実行し、先ほどsrcObject
に代入されたメディアソースが再生される。play
メソッドはHTMLElement
にあらかじめ含まれているメソッドであり、最終的にPromise
を返すので、今回は実装していないがcatch
メソッドを用いて失敗時の処理を実装することもできる。ちなみに<video src="流したい動画">
に対してplay
メソッドを使用すると流したい動画を再生させることができる。つまりこのメソッドによりHTMLMediaElement.src
プロパティにあるメディアソースも再生される。
参考記事
最後にMediaStream
オブジェクトをグローバル変数であるlocalStream
に代入し、次の処理へ移る。
もし処理が失敗していた場合は、catch
メソッド以降の処理へ移り、失敗を告げるコンソール出力とともにすべての処理をここで終える。
次は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などでアプリ上で利用できる状態でないと作動しない。
Peer
クラスはSkyWayを使用するうえで必要不可欠なクラス。このクラスはnew Peer(id, option)
またはnew Peer(option)
の二つから呼び出し可能で、今回は後者で呼び出している。id
はユーザーがほかのユーザーと通信を行う際に必要なPeer IDというもので、指定しない場合は自動で作成される。optinon
はSkywayの接続時のオプションを指定するオブジェクトで、key
にアプリ製作者がSkyWayを利用するために作成したAPIキーを代入しないと通信ができない。debug
は通信時にブラウザのコンソールに何を出力するのか決められるもので、今回は通信時の情報の全てを出力するように指定している。
参考記事
on
メソッドはPeer
クラスに含まれるもので、第一引数のイベント(今回はopen
)の実行時に実行される。open
イベントとはPeer
インスタンスの生成時にシグナリングサーバとの接続が鵜なくいった際に発生するイベントであり、今回は他のユーザーと通信する際に必要なPeer IDをブラウザ上の決まった要素へ表示するようにしている。
シグナリングサーバとは、SkyWayが提供している、通信するユーザー同士のIPアドレスなどの通信に必要な情報をそのユーザー間で交換する機能を持つサーバである。
参考記事
次は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 };
id='make-call'
の要素をクリックした場合、以下の三つを実行する。
-
id="their-id"
の要素の値を変数theirId
へ代入 -
Peer
インスタンスのcall
メソッドの結果を変数mediaConnection
へ代入。call
メソッドは接続を管理するMediaConnection
インスタンスを返すメソッドであり、第一引数に接続先の他のユーザーが所有するPeer IDを、第二引数にブラウザのストリームの音声・映像の情報を有するMediaStream
オブジェクトが入り、第三引数に発信時のオプションを入れることもできる。 - 独自に作成した
setEventListener
メソッドに変数mediaConnection
を引数にとったものを実行する。このメソッドは次に説明する
参考記事
32 setEventListener = mediaConnection => {
33 mediaConnection.on('stream', stream => {
34 const videoElm = document.getElementById('their-video');
35 videoElm.srcObject = stream;
36 videoElm.play();
37 });
38 }
setEventListener
メソッドの処理は以下の通り。
引数のmediaConnection
オブジェクトのイベントを発火するメソッドであるon
メソッドにの第一引数に'stream'
を指定して実行。もし'stream'
を指定した場合、MediaStream
を受信した場合に第二引数のクロージャを実行する。ここで使用するクロージャの引数stream
にはあとで見ていく着信処理の中のmediaConnection
オブジェクトのanswer
メソッドから送られてきたMediaStream
オブジェクトが入る。その後の処理は先ほど見ていったブラウザに自分のストリームを表示する処理と同じ。
参考記事
最後に着信処理
41 //着信処理
42 peer.on('call', mediaConnection => {
43 mediaConnection.answer(localStream);
44 setEventListener(mediaConnection);
45 });
この処理は着信側のみが行い、送信側は行わない。
Peer
インスタンスが入っているpeer
オブジェクトのon
メソッドはmediaConnection
オブジェクトと同様にイベントメソッドで、第一引数にcall
が指定された場合にはpeer.call()
の実行時に第二引数のMediaConnection
のインスタンスが代入されたmediaConnection
オブジェクトを引数にとったクロージャが実行される。mediaConnection
オブジェクトのanswer
メソッドはPeerIDを持ったほかのユーザーが自分のPeerIDへ接続があった場合に実行するもので、第一引数のMediaStream
オブジェクト(今回はlocalStream
)を接続元のPeer IDを持つブラウザへ送信する。第二引数に応答時のオプションを指定することもできる。最後に送信元からのMediaStrean
オブジェクトを含んだmediaConnection
オブジェクトを引数にとり、送信側と同様にsetEventListener
メソッドを実行し、送信元のストリームを受信側のブラウザにも映す。
参考記事