【PeerJS】HTMLファイルだけでリアルタイムなビデオチャットを作る このエントリをはてなブックマークに登録

2014年03月11日

takurutakuru

sc 2

こんにちは。クレイの浅海です。

皆さんはブラウザを使用するビデオチャットサービスを利用しているでしょうか。

弊社では毎朝ビデオチャットを使用して「朝会」というものをプロジェクト毎に行っています。
そのため、ビデオチャットサービスは無くてはならない存在です。
ビデオチャットサービスに関する情報には敏感なのですが、先日、下の記事が目につきました。

【プラグイン不要】 ブラウザだけでビデオチャットができるサービスまとめ
http://www.ideaxidea.com/archives/2014/03/video_chat.html

これを見て「こんなにたくさんビデオチャットサービスが出ていたのかー」と思うと同時に、エンジニアとしてある一つの仮説が心の中に生まれました。
「あれ、もしかしてビデオチャットサービス作るのって簡単なんじゃね?」と。

作ってみた

結論を先に書きますと、多:多でのビデオチャットを作るのは簡単ではありませんでした。
1:1でのビデオチャットを作るのは簡単だったので、今回はその方法を書いていきます。

実際に作ってみたビデオチャットを下のリンクで試すことが出来ます。
必要最低限のビデオチャット機能しかありません。

https://kray.jp/projects/webrtc/peer.html

このページを開くとまず、カメラとマイクへのアクセスを許可するかどうかをブラウザが尋ねてきます。
これらを許可すると、自分の映像が画面に表示されます。

「あなたのID」という部分があるかと思います。
この右側に表示されている文字列は、自分の電話番号のようなものです。(「番号」ではないですが・・・)

電話をかける方法は、通話したい相手に何らかの手段で「あなたのID」を送り、相手側にあるテキストフォームに「あなたのID」を入力してもらいます。
そして相手が「コール」ボタンを押すことにより、ビデオチャットが開始します。

調査

はじめに紹介したサイトにも【プラグイン不要】と書いてあるように、ブラウザにプラグインを入れなくてもビデオチャットができるサービスが登場しています。

ブラウザのプラグインが必要ないということは、HTML5でビデオやマイクを扱えるWebRTCのMedia Stream APIを使っていることが予想されます。
WebRTCは実装が面倒なので、簡単にWebRTCを扱えるプラグインがないかを調べてみると、PeerJS というライブラリが見つかったので、今回はこれを使いました。

PeerJS

PeerJS
http://peerjs.com/

WebRTCの実装が非常に面倒になる理由として、アイスサーバ、ブローカーサーバという2種類のサーバが必要になるという点が大きいです。
実装が面倒くさい部分である、P2Pのコネクションが確立するまでの色々な手続きだとか、通信状態に影響される繊細な処理だとかを勝手にやってくれます。
自分でサーバを用意しなくても、HTMLファイルを置く場所さえあれば、WebRTCを使ったWebアプリケーションを公開することが出来るようになるので、とても便利です。

WebRTCに関する話は、下の記事が大変参考になりました。ありがとうございます。

WebRTCのオープンソースソフトウェアまとめ
http://qiita.com/atskimura/items/97b2cc04e19781f4a4e6

ブラウザの対応状況

各ブラウザのWebRTCへの対応状況は以下のようになっています。
まだWebRTC自体がWorking Draftのため、全てのブラウザでベンダプレフィックスが必要であり、最新のiPhoneでもまだ使えないようです。

作り方

冒頭で紹介したビデオチャットの作り方を、順を追って説明していきます。

Media Stream API

まず、videoタグでカメラの映像とマイクの音声を再生します。

カメラとマイクを扱うAPIは非常に単純で、以下のソースだけで扱うことが出来ます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>PeerJS sample</title>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
  <script>
  // ベンダプレフィックスの差を吸収する
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

  var myStream;
  $(function(){
    navigator.getUserMedia({audio: true, video: true}, function(stream){
      myStream = stream;
      $('#video').prop('src', URL.createObjectURL(stream));
    }, function(){});
  });
  </script>
</head>

<body>
  <video id="video" autoplay></video>
</body>
</html>

上記ソースのうち、HTMLを無視して見ると、肝となるのは以下の4行だけなのがわかります。

navigator.getUserMedia({audio: true, video: true}, function(stream){
  myStream = stream;
  $('#video').prop('src', URL.createObjectURL(stream));
}, function(){});

myStreamにstreamを代入しているのは、あとで使うからです。

getUserMediaの第2引数が、カメラなどへのアクセスに成功した時のコールバックです。
ここでvideoタグのsrcにビデオの情報をセットしています。

getUserMediaの第3引数はエラー時のコールバックです。
今回は使わないのですが、これを省略するとfirefoxでは動かないようなので、空の関数を渡しています。

PeerJSのAPI key取得

PeerJSが提供するWebRTCに関するサーバを使用するためには、PeerJSのサイトでアカウントを作成し、API keyを生成する必要があります。

http://peerjs.com/peerserver
上記URLを開き、下の図の赤枠で囲った「Developer – Free」という部分からアカウントを作成します。

スクリーンショット 2014-03-06 16.40.33

アカウントを作成してログインすると、下のような画面が見れます。
「Create new API key」という赤いボタンを押すと、API keyを生成できます。

スクリーンショット 2014-03-06 16.42.14

JavaScriptでpeer IDの取得

冒頭で「電話番号」と呼んでいた文字列を取得します。

なにはともあれ、peer.jsを読み込みます。

<script type="text/javascript" src="http://cdn.peerjs.com/0.3/peer.min.js"></script>

peer.jsを読み込むとPeerオブジェクトが使えるようになります。
peerのIDを知るために、Peerのopenイベントを使用します。

  var peer = new Peer({key: 'API key'}); // PeerJSのサイトで取得したAPI keyを設定

  peer.on('open', function(id){
    console.log(id);
  });

正しいAPI keyが設定されていれば、openイベントのコールバックでpeer IDを取得できます。
→ 取得出来ない場合

peer IDにコールする

次に、取得したpeer IDという電話番号に他の人がコール(電話をかける)できるようにします。
以下のようにコールする関数を作ります。

  function callTo(peerId){
    var call = peer.call(peerId, myStream);

    call.on('stream', function(othersStream){
      $('#others-video').prop('src', URL.createObjectURL(othersStream));
    });
  }

callTo関数は、引数に相手のpeer IDを渡すことにより電話をかけることができます。

callして相手の応答があった場合、streamイベントのコールバックで相手のstreamがかえってくるので、自分のstreamを表示したときと同じように、videoタグのsrcに設定します。
そのために、body内に通話相手を表示するvideoタグを追加しておきます。
ここで注意すべきことが1つあり、自分を表示するvideoタグにはmutedを指定しておかないと、酷いハウリングが発生します。

<body>
  <video id="video" autoplay muted></video>
  <video id="others-video" autoplay></video>
</body>

受信側

コール出来るようになったので、そのコールを受ける側を実装します。

  peer.on('call', function(call){
    call.answer(myStream);

    call.on('stream', function(othersStream){
      $('#others-video').prop('src', URL.createObjectURL(othersStream));
    });
  });

誰かからのcallを受信したら相手側に自分のstreamを渡しています。
相手のビデオを表示する方法は、送信側でやった方法と同じで、相手のstreamをvideoタグにセットしているだけです。

UIを作っていないのでJavaScriptコンソールを使用することになりますが、これだけで1:1のビデオチャットができます。

トラブルシューティング

試してみて、なぜか動かない場合は、peerのerrorイベントを拾ってみるとなにかわかるかもしれません。

peer.on('error', function(e){
  console.log(e.message);
});

このようにすると、「API keyが正しくない」「callに失敗」などのエラーがある場合に、コンソールに出力されるようになります。

完成品

ここまで作ってきたビデオチャットを使用するには「JavaScriptコンソールに表示されているpeer IDを相手に伝え、相手もJavaScriptコンソールでcallTo関数を呼ぶ」という使い方になってしまいます。

このままではJavaScriptコンソールのことを知っている技術者しか扱えないため、一般の人でも扱えるようにUIを作成したのが、冒頭で紹介したデモです。
是非実際に誰かと使ってみてください。

https://kray.jp/projects/webrtc/peer.html

おわりに

1:1のビデオチャットは簡単に作ることが出来ました。
ここまで作った後に、多:多のビデオチャットに対応しようとしましたが、映像が3つになった途端にCPUが100%になってしまい使い物になりませんでした。複数人で同期をとるのも面倒です。
多:多のビデオチャットとなると、各チャットサービスは色々と工夫しているようです。

この情報は役に立ちましたか?

宣伝

DocBase

DocBaseとは

小さく始める・みんなで育てる・適切に伝える・安心して伝えるをコンセプトにした情報共有サービスです。
メモという形で小さく始められる、エンジニア以外のメンバーでも使いやすい仕組み、情報をまとめて整理できる、柔軟な権限設定で様々なプロジェクトで使えるなど、積極的な情報共有と業務の効率化を実現し、チームの成長を促します。

詳しくはこちらから。
https://docbase.io

  1. メモからはじめる情報共有 DocBase 無料トライアルを開始
  2. DocBase 資料をダウンロード

「いいね!」で応援よろしくお願いします!

このエントリーに対するコメント

  1. 参考になりました。
    ありがとうございます。

    makoto minakami

    2014年09月20日, 1:14 PM

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


トラックバック

we use!!Ruby on RailsAmazon Web Services

このページの先頭へ