スマホとPCでビデオ通話できるWebページを作ってみた


ブラウザ上でスマホ<->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キーを指定する。

script.js
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」ボタンを作って、オンオフを切り替えられるようにした。

index.html
<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>
script.js
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
    • 自動再生(再生ボタンを押さなくてもビデオが再生される)
index.html
<video id="js-local-stream"></video>
script.js
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は使えない)

最後に

予想よりずっと簡単にビデオ通話が実現できて驚きました。
ぜひ試してみてください。