webrtc + web audio api = スーパーサイヤ人
Post on 27-May-2015
6.590 Views
Preview:
DESCRIPTION
TRANSCRIPT
WebRTC + Web Audio API =スーパーサイヤ人
2013/02/23 #daiNagoyaJS vol.5
13年2月23日土曜日
いつもぎりぎり、@girigiribauerです
13年2月23日土曜日
本日のネタは、大なごやJS Vol.3で話したネタの完全版です
13年2月23日土曜日
今日話す内容
13年2月23日土曜日
今日話す内容
1.作ってきたコンテンツの概要
2.デモ
3.WebRTC, Web Audio API などの話
4.まとめ
13年2月23日土曜日
13年2月23日土曜日
今日話す内容
1.作ってきたコンテンツの概要
2.デモ
3.WebRTC, Web Audio API などの話
4.まとめ
13年2月23日土曜日
WebRTC +
13年2月23日土曜日
WebRTC + Web Audio API =
13年2月23日土曜日
WebRTC + Web Audio API =スーパーサイヤ人
13年2月23日土曜日
ドラゴンボールとは
•みんな大好きドラゴンボール
•サイヤ人は、金色の髪のスーパーサイヤ人に変身する
•変身すると強くなるのは男のロマン
映画あるよ! http://www.dragonball2013.com/
13年2月23日土曜日
スーパーサイヤ人になってみたかった
13年2月23日土曜日
元ネタ
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
respect!
• i'm a super saiyanhttp://www.youtube.com/watch?v=lIv88cC86r0
13年2月23日土曜日
全力投球の中二病は
coolだと思う
13年2月23日土曜日
そして前回・・・
13年2月23日土曜日
リベンジネタ
• 実は大なごやJS Vol.3 でやったネタ(2012/07/21)
• 前回は、ホントに軽く作ってみた
13年2月23日土曜日
リベンジネタ
•あれ、音声がとれない → まだ未実装
•(本番当日)「ク、クリックで・・・ 代用しました・・・」
13年2月23日土曜日
13年2月23日土曜日
13年2月23日土曜日
まさかのクリック
13年2月23日土曜日
ユーザー体験としては 0点
13年2月23日土曜日
それも今や昔の話・・・
13年2月23日土曜日
君もなれる!スーパーサイヤ人に!
13年2月23日土曜日
13年2月23日土曜日
今日話す内容
1.作ってきたコンテンツの概要
2.デモ
3.WebRTC, Web Audio API などの話
4.まとめ
13年2月23日土曜日
デモ• なれる!スーパーサイヤ人!
http://girigiribauer.com/dragonball-super-saiyan/
13年2月23日土曜日
満 足
13年2月23日土曜日
13年2月23日土曜日
今日話す内容
1.作ってきたコンテンツの概要
2.デモ
3.WebRTC, Web Audio API などの話
4.まとめ
13年2月23日土曜日
使用した主なAPIなど
• WebRTC (getUserMedia)
• Web Audio API
• Canvas
13年2月23日土曜日
このあたりの話をピンポイントで抜粋して紹介
13年2月23日土曜日
使用した主なAPIなど
• WebRTC (getUserMedia)
• Web Audio API
• Canvas
13年2月23日土曜日
WebRTC (getUserMedia)
• RTCは、Real Time Communication の略
•その中の getUserMedia は、ローカルにあるカメラ、マイクにアクセスできる
13年2月23日土曜日
対応状況
• http://caniuse.com/stream
(※2013/02/23時点)
13年2月23日土曜日
対応状況(※2013/02/23時点)
• Chrome, Operaに続いてFirefoxも getUserMedia が使える!
• Firefoxはabout:configのフラグ付き
• IEは、そもそもCU-RTC-Webという別仕様を推進してる(CU: Customizable, Ubiquitous)
13年2月23日土曜日
getUserMedia の基本的な使い方
• navigatorオブジェクトにあるgetUserMedia メソッド
•引数を3つ取る
• 1つ目は、デバイスの種別指定のオブジェクト(テキストではない)
13年2月23日土曜日
getUserMedia の基本的な使い方
• 2つ目は、ローカルデバイスにアクセスが出来たときに生成される、mediaStream オブジェクトを引数にもつ、コールバック関数
• 3つ目は、上記失敗したときのコールバック関数
13年2月23日土曜日
getUserMedia の基本的な使い方
•そこまで複雑じゃない、数行レベル
•クロスブラウザな書き方は、navigator.getUserMediaに対して上書きできないので、ちょっと工夫する
13年2月23日土曜日
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 { throw new Error('No getUserMedia implementation found.'); } };
• navigator.getUserMediaごと返す
•あとはfunctionでラッピングするなり
13年2月23日土曜日
getUserMedia の基本的な使い方
•デバイスへの接続がうまくいった後、とりあえず表示させるまでの話(前回の資料をさらっと再紹介)
13年2月23日土曜日
取得した LocalMediaStream オブジェクトをきちんと表示するところまで
(1)
• canvas要素を作る、もしくは予め作った要素を参照する
• var canvas = document.getElementById('canvas');var context = canvas.getContext('2d');
13年2月23日土曜日
取得した LocalMediaStream オブジェクトをきちんと表示するところまで
(2)
• createObjectURL にさっきの LocalMediaStream オブジェクトをぶちこんで、BlobURL(リソースを参照してる)を取得する
• var videoUrl = createObjectURL(stream);
13年2月23日土曜日
取得した LocalMediaStream オブジェクトをきちんと表示するところまで
(2)
•デバイスをBlobURLとして受け取ることで、同様のインターフェースで扱える(URL参照 ≒ デバイス参照)
• Blobは Binary Large OBject の略、FileAPI 周りでよく使われてる
13年2月23日土曜日
取得した LocalMediaStream オブジェクトをきちんと表示するところまで
(3)
• video タグの src 属性に、さっきの BlobURL をつっこむ
• var video = document.getElementById('video');video.src = videoUrl;video.autoplay = true;
•※autoplay 属性がないと最初の1コマだけで止まっちゃうのでつける
•単に表示のみなら、ここまででOK
13年2月23日土曜日
取得した LocalMediaStream オブジェクトをきちんと表示するところまで
(4)
•あとは連続して canvas に video 要素を反映してやるだけ
• var render = function() { context.drawImage(video, 0, 0, w, h); requestAnimationFrame(render);};requestAnimationFrame(render);
13年2月23日土曜日
video は分かったでは audio は?
13年2月23日土曜日
その前に、Web Audio API
を考える必要がある
13年2月23日土曜日
使用した主なAPIなど
• WebRTC (getUserMedia)
• Web Audio API
• Canvas
13年2月23日土曜日
Web Audio API
• 文字通り、Web の Audio の API
• ノードというオブジェクト同士をつなぎ合わせることで制御する
•中にはAnalyserノード、数値として解析できちゃうものもある
•仕様が幅広くて、まだまだ全容把握できてない
13年2月23日土曜日
対応状況
• http://caniuse.com/audio-api
(※2013/02/23時点)
13年2月23日土曜日
対応状況(※2013/02/23時点)
• Chrome, Safari, iOS Safari が使える
•つい数日前に、Firefox Nightly にてWeb Audio API がフラグ付きで導入
• Firefox21 か 22 あたりでWeb Audio API が正式実装される?
13年2月23日土曜日
対応状況(※2013/02/23時点)
• Firefox では、about:config からmedia.webaudio.enabled を true に
• ただし、Firefoxはまだ完全じゃないところもある(詳しくは後述)
13年2月23日土曜日
Web Audio API で今回やりたいこと
• 今回やりたいのは、入力から数値として取れるところまで
•出力側は必ずしも必要ではない
•ライブ入力の音声を、リアルタイムに周波数として取れれば良いので、AnalyserNode を使えばOK
13年2月23日土曜日
少し戻って・・・
13年2月23日土曜日
前回の資料より
13年2月23日土曜日
ここでようやく今回のキモ
13年2月23日土曜日
WebRTC +
13年2月23日土曜日
WebRTC + Web Audio API =
13年2月23日土曜日
WebRTC + Web Audio API =スーパーサイヤ人
13年2月23日土曜日
WebRTC + Web Audio API =スーパーサイヤ人(=ライブ音声入力)
13年2月23日土曜日
ドコとドコが繋がっているの?
• 先ほどの getUserMedia で出てきたmediaStream オブジェクトを対象のメソッドに渡して連携させる
• video側は、createObjectURL(stream) を使ってBlobURLを取得し、video.src として利用していた
13年2月23日土曜日
ドコとドコが繋がっているの?
• audio側は、AudioContext オブジェクトを用いる
• audio周りの処理が、AudioContext オブジェクトのメソッドを介して行われる
•なので、まず AudioContext を作る
• var context = getAudioContext();
13年2月23日土曜日
ドコとドコが繋がっているの?
• video側の createObjectURL(stream) の、audio側に相当しているものは、context.createMediaStreamSource(stream)
• 意味はそのまんま、mediaStream を 入力として作ります、と書いてある
• 2つの仕様が連携することで、逆にvideoよりもシンプルで分かりやすい
13年2月23日土曜日
ライブ音声入力の周波数ごとの値を
取得できるところまでの流れ
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (1)
• AudioContext を作る
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (2)
• AudioContext に対して、createMediaStreamSource メソッドを呼ぶと、MediaStreamAudioSourceNode という 出力用のノードが取得できる
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (3)
• 先ほどとは別に、AudioContext に対して createAnalyser メソッドを呼ぶと、AnalyserNode という、音データの解析ができるノードが取得できる
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (4)
•(今すぐ必要ではないけど、)あらかじめ周波数分のUint8Array型の型付き配列(Typed Array)を作っておく
•ただの配列でも良いけど、速度の問題
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (5)
• source は出力オンリーなので、audioAnalyserノードの入力につなぐ
• mediaStream オブジェクトから、audioAnalyserノードの入力までがつながった
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (6)
• audioAnalyserノードの getByteFrequencyData メソッドを任意のタイミングで呼ぶことで、型付き配列 audioAnalyzedData に毎回データが入る
var context = getAudioContext();var source = context.createMediaStreamSource(stream);var audioAnalyser = context.createAnalyser();var audioAnalyzedData = new Uint8Array(audioAnalyser.frequencyBinCount);source.connect(audioAnalyser);audioAnalyser.getByteFrequencyData(audioAnalyzedData);
13年2月23日土曜日
取得した LocalMediaStreamオブジェクトを、値として処理
できるところまで (7)
• 後はただの配列に対する処理
•今回のコンテンツでは、簡素化するために周波数ごとの平均値を取り、それを時間軸に対しても平均化(一瞬だけ音がでかくなることがあるのを反応しないようにならす)
•平均化された数値をしきい値と比較
13年2月23日土曜日
Web Audio API
•まだまだ機能は豊富にあるけど、きりがないので一旦この辺で・・・
• AnalyserNode だけでも、色々応用考えられそう
•例:音声入力だけで操作するゲーム
•例:絶対音感を再現するとか
13年2月23日土曜日
おまけ
• Q. Firefoxではライブ音声入力できないの?
• A. まだAudioContext のメソッドが足りないっぽいです
13年2月23日土曜日
おまけ• context.create
MediaStreamSource がないですね・・・
•これがないと、ライブ音声入力をつなぐことが出来ません
13年2月23日土曜日
使用した主なAPIなど
• WebRTC (getUserMedia)
• Web Audio API
• Canvas
13年2月23日土曜日
Canvas
• 前回もちょっと使ったけど、今回はよりCanvasに向いている表現にトライ
•気が溜まっていく表現は、下から上に放射線上に変化していってほしい
•(ここから先はおまけです)
13年2月23日土曜日
Canvas
• 先行して検証用コンテンツを作ってみた
• radical arrowhttp://jsdo.it/pypupypa/radical-arrow
13年2月23日土曜日
Canvas
13年2月23日土曜日
Canvas におけるsave(), restore()
• 自分も最初に Canvas を触ったころ、勘違いして理解できなかったところ
• context.save() は、Canvasのピクセル情報を保持するのではなく、contextを保持する
•ここでいうcontextの保持とは、Canvasの回転、変形具合や色など
13年2月23日土曜日
Canvas におけるsave(), restore()
• 実はこの矢印の座標計算、x軸をプラスにすることだけやっている
•回転角度から、sin, cosを使ってx, yがいくつで、次の移動が・・・みたいなことはやってない
13年2月23日土曜日
Canvas におけるsave(), restore()
context.save();...context.translate(canvasWidth / 2, canvasHeight / 2);context.rotate(rad);context.translate(-canvasWidth / 2, -canvasHeight / 2);context.drawImage(image, x, y);...context.restore();
•まず context.save() で 今のcontext を保存しておく(あとで戻すため)
13年2月23日土曜日
Canvas におけるsave(), restore()
13年2月23日土曜日
Canvas におけるsave(), restore()
context.save();...context.translate(canvasWidth / 2, canvasHeight / 2);context.rotate(rad);context.translate(-canvasWidth / 2, -canvasHeight / 2);context.drawImage(image, x, y);...context.restore();
• context に対して様々な処理をしてdrawImage で矢印を描画する
13年2月23日土曜日
Canvas におけるsave(), restore()
13年2月23日土曜日
Canvas におけるsave(), restore()
context.save();...context.translate(canvasWidth / 2, canvasHeight / 2);context.rotate(rad);context.translate(-canvasWidth / 2, -canvasHeight / 2);context.drawImage(image, x, y);...context.restore();
• context.restore() を呼ぶと、contextに対して回転や移動などの処理をする前の状態に戻る
•元通りの座標に戻るので、オブジェクトごとに処理が固定化できる
13年2月23日土曜日
Canvas におけるsave(), restore()
13年2月23日土曜日
Canvas その他
• 一定フレームごとの描画処理で、前に描いたものに対して、半透明の背景色で塗りつぶすと、残像っぽくなる
•これだけたくさんのオブジェクトをDOM要素でやったらたぶんつらい(つらそうなのでやってない)
13年2月23日土曜日
エフェクトもそれなりに
13年2月23日土曜日
13年2月23日土曜日
13年2月23日土曜日
13年2月23日土曜日
すげーそれっぽい!
13年2月23日土曜日
エンジニアでもこれくらいまでなら誰でもできるはず
13年2月23日土曜日
今日話す内容
1.作ってきたコンテンツの概要
2.デモ
3.WebRTC, Web Audio API などの話
4.まとめ
13年2月23日土曜日
リアルタイムWeb!
•リアルタイムに色々できるようになってきた、素敵な時代
•ブラウザの進化すごい
13年2月23日土曜日
ライブ音声入力
• 声というユーザーインターフェース
• Web Audio API は、いじりがいがありそう
13年2月23日土曜日
くだらないことに全力投球するの楽しい
• 元ネタは、茶化すわけではなくて本当にリスペクトしてる
•あそこまで熱くなれるものを、なんとかして他の人にも体験させられないだろうか?
•体験の共有
13年2月23日土曜日
これからもくだらないことに
全力投球でいきます!
13年2月23日土曜日
ありがとうございました!
13年2月23日土曜日
top related