話題の記事

[HTML5] MediaStream APIを使ったライブチャットを作ってみよう

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

MediaStream APIとは

WebRTC (Web Real-Time Communication)で定義されているAPIの一つで、ローカルのWebカメラやマイクからストリームデータを取得するためのAPIです。MediaStream APIの詳細はW3Cでドラフトが公開されています。 http://dev.w3.org/2011/webrtc/editor/getusermedia.html

MediaStream APIでは、通信時のストリームについて定義されています。これによって、Webカメラから取得した画像やマイクから取得した音声は、加工することが可能です。

MediaStream APIの使い方

今回はMediaStream APIの中で定義されている getUserMedia メソッドを使います。

最初にnavigator.getUserMedia関数が使えるか確認します。 W3Cでは、navigator.getUserMediaと定義されていますが、まだドラフト段階なのでベンダープレフィックスがついています。

  • navigator.webkitGetUserMedia: WebKit用
  • navigator.mozGetUserMedia: Mozira用
  • navigator.msGetUserMedia: Microsoft用


よって、利用する際には、下記のように書いてベンダー毎にチェックします。

navigator.getUserMedia = ( navigator.getUserMedia ||
                           navigator.webkitGetUserMedia ||
                           navigator.mozGetUserMedia ||
                           navigator.msGetUserMedia);

次にnavigator.getUserMediaを使ってMediaStreamを取得します。 取得したMediaStreamからWebカメラとマイクのデータにアクセスできるようになります。
navigator.getUserMediaを使うと非常に簡単にWebカメラをVideoタグに表示することができます。 getUserMedia() の最初のパラメータでは、アクセスするメディアのタイプを指定します。

navigator.getUserMedia(
    {video:true},
    function(stream) {
        videoElement.src = URL.createObjectURL(stream);
    }
);

サンプル: ライブチャット(画像のみ/音声なし)

今回はWebカメラの映像を使ったライブチャットを作ってみます。

クライアントサイド

まず、Webカメラ映像をWebP( http://html5experts.jp/jxck/2550/ )形式の画像に変換します。

navigator.getUserMediaでMediaStreamを取り出してVideoタグで再生させます。

<video id="video" autoplay width="240" height="160"></video>
navigator.getUserMedia(
    {video: true},
    function(stream) {
        video.src = window.URL.createObjectURL(stream);
    }
);

そしてCanvasに再生中のVideoを描画します。 この場合のCanvasはVideoを書き込むだけのバッファ的な利用になるのでスタイルで隠しておきます。

<canvas style="display:none;" width="640" height="480"></canvas>
canvas.getContext('2d').drawImage(video, 0, 0);

canvasに描画できたのでwebp形式のData URLスキームに変換します。 Data URLスキームは、data:から始まる文字列です。

imgData = canvas.toDataURL('image/webp');

Webp形式の画像はバイナリなのでbase64形式で文字列化あれています。

data:image/webp;base64,UklGRpgSAABX...z3gAAA==

そして、このData URLスキーム形式となったwebp画像データをWebSocket経由で相手に投げます。 投げるタイミングは、サーバの負荷や帯域などを考慮してきまます。

$("#join").click(function(){
    ...
    camInterval = setInterval(updateCam,1000);
});

function sendCamImage(){
    updateCamImage();
    primus.write({ action: 'img', room: room, img: camImage });
}

サーバサイド

今回チャット機能は、Primusを使います。 Primusは、Node.jsのリアルタイムWebのフレームワークのラッパーライブラリです。 そして、PrimusでWebSocketのなかでEngine.IOをつかっています。

var primus = new Primus(server, {
  transformer: 'engine.io',
  parser: 'JSON'
});
primus.use('rooms', PrimusRooms);

それに加えてチャットのルーム機能を実現するためにPrimusにルーム機能を追加するPrimus-Roomsライブラリを使います。

primus.on('connection', function (spark) {
  spark.on('data', function (data) {
    data = data || {};
    var action = data.action;
    var room = data.room;
    if ('join' === action) {
      spark.join(room, function () {
        console.log(spark.id + " is join at " + room);
      });
      return;
    } else if ('leave' === action) {
      spark.leave(room, function () {
        console.log(spark.id + " is join at " + room);
      });
    } else if ('msg' === action) {
        spark.room(room).write(data);
    } else if ('img' === action) {
        spark.room(room).write(data);
    } else {}
  });
});

まとめ

MediaStream APIを使うと簡単にローカルのWebカメラにアクセスすることができました。今回は、Webカメラから取得したデータを使ってライブチャットを作成してみました。他にもCanvas連携して画像処理や顔認識などに応用してみてはいかがでしょうか。
次回は音声ありのライブチャットをつくってみます。