大探検!HTML5オーディオスプライト・中編

前回に続いて、モバイルオーディオを理解するための記事やライブラリと、僕の調査による補足をご紹介していきます。

また、前回の記事に誤りがあったので少し修正しています。何がしか開発中の方は再度ご確認ください。

また、僕の記事は、訂正箇所を明示せずに訂正している場合がありますのでお気をつけて。

~で、本題の前に…

モバイル Safari の Audio 制限の理由

この制限の理由について Apple の正式なアナウンスはありません。

従量課金でインターネットに接続しているユーザーに対して、意図せず巨大なオーディオがダウンロードされることを防ぐため、といわれています。

さて、従量課金に絡んで興味深い点があります。

iOS6 からより強力なオーディオ機能、WebAudio がサポートされました。

iOS の WebAudio はユーザーのタッチを基点とせずにオーディオファイルのダウンロードができてしまいます。そして、start() のときにユーザーのタッチが要求されます。

相変わらずメディア周りに制限がある点は同じですが、ユーザーのインタラクション無しに通信が発生している点は、先の推測と矛盾しています。

従量課金説の他に、モバイル Safari のオーディオ機能をリッチにしてしまうと iTunes の地位が低下してしまうから、という指摘もあります。(url失念)

はてさて、モバイル Safari の制限はどういった理由なのか?答えはありませんが、在野の Web 技術者の発奮で、大手の思惑の斜め上を行き、UX をアゲ↑アゲ↑しちゃいましょう。

BoomBox.js 2014/02/19~

「boombox.js」は、ブラウザでサウンドを再生する際に使われることの多い、一般的なオーディオ関連のAPIである 「HTMLAudio」「WebAudio」「HTMLVideo」を包括して、一貫性のあるAPIとして提供するブラウザ向けサウンドライ ブラリです。

サイバーエージェントが公開しているライブラリです。

WebAudio, HTMLAudio に加え HTMLVideo も隠し味として使用するオーディオライブラリで、オーディオスプライト機能も提供されます。

次のリンクは素晴らしいまとめですが Github のデザインと干渉してしまって見辛いです。心の中で手を合わせつつ印刷して手元におきましょう。

CyberAgent/boombox.js ブラウザ対応表(2014-03-18)

オーディオ + ビデオフォールバック

このライブラリ・記事の括目な点としては、Android4 以降で Android 標準ブラウザのオーディオ機能の制限が強くなり同時再生数が一音になります。

その際に、Video タグを使用したフォールバックで2音の同時再生を可能にしている点です。ハック感がたまりませんね。

これにより BGM を1トラック鳴らしながら SE を1トラック鳴らすことができリッチなゲーム等のアプリが制作可能です。

OS/Browser 1 sound 2 sound multi sound
IOS 5: Safari - -
IOS 6, 7: Safari
Android 2.x: basic
Android 4.x: basic ✔ *1 -
Android 4.x: chrome

*1 HTMLAudio/HTMLVideo 併用

先の表には Android 4.x について HTMLAudio/HTMLVideo 併用とあります。

しかし今回確認したところ、HTMLAudio の制限が強まるのは Android4 の途中からになります。一方で HTMLVideo の制限が弱まって、ビデオのインライン再生が可能になるため、オーディオ + ビデオフォールバックが成立します。

この境界は、Android4.1.1 Webkit 534.3 と Android4.4.4 Y! Browser Webkit 537.36 の間にありました。Android4.1.1 の HTMLAudio は Android2.3 と同じく制限がありません。より正確な境界はどなたか特定して教えてください m(__)m

メモリリーク

またコードを眺めていてそれと分かるメモリリークがありました。長時間滞在型のページで使う前に修正した方が良いでしょう。

次の HTMLAudio と HTMLVideo に対する以下のイベントリスナが dispose() でも解除されていません。

this.$el.addEventListener(
    'ended',
    function (e) {
        self._onEnded(e);
    },
    false);

イベントとタイマーに絡んでクロージャを多用していてオブジェクトのライフサイクルがとっても追いづらいです。大規模開発でこのようなコードが使われているとそのうちに目も当てられなく、、、

currentTime が正しく動かないブラウザ

HTMLAudio HTMLVide のシーク設定(currentTime) が設定出来ないブラウザがある場合は、内部でcurrentTimeが設定されても無視されます。

記事中には、currenTime が正しく動かないブラウザがある、とありました。

残念ながらブラウザ名・バージョン等は明示されていません。これについては先の記事でも触れたとおり、Opera Mobile 12 と Desktop 版 Opera12 が不可解な挙動をしました。そこで僕は Opera12 のことを言っているのでは?と考えています。

Android 版 & Windows PC版 Opera12 で duration, currentTime 周りが独特

Opera Mobile 12 で currentTime が更新されない

Opera Mobile 12(Android4.4.4 & 2.3.5) は 2回目以降の currentTime へのセットから currentTime が更新されなくなります。仕方が無いので現在の再生位置を知るために Date.now などを使用します。また、セットは動作するのでシークは可能です。

Windows PC版 Opera 12.1x

あまりにも問題が多いので箇条書きにします…主に Opera 12.17 portable apps 版 WinXP 32bit で調べています。

  • 勝手に再生が始まる。その際には timeupdate が発行されない。
    • Opera 12.16 1860 Win8 64bit では勝手に再生はしない。
    • Opera11、10.54 では WinXP では発生しない。
  • loadeddata イベント後も duration に Infinity が入っている。play() してしばらくすると duration が取れるようになる。Infinity の間は currentTime に set(seek) ができない。
  • pause() が動かず再生し続ける。音を停止するには Audio.src = '' をする。再び再生するには Audio.src = source とする。但し音が鳴り始めるまでに 2~3 秒程度時間が掛かる。
  • 再生中に currentTime が変化しない。Date を使って再生時間を管理する。
  • volume=0, muted=true などとすると、その後の音量変更ができない。
予行演習として

このように独自エンジンの最後となった Opera12 は支離滅裂な乱れっぷりです。

一方でなんらかの手を講じれば、再生・シーク・停止が確実であることも分かりました。そのため pettanR でもパッチコードをあてて調教することができました。

このような挙動の怪しい古いブラウザのサポートは、挙動の怪しい最新ブラウザが登場した場合の予行演習として行えたらいいですね。コードがよくできていれば綺麗に隠蔽できますし、まずければスパゲッティ化するので諸々思い知ります。

Opera Mobile 12 で可変ビットレートの再生がボロボロ…

ところで、可変ビットレート(ogg VBR)な音声ファイルでは duration が正しくなく(短い数値が返る)、currentTime へのセットでは意図した再生位置より後ろから再生されます。

このズレは曲の後の方ほど大きくなり、特に無音部分があると大きくなるようです。

可変ビットレートでは曲の長さと位置を正しく扱えない、と推測して固定ビットレート(mp3 CBR)で音声ファイルを用意したところ意図した再生が行われました。

Opera12 で 2音以上の再生が乱れる

描画要素が増える等で Opera12 が忙しくなってくると2音以上の再生が乱れる、という症状にも遭遇しました。

この問題は Android 版に加えて、マシンリソースが潤沢なはずのデスクトップ版 Opera12 (WindowsXP, Windows8) でも遭遇しています。

続く

ここまでお付き合いくださりありがとうございます。Presto Opera 祭りとなった中編でした。

えぇと、独自エンジンを辞めた Blink Opera には食指が動かずほとんど触っていません。これは Vivaldi も同様です、悪しからず。

さてさて、次回はさらなるマイナーブラウザが登場します、乞うご期待!