Help us understand the problem. What is going on with this article?

スマホと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.png

やったこと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は使えない)

iOS の画像.jpg

最後に

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away