Android/iOSでAudio要素の連続再生対策
HTML5でVideo/Audioがノンプラグインで再生出来るようになりましたが、シンプルに一つのファイル(単独のVideo/Audio要素)を再生するだけであれば
各ブラウザ向けにエンコードして(対応した拡張子の)ファイルを用意するだけで簡単に利用出来ます。
この対応拡張子(コーデック)が異なる部分も厄介な問題ですが、既に話題している方が多いので本エントリーでは省略します。
タイトルのAudio要素を連続して再生する状況ですが、例えばアプリやゲームの操作時に発生するSE(サウンドエフェクト)として連続して再生する状況があるかと思います。
PCブラウザ(IE9+、Chrome、Firefox)はAudioを連続で再生しても概ね問題なく動作しましたが、スマホブラウザ(Android、iOS)は少し工夫しないと連続で再生出来ませんでした。
また、その他にもAudio要素をスマホで扱う際に注意すべき点を紹介します。
Audio要素の自動再生
Audio要素にautoplay属性を指定すると、再生準備が整った時点で自動的に再生が開始されます。
このautoplay属性はPCブラウザでは機能しますが、スマホブラウザでは動作しません。
これはバグではなく仕様で、パケット通信が従量課金の可能性を考慮してユーザが意図して再生(タップ)するまで再生・読込ともに行わない仕様とのこと。
読込にもユーザのアクション(タップ)が必要になるため、autobuffer属性でプリロードする事も出来ません。
つまり、ページ読込時に自動でBGMを流すことは出来ませんし、
PCブラウザでは動作する下記コードはどちらも動作しません。
<audio src="music.mp3" autoplay></audio>
<script> window.addEventListener( 'load', function() { var audio = document.getElementById( 'audio' ); audio.play(); }, false ); </script> <audio src="music.mp3" id="audio"></audio>
スマホブラウザでAudioが再生される条件
- 1. Audio要素の再生ボタンをタップ(controls属性で表示されるUI)
-
この使い方であれば特に悩むことはないと思います。
<audio src="music.mp3" controls></audio>
- 2. JSのイベントハンドラ(clickやtouchstart)の中でplay()を実行
-
ユーザのアクションがあれば再生(読込)は可能なので、イベントをトリガーにしてJSからも再生出来ます。
<script> var button = document.getElementById( 'button' ); // Audio要素を取得して再生 var audio = document.getElementById( 'audio' ); button.addEventListener( 'touchstart', function() { audio.play(); }, false ); // オンザフライで生成したAudio要素も再生可能 var audio = new Audio( 'music.mp3' ); button.addEventListener( 'touchstart', function() { audio.play(); }, false ); </script>
- 3. 上記2の中で予めload()を実行して読み込んでおく
-
ユーザのアクションがあれば読込可能、という仕様のため事前に読み込んでおけば任意のタイミングで再生可能です。
ただ、この方法はOSによっては対応していなかったり、今後のバージョンアップで動かなくなる可能性もあるので事前検証をおすすめします。<script> var button = document.getElementById( 'button' ); var audio = document.getElementById( 'audio' ); // タップ時に読み込んでおく button.addEventListener( 'touchstart', function() { audio.load(); }, false ); // 以降任意のタイミングで再生可能 setTimeout(function() { audio.play(); }, 10000 ); </script>
Audioの連続再生
スマホブラウザでは単純に同じAudio要素を繰り返しplay()しても意図した通りに再生されません。
※play()完了(endedプロパティがtrue)になるまでは次回のplay()が無視されます。
これを回避するには下記コードのようにplay()と同時にnew Audio()で次回再生に備えてAudio要素を事前に初期化(キャッシュ)しておく方法が一番安定していました。
<script> var button = document.getElementById( 'button' ); var audio = new Audio( 'music.mp3' ); button.addEventListener( 'touchstart', function() { audio.play(); // 次回再生に備えて初期化 audio = new Audio( audio.src ); }, false ); </script>
ただ、再生する度にnew Audio()する対応は良いとは言えないので、PCブラウザでは予め多めにAudio要素を作成しておいて、
再生が終わったAudio要素を再利用する事で都度new Audio()する事を回避出来ます。
下記デモではスマホはnew Audio()で初期化、PCブラウザは事前に作成したAudio要素を再利用する形で連続再生に対応しています。
まとめ
Audio要素はPCのモダンブラウザなら概ね問題なく使える状況になりつつある。
ただし、当面は複数コーデック(拡張子)でファイルを用意する必要あり。
スマホブラウザはiOS、Androidともに自動再生は出来ないが、iOS6/Android4であれば比較的ブラウザのサポート状況が良い。
今回未検証だが、iOS5やAndroid2.3はAudioの再生がシングルスレッドで同時に複数再生出来ないとの情報があるなど、
OS(バージョン)によって動作が異なるので古いOSもサポートする場合は十分に検証することをおすすめします。