Hatena::ブログ(Diary)

IT-Walker on hatena このページをアンテナに追加 RSSフィード

2011-12-12

最新のWeb RTC仕様について調べてみた

ワーキングドラフトが公開されたり、IEBlogでも言及されるなど、注目度が一層高まってきた感のあるWeb RTC (Web RealTime Communication)仕様について、改めて調べてみました。


Web RTCは、Webアプリからカメラやマイクでメディアデータを取り込んたり、リモートホストとのP2Pのデータ送受信を行うためのJavaScript APIです。


Web RTCは、以前はWHATWG HTMLの一部として仕様が提案されていましたが、分離して一つの仕様になりました。分離したのはつい最近です。

API自体は単純なので、これまでは仕様書流し読みしてわかった気になっていたのですが、「ローカルからのメディアデータの取り込みとP2Pがなんで同じ仕様にあるんだろう?」とふと疑問に思って、きちんと仕様書を眺めて見ました。同じように疑問に思う方が居らっしゃれば、お役に立つ記事かと思います。


ちなみに現時点では、Web RTCを仕様書通りに実装しているブラウザはありません。

Operaが提供している実験的なビルドデスクトップ版モバイル版の両方があります)で、古い仕様のnavigator.getUserMedia()が動作するのみです。


また、Microsoftが「Media Capture API」という競合仕様を実装したビルドを提供していますが、こちらはWeb RTCとは互換性がありません(Media Capture APIは現在非推奨となり、Web RTCに一本化されます。詳しくはIE Blogこちらの記事をお読みください)。


ほか、Chromeでもソースコードへのマージが開始されたそうです。フル実装を完成させるのは、やはりChromeが最速になりそうですね。


また、W3C内のワーキンググループによってまとめられたユースケースシナリオもあります。ぼくもまだ目を通せていませんが、プレビュー機能や音声入力についても触れられており、APIが今後考慮しなければいけない事項がまとめられています。

https://dvcs.w3.org/hg/dap/raw-file/tip/media-stream-capture/scenarios.html


では、以下にWeb RTCについて調べた結果を書いておきます。

Web RTC概要

Web RTCは、以下のようなユースケースを実現するAPIプロトコルです。

  • デバイスのカメラやマイクから、メディアデータを取り込む
  • リモートのブラウザデバイスから、メディアデータを取り込む
  • そうして取り込んだデータを、video/audio要素を用いて表示できる
  • そうして取り込んだデータを、ローカルに保存できる
  • ローカルファイルに保存されたメディアデータも同様に読み込める
  • リモートのブラウザデバイスに、メディアデータ(に限らず任意のデータ)を送信できる

要は、メディアデータの送信先/受信先を高度に抽象化して、リモートとローカルをあまり意識せずにメディアデータの取り扱いを可能にする、というAPIを志向していると。

それを目指した結果、video/audio要素・デバイスからのメディア取り込み・P2Pを包括した仕様になっているという感じです。


Web RTCは、http://webrtc.org というサイトを中心として、W3CによるJavaScript APIIETFによるネットワークプロトコルの仕様策定が進んでいます。どちらもまだまだドラフト段階なので、この記事で書かれていることが将来にわたって通用する保証は全くありません。

Web RTCのJavaScript API(2011/10/27版をベースに)

現在の最新版の仕様に従い、Web RTCの主なJavaScript APIを紹介します。


navigator.getUserMedia()

このAPIを使用すると、デバイスが持つカメラ/マイクからのデータ取り込みを実現できます。APIはだいたいこんな感じ。

getUserMedia(options, successCallback, errorCallback)

  • options・・・音声と動画のどちらを取り込むか(デフォルトではどちらも取り込む)を指定できる。
  • successCallback・・・取り込み成功時に呼び出されるコールバック。
  • errorCallback・・・エラー時に呼び出されるコールバック。

optionsは、仕様上はMediaStreamOptions型とされていますが、サンプルコードなどを見ると文字列となっています。ぼくの理解では、以下のようにJavaScriptオブジェクトを指定して呼び出すものと思えるのですが、

// 音声のみを取り込む(デフォルトではaudio/videoともにtrue)
navigator.getUserMedia({ audio: true, video: false }, ...)

サンプルを見るかぎり、"audio video"のように、取り込みたいメディアの種類を文字列(スペース区切り)で指定するようです。

navigator.getUserMedia("audio", ...)

現在は過渡期なので、今後どちらの方向に行くか、はたまた全く違うAPIになるかはわかりません。ぼくの感覚では、どちらもあんまりイケていないような・・


第二引数に指定するコールバックは、LocalMediaStream型を引数に取ります。この型の詳細は後述。


第三引数に指定するコールバックは、エラー情報を格納したオブジェクトです。codeプロパティを持ちます。現在のところ、パーミッションエラー以外の状況を想定していないようです。


で、getUserMedia()の利用方法はこんな感じ。カメラから取り込んだ動画(と音声)をvideo要素に与えて再生させるには以下のようなコードになります。

var video = document.getElementById("video");

// 仕様書に忠実なら、「navigator.getUserMedia({}, ...)」となる
navigator.getUserMedia("video audio", function(stream) {
  // 取り込んだストリームデータをURLに変換
  var url = URL.createObjectURL(stream);
  video.src = url;
});

URL.createObjectURL()は、本来URLでは表せない形式のオブジェクトを、ブラウザが処理可能なURL形式の文字列に変換するものです。


Stream API

Web RTCの「メディアデータの送受信先がリモートかローカルか意識しないで済む」という特徴は、全てこのStream APIによる抽象化により実現されています。

その中心的なインターフェースMediaStreamです。先のgetUserMedia()で、成功時に呼び出されるコールバックにもこのインターフェースを実装したオブジェクトが渡されます。


MediaStreamのIDL定義を引用すると以下のようになります。


[Constructor (in MediaStreamTrackList trackList)]

interface MediaStream {

readonly attribute DOMString label;

readonly attribute MediaStreamTrackList tracks;

MediaStreamRecorder record ();

const unsigned short LIVE = 1;

const unsigned short ENDED = 2;

readonly attribute unsigned short readyState;

attribute Function? onended;

};


特にポイントとなるのがrecord()メソッド。これを使用すると、メディアストリームをローカルに保存できます。

record()の戻り値MediaStreamRecorderというインターフェースで、このインターフェースは以下のメソッドをひとつだけ定義しています。

void getRecordedData (BlobCallback? callback);

このメソッドはコールバック関数をひとつだけ引数に取ります。そのコールバックには、保存されたメディアデータを表すBlob型が渡されます。コールバックは複数回呼び出される可能性があります。


ではこれらの知識を元に、カメラ/マイクから取り込んだメディアデータをローカルに保存した後、それをサーバアップロードするようなサンプルコードを考えてみると以下のようになります。

navigator.getUserMedia("video", function(stream) {
  var recorder = stream.record();
  stream.onended = function() {
    recorder.getRecordedData(function(blob) {
      var xhr = new XMLHttpRequest();
      ...
      xhr.send(blob);
    });
  });
});
PeerConnection

そして最後に紹介するのが、リモートホストとのP2P接続を抽象化したインターフェースです。

名前はPeerConnection。IDL定義を抜粋したのが以下。

[Constructor (in DOMString configuration, in SignalingCallback signalingCallback)]

interface PeerConnection {

readonly attribute unsigned short readyState;

void addStream (MediaStream stream, MediaStreamHints hints);

void removeStream (MediaStream stream);

readonly attribute MediaStream[] localStreams;

readonly attribute MediaStream[] remoteStreams;

void close ();

attribute Function? onconnecting;

attribute Function? onopen;

attribute Function? onstatechange;

attribute Function? onaddstream;

attribute Function? onremovestream;

}

まずPeerConnectionは、コンストラクタを用いてオブジェクトを生成します。コンストラクタ引数文字列。STUNやTURNといったプロトコルリモートホストのアドレスを指定します。以下の例では、STUNプロトコルを使用してrelay.example.netの3478番に接続しています。

var con = new PeerConnection("STUN relay.example.net:3478");

こうしてPeerConnectionのオブジェクトを生成したら、addStream()、removeStream()といったメソッドを使ってMediaStreamを追加したり削除したりできます。こうして、リモートホストとのメディアデータ送受信が可能になるわけですね。

con.addStream(stream);

また、接続の状態やストリームの接続数が変化するたびにイベントが発火します。on-で始まる関数がそれです。

これらを使って、リモートからデータを受け取って表示するには、以下のようなコードになるのでしょう。

var video = document.getElementById("video");

// リモートピアに接続
var con = new PeerConnection("STUN example.com");
// ストリームが追加されたことを検知したら、video要素に表示
con.onaddstream = function() {
  var stream = con.remoteStreams[0];
  video.src = URL.createObjectURL(stream);
};

これでWeb RTCの全体像は説明し終えました。今後APIがどうなっていくかはわかりませんが、全体的なコンセプトが変わることは恐らくないでしょう。

現在、Web RTCを試すには

先にも言いましたが、現在Web RTCを仕様通りに実装しているブラウザはありません。

OperaがgetUserMedia()の古い仕様をサポートしているのみです。

それらを試すには、特別なビルドデスクトップ版/Android版)をインストールして、以下のページにアクセスしてみると良いです(この手順は、DEV.OPERAの10/19の記事を参考にしました)。

http://people.opera.com/danield/html5/explode/

このサンプルでは、以下のようなコードでメディアデータの取り込みが実現されています。

var video = document.getElementById("video");
navigator.getUserMedia("video audio", function(stream) {
  video.src = stream;
});

video要素のsrc属性に、getUserMedia()の結果を直接指定できています。以前の仕様ではこれが可能でした(今後、また可能にならないとも限りませんが)。

てな感じで、まだ仕様も全然固まっていないのにWeb RTCについて妙に詳しく書いてしまいました。

今後、すぐに仕様が変わって、この記事の内容が陳腐化しないことを祈ります。。

jovi0608jovi0608 2011/12/13 01:16 白石さん:WebRTCに関しては日本語で解説したものがなかったので、非常に助かります。

>ちなみに現時点では、Web RTCを仕様書通りに実装しているブラウザはありません。

ブラウザとしては非常に(本当に)マイナーですが、 Ericsson の Epiphany も WebKitベースで試験実装されており、最近もリリースされているので、いかがでしょうか?
https://labs.ericsson.com/developer-community/blog/november-2011-release-web-real-time-communication-api

手元の Ubuntu だと仮想環境で実際の video chat のテストではエラーでますので個人的にはまだ動作確認できていませんし、WHATWG/W3C の現ドラフトのサポート状況まで全然把握できていないのでコメントして申し訳ないのですが、 WebRTCに精力的にかかわっている Ericsson の実装は気になるところです。

いつちゃんとリリースされるかはもはや FAQっぽいですが Chrome の WebRTC実装の完了は本当に待ち遠しいです。

SyunpeiSyunpei 2011/12/13 08:43 > Ericsson の Epiphany も WebKitベースで試験実装されており
へえ!知りませんでした。
貴重な情報、ありがとうございます!素晴らしい!

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/Syunpei/20111212/1323679295
リンク元