調査環境
- iOS 8.1 + iPhone 5
- Chrome for Android 38.0 + Xperia A
iOS タッチ制約
- 初回の start() はユーザのタッチ操作を起点とした実行コンテキストで実行する必要がある
- AudioContext のインスタンスごとに制約がかかっている
- 実行コンテキスト
- setTimeout は大丈夫
- decodeAudioData はアウト。コールバック中で初回の start() を呼び出しても再生されない。
タッチ制約にハマる例
element.addEventListener('click', function() {
context.decodeAudioData(buffer, function(buffer) {
var src = ctx.createBufferSource();
src.buffer = buffer;
src.connect(context.destination);
// タッチ制約により動作しない
src.start(context.currentTime);
});
}, false);
回避方法
次のようなコードを仕込んでおくとタッチ制約を回避できる。
context.createBufferSource().start(0);
デコード時間
decodeAudioData の所要時間を計測(ms)
iOS
iOS 8.1 + iPhone 5
- HE-AAC
- 441, 446, 448
- AAC
- 250, 252, 251
Chrome for Android
- HE-AAC
- 1915, 1902, 1789, 2223, 2059,
- AAC
- 2507, 2914, 2698, 2878, 2967,
DataRate ごとのデコード時間(Chrome)
decodeAudioData のコストが高すぎる為、bitrate ごとの値を取ってみる。
HE-AAC でそれぞれ DataRate を変更し、計測した数値が以下。
- 56kbit/s: 2102, 1941, 1852, 1984, 2088
- 48kbit/s: 1772, 2043, 2048, 2005, 1983
- 32kbit/s: 1806, 1960, 1891, 1922, 1784
- 24kbit/s: 1658, 1829, 1860, 1805, 1739
createBuffer を使う(iOS)
Safari では ArrayBuffer からオーディオデータへの変換に decodeAudioData に代えて createBuffer が使える。
createBuffer は何故か変換コストを要しないため iOS ではこちらの方が高速に動作する。
但し標準ではないのでいつ切られてもおかしくなく、decodeAudioData の方が安心して使える。
CPU 使用率
iOS での AAC、HE-AAC それぞれのデコード所要時間は次の通り(com.apple.WebKit の CPU Usage)
AAC で 21〜25%、
HE-AAC で 35〜40%
ファイル記録
デコード時間の計測に利用したファイルはそれぞれ次の通り
HE-AAC
Data format: 2 ch, 16000 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Stereo (L R)
estimated duration: 35.587750 sec
audio bytes: 251859
audio packets: 559
bit rate: 56319 bits per second
packet size upper bound: 796
maximum packet size: 796
audio data file offset: 4096
optimized
audio 569404 valid frames + 2112 priming + 900 remainder = 572416
source bit depth: I16
format list:
[ 0] format: 2 ch, 32000 Hz, 'aach' (0x00000000) 0 bits/channel, 0 bytes/packet, 2048 frames/packet, 0 bytes/frame
Channel layout: Stereo (L R)
[ 1] format: 2 ch, 16000 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Stereo (L R)
info dictionary:
approximate duration in seconds 35.588
AAC
Data format: 2 ch, 32000 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Stereo (L R)
estimated duration: 35.587750 sec
audio bytes: 290577
audio packets: 1115
bit rate: 65151 bits per second
packet size upper bound: 359
maximum packet size: 359
audio data file offset: 8192
optimized
audio 1138808 valid frames + 2112 priming + 840 remainder = 1141760
source bit depth: I16
format list:
[ 0] format: 2 ch, 32000 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Stereo (L R)
info dictionary:
approximate duration in seconds 35.588
Chrome for Android 一部端末での問題
やはり端末間の差違がある。
音質やノイズの有無も端末によってかなり変わるため注意が必要。
ノイズが混ざる(処理遅延が生じる)
L-01F 等の一部端末で Web Audio API の再生結果に特定条件下でノイズが混ざることがある。
描画レート(描画 FPS)が下がるとノイズが混ざり始め、レートを上げると再生結果が正常になるというもので、オーディオ処理が描画スレッドに巻き込まれているような動作を見せる。
次のようなコードを入れて無理矢理 FPS を稼ぐことで上記問題は回避できる。
<div id="fps-slowdown-make-sound-noisy"></div>
#fps-slowdown-make-sound-noisy {
width:0px;height:0px;
position: absolute;
-webkit-animation-name: anim-void;
-webkit-animation-duration: 1s;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes anim-void {
from { top: 0px; }
to { top: 1px; }
}
API が無い
NEON 命令に対応していない端末では Web Audio API 自体が無効化されている(生えていない)。
iOS 7.x で decodeAudioData がキャンセルされる
(iOS 8.x では未検証)
iOS 7.1 で decodeAudioData に処理が入った瞬間にスクリーンを長押しする(スクロールを繰り返す)と decoeAudioData の処理がキャンセルされることがある(エラーやコールバックの発火もなく、ただ処理が消滅する)。