最近またLocal Player (Chrome Player)を実装しなおしています.
一応説明しておくと, Local Playerは, 完全にローカルで動作する音楽プレイヤーです.
シンプルさを求め(実装がめんどくさいだけ), 操作しやすく(これは大事), 良い感じのプレイヤーです.
半年前に, ソースコードがスパゲッティになって, 開発を中断していましたが, 最近また書きなおし始めたのです.
音楽プレイヤーをブラウザー上で実装するのには, 音楽ファイルをJavaScriptで読み込まなければなりません.
そこでHTML5ですよ!!!
<audio src="url/to/musicfile.mp3" type="audio/mp3" />
みたいな感じで, 音楽を再生できます.
詳細は他のページに譲ります.
さて, 音楽ファイルを再生するには, ローカルファイルからurlをaudio要素のsrcにファイルをぶち込まなければならないわけですが, どうすればいいでしょう.
まぁ素直な実装は, File APIのFileReaderでreadAsDataURLを使うことでしょう.
実際, Local Playerは今までこの方法をとっていました.
だいたいこんな感じの実装です
var reader = new FileReader();
reader.onerror = function(e) {
console.dir(e);
};
reader.onload = function(e) {
var audio = new Audio(e.target.result);
audio.volume = 0.5;
audio.addEventListener('ended', function() {
delete audio;
next_music();
});
audio.play();
};
reader.readAsDataURL(file);
極めて普通ですね.
教科書そのまんまって感じです.
deleteはいらないと思いますが, e.target.resultが馬鹿でかい文字列となっており, メモリーがやばいことになります.
この実装を用いたLocal Playerで, 音楽を再生して, 10秒再生したらすぐ次のファイルへとスキップする, という動作を繰り返した時, CPU使用率とメモリー使用率は次のようになります.
確認環境はUbuntu, メモリーは2GBです.
曲を開始した瞬間, 5MBの音楽ファイルをreadAsDataURLして, メモリーが一時的に上がります.
大体, 山の大きさがメモリーの5%くらい, つまり, およそ100MBの文字列がJavaScriptの中でできては消え... を繰り返してるのです.
こんなんだと, 1秒ごとにスキップして行ったらどんどんメモリーは食うはCPUはしんどいわ...
しかも, 「曲をスキップする」というのは音楽プレイヤーとしては, よくあることなのです.
で, 一年間ほど悩んでいました.
今日, 神様のお告げが
ξ*‘ ー‘)<( それcreateObjectURLでデキルヨ )
え...???
どう違うの???
取り敢えず実装してみよう...
var createObjectURL
= window.URL && window.URL.createObjectURL
? function(file) { return window.URL.createObjectURL(file); }
: window.webkitURL && window.webkitURL.createObjectURL
? function(file) { return window.webkitURL.createObjectURL(file); }
: undefined;
if (!createObjectURL) return;
var audio = new Audio(createObjectURL(file));
audio.volume = 0.5;
audio.addEventListener('ended', function() {
delete audio;
next_music();
});
audio.play();
だいたいこんな感じの実装
はい, とってもとーっても簡単ですね (にこにこ
取り敢えずさっきと同じ条件で, 音楽を読み込んで次々とスキップしてみます
.......
いやいやいやいや...
メモリー...一定じゃん...
これ, ブログ見てる人には分からないでしょうが, ちゃんと音楽も聞こえてますし, スキップしてますし...
分かりやすいように, 音楽を再生する瞬間にCPUにワザと負荷を与えるような感じのコードを入れてみます.
for (var i = 0; i < 2e4; i++) {
console.log(i);
};
これで, さっきと同じ条件で行ってみます.
ちゃんと音楽流れてるんですよ? ホントに. ホントです.
メモリー全然食ってないじゃん...\ヤベェ/
まとめ
createObjectURLは凄い*1
何が凄いって, 全然ふっつーの関数呼び出しで書いてるのに, 裏ではurl先のローカルファイルをstream(?)的に読み込んでる.
あ, いや, 読み込んでるのはaudio elementの方なのかな...
これまでは, readAsDataURLで一気に読み込んでいたため, 50MBある1時間超のファイルを再生できませんでした.
それがcreateObjectURLによって解決されてしまったのです.
さらに, これまでできなかった動画再生も可能になります!!! ← なりました!!!
createObjectURL, どういう実装になってるんでしょう?
ちゃんと音楽や動画のシークもできるし, すごく不思議です.
不思議なのは, USB接続の外付けHDDなどにある音楽を, 再生して直ぐにUSBをぶっこぬいても, そのまま音楽が聞こえ続けることなんです.
フッ, またV8の闇に取り込まれそうになってしまったぜ...
追記(2012/11/21)
Local Playerはmanifest_version: 2の波についていけなくてStoreから削除されました.