WebRTCで
ドラゴンボールごっこ
         2012/07/21
  #daiNagoyaJS @girigiribauer
WebRTCとは

• RTCは、Real Time Communication の略
• ローカルデバイスにアクセスするための
 getUserMedia API
• ブラウザとブラウザ同士が直接通信する
 Peer-to-Peer connections API
WebRTCとは

• getUserMedia は   gUM と略されることも
  あるっぽい

• 時代はリアルタイム
ドラゴンボールとは

• みんな大好きドラゴンボール
• 説明不要


          http://www.dragonball2013.com/ より引用
対応状況(※2012/07/21時点)

• みんなの味方、 “When can I use”
 http://caniuse.com/#feat=stream

• Operaはすでに対応
• Chromeもオプションいじればプレ
 フィックス付きで使える
対応状況(※2012/07/21時点)
• Firefox 16(今のNightly)は
 getUserMedia のみに対応予定
 http://hacks.mozilla.org/2012/07/getusermedia-is-
 ready-to-roll/

• これからどんどん増えていきそうで
 楽しみ!
getUserMedia API で
 どんなことできるの?


• 写真とって投稿するのが
 Webアプリでできる

• ARで遊ぶとか
getUserMedia API で
  どんなことできるの?

• 顔認識させたり
 (試してみたけどけっこう重い、
 特別な理由がない限りはネイティブア
 プリ向き?)
 https://github.com/liuliu/ccv
Peer-to-Peer connections API
 でどんなことできるの?

• (Peer to Peer なので)サーバに負荷の
 かかりにくい、双方向なビデオチャッ
 トとか

• (HTML5エロチャットサイトとか
 乱立しそう。。。)
Peer-to-Peer connections API
 でどんなことできるの?


• スマートフォンとか需要ありそうなの
 で、早く対応してくれたらいいな

• 今回はこっちは触れる程度で。。。
JavaScriptでカメラいじれるなら、
   いろいろいじりたい!
JavaScriptでカメラいじれるなら、
    いろいろいじりたい!


• HTMLの要素として扱える
• スタイルもあてられる
• canvasの要素としても
 エフェクト(画像処理)かけられる
これだ!

• Jaylen Becomes A Super Saiyan
  http://www.youtube.com/watch?v=u8szR7LnmlI
これだ!

• 今回はこれが元ネタ
• リアルタイムでやりたい!
ということで、
本日のレシピ
• 1. getUserMedia で映像と音が取れるか
 検証

• 2. 今までのHTML技術との組み合わせ
• 3. Tipsとか
• 4. まとめ
1. getUserMedia で
映像と音が取れるか
      検証
chromeでの API の許可
chromeでの API の許可


• chrome://flags にアクセス
• 「MediaStreamを有効にする」に
 チェックして再起動
getUserMedia APIの
        基本的な使い方
• 仕様はこちら
 http://dev.w3.org/2011/webrtc/editor/
 getusermedia.html#navigatorusermedia

• 呼び出し方は以下の通り
 navigator.webkitGetUserMedia(
    constraints, // devices
    successCallback, // ok
    errorCallback // ng
 );
getUserMedia APIの
     基本的な使い方

• constraints は、どのデバイスに許可
 出すかの指定をオブジェクトで行う

• successCallback は、ユーザーが許可した
 ときに呼ばれるコールバック関数
getUserMedia APIの
      基本的な使い方

• successCallback の引数として
 LocalMediaStream オブジェクトが取得で
 きる

• errorCallback は、それ以外のときに
 呼ばれるコールバック関数
過去に仕様が変わっていて、
動かないサンプルが多いので注意


• 主に第1引数が変わってて、それで動か
 ないサンプルが多い(仕様策定と実装
 が平行で進められているのでしょうが
 ない)
過去に仕様が変わっていて、
動かないサンプルが多いので注意


• "video audio" という文字列指定が、
 { "video": true, "audio": true } のオブジェ
 クト指定に変わった
 http://www.webrtc.org/blog/
 changestoourwebrtcapiimplementation
現時点でオーディオの入力デバイス
(マイク)にアクセスできない(!)

• getUserMedia では、audio指定しても、
 現時点ではまだ取得できない

• 詳しいやりとりはこのへんっぽい
 http://code.google.com/p/chromium/issues/detail?
 id=112367

• 対応してくれるのをおとなしく待つ
「はああああ!!!」とか
言って反応させるとか、
まだできない・・・!?
「はああああ!!!」とか
言って反応させるとか、
まだできない・・・!?




   このタイミングでちょっと萎えた
取得した LocalMediaStream オブジェク
トをきちんと表示するところまで(1)



• canvas要素を作る、もしくは予め作った
    要素を参照する

•   var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
取得した LocalMediaStream オブジェク
トをきちんと表示するところまで(2)


• createObjectURL にさっきの
    LocalMediaStream オブジェクトを
    ぶちこんで、BlobURL(リソースを参照
    してる)を取得する

•   var videoUrl = createObjectURL(stream);
取得した LocalMediaStream オブジェク
トをきちんと表示するところまで(2)

• デバイスをBlobURLとして受け取ること
  で、同様のインターフェースで扱える
  (URL参照 ≒ デバイス参照)

• Blobは Binary Large OBject の略、
  FileAPI 周りでよく使われてる
取得した LocalMediaStream オブジェク
トをきちんと表示するところまで(3)

• video タグの src 属性に、
    さっきの BlobURL をつっこむ

•   var video = document.getElementById('video');
    video.src = videoUrl;
    video.autoplay = true;

• ※autoplay 属性がないと最初の1コマだ
    けで止まっちゃうのでつける
取得した LocalMediaStream オブジェク
トをきちんと表示するところまで(4)

• あとは連続して canvas に video 要素を
    反映してやるだけ

•   var render = function() {
      context.drawImage(video, 0, 0, w, h);
      requestAnimationFrame(render);
    };
    requestAnimationFrame(render);
ここまでのサンプル


•   http://web-utage.com/sample/
    dragonball_super_saiyan/
軽くまとめ
• 1. 表示用の canvas を用意(表示するだ
 けなら video タグだけでOK)

• 2. createObjectURL を使って、デバイス
 アクセス用のBlobURLを取得する

• 3. video タグの src に BlobURL をつっこ
 む(と表示される)
軽くまとめ

• 4. canvas に毎フレーム反映する

• これだけでカメラ画像取得できる、
 なんという素敵な時代に生まれたのか
本日のレシピ
• 1. getUserMedia で映像と音が取れるか
 検証

• 2. 今までのHTML技術との組み合わせ
• 3. Tipsとか
• 4. まとめ
2. 今までのHTML技術
 との組み合わせ
今までのHTML技術との
     組み合わせ

• 音が取れない以上、
 今回はこっちでがんばるしかない
考えられる組み合わせ

• 1. canvas をピクセル単位で
 いろいろいじる

• 2. CSS filter でエフェクトかける
• 3. その他、既存手法いろいろ
1. canvas をピクセル単位で
        いろいろいじる
• context.getImageData()
  配列でピクセルの値を取得

• context.putImageData()
  配列のピクセルの値をセット

• この間でピクセルの数値を変えちゃえ
  ば、簡単にエフェクトかけられる
1. canvas をピクセル単位で
           いろいろいじる
•   var data = context.getImageData(0, 0, 370, 370);
    (中略、黒→黄色とか)
    context.putImageData(data, 0, 0);

• きっと画像処理の分野から応用すれ
    ば、いろいろ良さげなライブラリたく
    さん出てきそう
2. CSS filter
• Chrome18から使える
 http://caniuse.com/#feat=css-filters

• 任意の要素に対して、CSS でフィルター
 かけられる(bodyタグでも)

• このページが比較的分かりやすい
 http://www.html5rocks.com/en/tutorials/filters/
 understanding-css/
2. CSS filter
• grayscale : 白黒フィルター、0 ∼ 100% の
 範囲

• sepia : セピア色、上に同じく
• saturate : 油絵の具で塗ったような感じ
• hue-rotate : 色相を回転させる
• invert : 色を反転させる
2. CSS filter
• opacity : 不透明度(なんでこれあるのか
 分からないけど、読む限りハードウェ
 アアクセラレーションでこっちのがパ
 フォーマンスが良いらしい)

• brightness : 明るさの変化、白く飛ばし
 た感じ
2. CSS filter

• contrast : コントラスト比をいじる
• blur : ぼかし
• drop-shadow : 影効果(これもopacityと
 同じで、CSSにbox-shadowってのがあ
 る)
2. CSS filter

• スペースでつなげて複数指定もできる
    (ただやりすぎると重くなるので注意)

•   -webkit-filter: brightness(0.5) grayscale(1.0);
    →元々黄色いやつを白く飛ばしておくとか
3. その他いろいろ
• かけたいエフェクトにもよるけど、
 複雑なものはPNGとかでテキトーに
 作ってかぶせた方が早い

• JavaScript で canvas のピクセルいじれば
 なんとかできるけど時間の無駄になる
 ことが多い(&めんどくさい)
ここまでのサンプル


•   http://web-utage.com/sample/
    dragonball_super_saiyan/
軽くまとめ
• 結局 canvas に反映しちゃえば、あとは
 canvas に対する操作と何ら変わらない

• Chrome に限れば CSS filter も使えるの
 で表現の幅が広がる
 (&canvas なら楽できる)

• 後は既存の手法とのいいとこ取り
本日のレシピ
• 1. getUserMedia で映像と音が取れるか
 検証

• 2. 今までのHTML技術との組み合わせ
• 3. Tipsとか
• 4. まとめ
3. Tipsとか
navigator.getUserMedia は
       別名で呼べない
• TypeError: Illegal invocation ってエラー
• navigator.getUserMedia を別変数で参照し
  て呼んでもダメ

• プレフィックスの違いを吸収したいと
  きは、関数呼び出しをまるごと返す
navigator.getUserMedia は
                 別名で呼べない
      var getUserMedia = function(t, onsuccess, onerror) {
        if (navigator.getUserMedia) {
          return navigator.getUserMedia(t, onsuccess, onerror);
        } else if (navigator.webkitGetUserMedia) {
          return navigator.webkitGetUserMedia(t, onsuccess, onerror);
        } else if (navigator.mozGetUserMedia) {
          return navigator.mozGetUserMedia(t, onsuccess, onerror);
        } else if (navigator.msGetUserMedia) {
          return navigator.msGetUserMedia(t, onsuccess, onerror);
        } else {
          onerror(new Error("No getUserMedia implementation found."));
        }
      };
http://www.html5rocks.com/ja/tutorials/webgl/jsartoolkit_webrtc/#toc-webrtc より
毎フレームの処理が重くなりがち、
requestAnimationFrame を使った方が
               よさげ



• これは WebRTC に限った話じゃないの
 で、「requestAnimationFrame」でぐぐる
 とたくさん出てくる
毎フレームの処理が重くなりがち、
requestAnimationFrame を使った方が
               よさげ

 var requestAnimationFrame = (function() {
   return window.requestAnimationFrame ||
   window.webkitRequestAnimationFrame ||
   window.mozRequestAnimationFrame ||
   window.msRequestAnimationFrame ||
   window.oRequestAnimationFrame ||
   function(callback, element) {
     setTimeout(callback, 1000 / 60);
   };
 })();
LocalMediaStream→video→canvasの
とき、必ずしもvideoはDOMツリーに
        入れなくともよい


• 今回、特に入力映像をそのまま表示す
  る必要がなかったので、video タグは
  設置してない

• canvas タグだけあればOK
なぜ映像は取れて、
  音だけ使えないのか?
• ゆくゆくは WebRTC と WebAudioAPI と
 の統合が図られているから、かも?
 (英語ちょっと自信ない。。)

• このへんとか参考になるかも
 http://www.html5rocks.com/en/tutorials/
 getusermedia/intro/#toc-webaudio-api
必ずしもJavaScriptで
    解決しなくてもよい
• ガタガタ揺らすエフェクトは、
  JavaScript で CSS の position プロパティ
  いじるとか、斜めなら canvas 内の
  ピクセルいじるしかない

• 今なら CSS animation 内で transform を
  使うだけで揺らせる(斜めにも)
本日のレシピ
• 1. getUserMedia で映像と音が取れるか
 検証

• 2. 今までのHTML技術との組み合わせ
• 3. Tipsとか
• 4. まとめ
4. まとめ
4. まとめ

• WebRTC の可能性
• Web がネイティブになる世界
• リアルタイム性
WebRTC の可能性

• デバイスへのアクセスが一般化すると、
 Webアプリで展開できる種類も増える

• スマートフォン(iOS, Android,
 WindowsPhone)にWebRTCが普及し
 出したころが本当のスタートかも
Web がネイティブになる世界

• デバイスとかの機能を Web API で呼ぶ
 といった、インターフェースが徐々に
 Web ベースになってきてる

• そのうちネイティブはブラウザエンジ
 ンだけになって、やがて Web がネイ
 ティブになる世界(例 : FirefoxOSとか)
リアルタイム性
• パーソナライズ(個々のユーザーに最
 適化)されたものを提供するには、
 その場で作ってその場で返すリアルタ
 イム性が大事

• 単一なものではなく、自分ならではの
 何かが欲しい人たち向け
リアルタイム性
• 誰もキャプチャしてエフェクトつけて
 YouTubeにアップとかしない(2, 3人居たけど)

• でもその場でできるなら、
 ちょっとやってみようかなって気になる

• WebRTC 試してみよう!
 変身コンテンツとか作ってみよう!
ありがとうございました!

WebRTCでドラゴンボールごっこ