ブラウザ上でスマホ<->PC間のビデオ通話を試したので、過程等々を記録します。
WebRTCに触れるのは初めてでしたが、SkyWay公式のサンプルコードが最高で、ほとんど手を加えることなく実現できました。
同じ初学者の方が全体感を掴む助けになれば幸いです。
技術要素
- WebRTC: ブラウザ上でリアルタイム通信する技術
- SkyWay: WebRTCを簡単に使うためのプラットフォーム
- skyway.js: WebRTCを簡単に使うためのJavascriptライブラリ
- nginx: Webサーバ
- ngrok: ローカル環境を簡単に外部公開できるサービス
確認環境
PC: ubuntu18.04.3 LTS (Bionic Beaver) / Chrome 78.0.3904.97
iPhone: 12.4.1 / Safari
iPad: 13.1 / Safari
android: 7.1.1 / Chrome 70.3538.64
(バージョン古いですが。。。)
全体の流れ
- SkyWayのアカウントを作成
- SkyWayにログインし、アプリケーションをつくる
- SkyWay公式のサンプルコードをclone
- サンプルコードを微調整
- ローカルPCにWebサーバを立てる
- ngrokでローカルPCのWebサーバを外部公開
- スマホからアクセスして動作確認
やったこと1 〜SkyWayのセットアップ〜
SkyWayのアカウントを作成し、アプリケーションをつくる。
やったこと2 〜コード微調整〜
SkyWay公式のサンプルコードをclone。
git clone https://github.com/skyway/skyway-js-sdk
cd skyway-js-sdk
# npm ci ←index.htmlとscript.jsだけなのでnpmは不要
examples/p2p-media に1対1のビデオ通話のサンプルコードがある。
ほぼほぼそのまま使えるが、以下の点を変更した。
APIキーの追加
SkyWayと接続できるよう、APIキーを指定する。
window.__SKYWAY_KEY__ = '前項で作成したアプリケーションのAPIキー';
これだけで実機で問題なく動作した(神)。
以降は機能追加の記録です。
カメラの指定
getUserMedia()の引数によって、デバイスや帯域、サイズの指定ができる。(cf. MediaStreamConstraints)
スマホ特有の内容として、facingMode: 'user'
で液晶側のカメラ、
facingMode: 'environment'
で背面のカメラを指定できる。
const localStream = await navigator.mediaDevices
.getUserMedia({
audio: true,
- video: true,
+ video: { facingMode: 'user' }, // 液晶側のカメラ
})
ミュート
カメラとマイクのミュートは、公式ドキュメント通りにすれば問題なくできた。
今回は、適当に「Toggle Camera」「Toggle Microphone」ボタンを作って、オンオフを切り替えられるようにした。
<div class="toggle-mute">
<button id="js-toggle-camera">Toggle Camera</button>
<span id="camera-status"></span>
<br>
<button id="js-toggle-microphone">Toggle Microphone</button>
<span id="microphone-status"></span>
<br>
</div>
const toggleCamera = document.getElementById('js-toggle-camera');
const toggleMicrophone = document.getElementById('js-toggle-microphone');
const cameraStatus = document.getElementById('camera-status');
const microphoneStatus = document.getElementById('microphone-status');
toggleCamera.addEventListener('click', () => {
const videoTracks = localStream.getVideoTracks()[0];
videoTracks.enabled = !videoTracks.enabled;
cameraStatus.textContent = `カメラ${videoTracks.enabled ? 'ON' : 'OFF'}`;
});
toggleMicrophone.addEventListener('click', () => {
const audioTracks = localStream.getAudioTracks()[0];
audioTracks.enabled = !audioTracks.enabled;
microphoneStatus.textContent = `マイク${audioTracks.enabled ? 'ON' : 'OFF'}`;
});
videoタグの要素
videoタグは、muted, autoplayなどの要素をつけることで動作を設定できる。
ここは地味にハマりポイントだった。
- muted
- trueだと、自分の音声が自分のスピーカーから聞こえなくなる
- muted=trueでも自分の音声は相手に届く。相手の音声も自分に届く。
- muted=trueにしないとiPhoneでは複数のvideoタグが使えない(参考) (←ハマりポイント)
- playsinline
- インライン再生するための属性
- iPhoneでvideoタグを使う場合は必須(参考) (←ハマりポイント)
- autoplay
- 自動再生(再生ボタンを押さなくてもビデオが再生される)
<video id="js-local-stream"></video>
const localVideo = document.getElementById('js-local-stream');
localVideo.srcObject = localStream;
localVideo.muted = true; // 自分の音声を自分のスピーカーから聞こえなくする。相手には届く。
localVideo.playsInline = true;
localVideo.autoplay = true;
やったこと3 〜公開して動作確認〜
ngrokが便利すぎる
を参考にローカルでWebサーバ(nginx)を起動し、ngrokで公開した。
# nginxの設定
$ vi /etc/nginx/sites-available/default
#--設定内容-------------
# 12345番ポートで接続待ち受け
listen 12345 default_server;
listen [::]:12345 default_server;
# サンプルコードを公開
# ※index.htmlとscript.jsだけなので、特にビルドはいらない
root (前略)/skyway-js-sdk/examples/p2p-media;
#---------------
# nginx起動
$ sudo nginx
# 起動確認(12345ポートでLISTENしている)
$ netstat -anp | grep 12345
tcp 0 0 0.0.0.0:12345 0.0.0.0:* LISTEN -
# ngrok実行
$ ngrok http 12345
# ngrok実行結果
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account (Plan: Free)
Update update available (version 2.3.35, Ctrl-U to update)
Version 2.3.34
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://d21b048e.ngrok.io -> http://localhost:12345
Forwarding https://d21b048e.ngrok.io -> http://localhost:12345
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
やったこと4 〜動作確認〜
ngrokを起動時に表示されるアドレス(↑だとhttps://d21b048e.ngrok.io
)は、インターネット経由でアクセスできる。
PCとスマホ実機からアクセスして、動作確認を行った。
(注意: httpsのアドレスを使うこと。httpだと、WebRTCは使えない)
最後に
予想よりずっと簡単にビデオ通話が実現できて驚きました。
ぜひ試してみてください。