明日も楽をするために

めんどくさがりなITエンジニアが書くメモ帳

苦しんで覚えるHtml5Audioの世界

その昔スマホWebブラウザで音声を再生する際に苦労したので、その時のメモを公開します(供養)

  • onmousedown、onmouseup、onclick、ontouchstart、ontouchendが音声再生のトリガーになる(追記 touchstartだとトリガーにならないAndroidOS5~6が出現)
  • iOS6:iPhone4:audio.currentTime = 0;はinvalid state error dom exception 11(音声を読み込まないとアクセスできない?)
Android2.2~2.3 webkit533
Android3.0~4.2 webkit534
iOS6            webkit536
Android4.3      webkit537
  • memo
var audio = new Audio();
audio.play();
audio.load();

どちらか片方だけトリガーイベントで呼び出せばいけるみたい
例えば

window.addEventListener('touchstart', function (e) {
    audioPlayer.load();
});

こんな感じで一度呼び出して先にloadすればplayはトリガーイベント以外でも動作するっぽい
Androidで音声再生時にリファラーが送られない時がある(.htaccessが使えない)6系は大丈夫?
Android4.1.2で音声の先頭または後方が途切れる場合がある

audioとvideo再生時にUAが変わる

audioとvideo取得時にアクセスするUAがwebviewの物とは異なる
Androidの場合(Zenfone5)
stagefright/1.2

iPhoneの場合(iPhone6の9.2)
AppleCoreMedia/1.0.0.13D15 (iPhone; U; CPU OS 9_2_1 like Mac OS X; ja_jp

端末

機種名 version 対応音声 備考
AQUOS PHONE SH-07D 4.0.4 wav 非対応端末
MEDIAS X N-04E 4.1.2 wav ogg 再生確認 快適
ARROWS X F-02E 4.1.2 wav ogg 音が小さすぎて判別不可能 キーボード操作が難しい
AQUOS PHONE EX SH-04E 4.1.2 wav ogg ログを見ると再生できているようだが、音が全く聞こえない
Xperia A SO-04E 4.1.2 wav ogg ログを見ると再生できているようだが、音が全く聞こえない
MEDIAS X N-04E 4.1.2 wav ogg スクロールがしにくい、音は問題ない
AQUOS PHONE ZETA SH-06E 4.2.2 wav ogg ログを見ると再生できているようだが、音が全く聞こえない
ELUGA P P-03E 4.2.2 wav ogg ログを見ると再生できているようだが、音が全く聞こえない
GALAXY J SC-02F 4.4.2 wav ogg mp3 特に問題なし
Xperia Z SO-02E 4.4.2 wav ogg 特に問題なし 快適

Android端末調査

調査項目

  • インスタンスの生成はメソッド内で生成が必要かどうか
  • 基本的には1音再生で、インスタンスは一つが鉄則
  • Android4.1以下は事前ロードが可能
  • EventListenerでendedが発火しない場合に無名関数をやめると動く
  • freac-1.0.26-binでmp3からoggに変換
  • oggファイルをCBR、ABR方式にすることによって音声が途中で切れる現象を防ぐことを確認4.1.2(デフォルトはVBRだと思わる。再現性あり
  • oggファイルのビットレート方式によってendedが発生しないパターンがあるが、原因不明
  • touchstartだとトリガーにならない端末がAndroidである(5~6系)
機種名 version インスタンスの事前生成 戻るボタン操作後の動作 備考
MEDIAS U N-02E 4.0.4 - 事前読み込みができることを確認
Xperia UL SOL22 4.1.2 - 事前読み込みができることを確認、事前読み込みしないと再生できない、oggによって一部途切れる
MEDIAS X N-04E 4.1.2 - 事前読み込みができることを確認、事前読み込みしないと再生できない、oggによって一部途切れる
Galaxy S4 SC-04E 4.2.2 音声が再生される 画面遷移できない(イベントリスナーバグ)、ABRでendedが発火しない?VBRは発火する
ELUGA P P-03E 4.2.2 音声が再生される -
Xperia Z1 SO-01F 4.4.2 画面遷移できない(イベントリスナーバグ)
Asus Zenfone5 5.0 - oggファイルによってendedが発火しない(Adobe MediaEncoderで生成)
AQUOS U SHV37 6.0.1 - -
iPhone6 8.4 音声はタップしても再生しない -

イベントリスナーが発火しないパターン
Xperia Z1 SO-01F

audio.addEventListener('error',this.jump,false); ○
audio.addEventListener('error',jump,false); ×
audio.addEventListener('ended', function foo() { ○
    jump();
}, false);
audio.addEventListener('ended', function() { ×
    jump();
}, false);

■Galaxy S4 SC-04E

audio.addEventListener('error',this.jump,false); ○
audio.addEventListener('error',jump,false); ×
audio.addEventListener('ended', function foo() { ○
    jump();
}, false);
audio.addEventListener('ended', function() { ○
    jump();
}, false);

4.1.2の奇妙なバグ(一度先に何かしら読み込めばあとは問題ない)
Xperia UL SOL22

audio.src = sounds[0]; ○
audio.load();
function onClick() {
    audio.play();
}
 
function onClick() {
    audio.src = sounds[0]; ×
    audio.load();
    audio.play();
}

oggファイルについて

Sampleコード

基本的にaudioをコードを極力かかないことでエラーを防ぐ

var audio = new Audio();
//srcに指定した段階で勝手に読み込みを始めるがスマホはタッチ制約があるため読み込みを基本的に行わない
//Android4.1以下は例外的に読み込みを始める。むしろAndroid4.1以下の時は何かしら読み込みをしないと音声操作が何もできなくなる。
//(たぶん内部的にソースがないのでExceptionを吐いてる可能性・・・)
//初期化時に指定してもいいしタップ時に指定しても動くが出来れば、タップ時にsrcに指定を推奨
//audio.src = "http://foo.com/foo.mp3";
 
function play() {
    //ここでstopを呼び出してもよい

    //canplaythroughは音声のロードが終わった際に発生するevent
    //読み込み終了時のイベントは色々あるが、端末によってイベントの発生タイミングが異なるため(かなり違う
    //単純にどの端末でも音声読み込み後に発生する可能性が高いイベントがcanplaythroughである
    //通常はplayを呼び出すだけで、読み込みと再生を行ってくれるが、読み込み前にplayを実行すると落ちたりエラーになる端末があるため(ARROWSとか)

    //第二引数に指定する関数は無名関数だと呼ばれない端末が存在するので、必ず適当な名前をつける。
    //他に記述した関数を呼び出す際は必ずthisをつける(例:this.stop)
    audio.addEventListener("canplaythrough", function local() {
        //一応消しておく本来は何回addしても問題ないはずだが一応・・・
        audio.removeEventListener("canplaythrough", local, false);
        audio.play();
    }, false);
    audio.src = "http://foo.com/foo.mp3";
    audio.load();
}
 
function stop() {
    audio.pause();
    //↓音声を読み込む前に時間を移動させるとExceptionを吐く端末がある(新しい端末は吐かない)
    try {audio.currentTime = 0;} catch(e) {}//iOS6、Android4.2対応
}

音声が再生できない際のチェック項目

  • 音声再生に対応しているか?(基本的には対応していると思うが。。。。WebAudioAPIだとインスタンスが生成できても音が一切ならない端末もあるらしい
  • 音声ファイルは対応しているか?(iPhoneは基本はmp3、Androidoggが基本だが稀にmp3が再生できる端末もある)
  • トリガーをちゃんと使用しているか?(onClick,touchend)
  • urlをaudioに渡すタイミングは適切か?(srcに渡した段階でloadが始まるのがデフォルトだが(スマホはトリガー次第でロードしない)、それで予期しない動きをすることがある
  • audio再生時にちゃんと音声が読み込まれているのを確認した上でplayを呼び出しているか?(loadが全部終わらない前にplayするとクラッシュする端末あり)
  • 指定のeventリスナーは発火しているか?(endedなど音声ファイルによって発火しない場合あり)
  • その音声ファイルは本当に問題ないか?(oggビットレートの変換タイプ(VBR,ABR,CBR)によって動作が変わる場合がある