jef*_*vav 11 audio html5 webkit ios webkitaudiocontext
在iOS 6下的HTML5中使用webkitAudioContext时,我一直在努力解决难以捉摸的音频失真问题.在其他情况下可能会发生这种情况,但我可以获得100%repro的唯一方法是在重启设备后第一次访问我的页面.看起来如果您在访问此页面之前访问任何具有音频功能的页面,则不会出现问题.
失真仅发生在webkitAudioContext.decodeAudioData()生成的音频上,然后通过webkitAudioContext.createBufferSource()播放.webkitAudioContext.createMediaElementSource()的音频播放不会扭曲.
我错过了一些初始化步骤吗?以下是我作为错误报告提交给Apple的完整代码和HTML(但未收到回复):
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var buffer = null;
var context = null;
var voice = null;
function load_music(file) {
context = new webkitAudioContext();
voice = context.createBufferSource();
var request = new XMLHttpRequest();
request.onload = function() {
context.decodeAudioData(request.response, function(result) {
buffer = result;
document.getElementById("start").value = "Start";
});
};
var base = window.location.pathname;
base = base.substring(0, base.lastIndexOf("/") + 1);
request.open("GET", base + file, true);
request.responseType = "arraybuffer";
request.send(null);
}
function start_music() {
if (!buffer) {
alert("Not ready yet");
return;
}
voice.buffer = buffer;
voice.connect(context.destination);
voice.noteOn(0);
document.getElementById("compare").style.display = "block";
}
</script>
</head>
<body onload="load_music('music.mp3')">
<p>This is a simple demo page to reproduce a <strong>webkitAudio</strong>
problem occurring in Safari on iOS 6.1.4. This is a stripped down demo
of a phenomenon discovered in our HTML5 game under development,
using different assets.</p>
<p><u>Steps to reproduce:</u></p>
<ol>
<li>Power cycle <strong>iPhone 5 with iOS 6.1.4</strong>.</li>
<li>Launch Safari immediately, and visit this page.</li>
<li>Wait for "Loading..." below to change to
"Start".</li>
<li>Tap "Start".</li>
</ol>
<p><u>Issue:</u></p>
<p>Audio will be excessively distorted and play at wrong pitch. If
another audio-enabled web site is visited before this one, or this
site is reloaded, the audio will fix. The distortion only happens on
the first visit after cold boot. <strong>To reproduce the bug, it is
critical to power cycle before testing.</strong></p>
<p>This bug has not been observed on any other iOS version (e.g. does
not occur on iPad Mini or iPod 5 using iOS 6.1.3).</p>
<input id="start" type="button" value="Loading..." onmousedown="start_music()" />
<span id="compare" style="display:none;"><p><a href="music.mp3">Direct link</a> to audio file, for
comparison.</p></span>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
注意:正文提示这只发生在iOS 6.1.4上,但我的意思是说问题只发生在这种情况下的电源循环时.我在6.1.3下的iPad Mini上也遇到过这个问题,但是没有电源循环.
编辑:我尝试过的一些事情......推迟创建缓冲源没有任何区别.使用不同的转码器生成.mp3文件,它播放没有区别.播放一次性静音,因为第一个声音没有区别,因为每次decodeAudioData声音的失真都会继续,直到页面重新加载.如果createMediaElementSource和createBufferSource源混合在同一页面中,则只有createBufferSource音频(使用decodeAudioData)会扭曲.当我在失败案例和非失败案例中检查request.response.byteLength时,它们是相同的,表明XMLHttpRequest没有返回不正确的数据,但我认为数据损坏会损坏MP3头并呈现档案无论如何都无法播放.
失效条件和非失效条件之间存在一个可观察到的差异.只读值context.sampleRate在故障状态下为48000,在非故障状态下为44100.(然而失败状态的声音低于非失败状态.)我发现的唯一一件事是黑客,如果在应该报告44100的浏览器上检测到48000,我会通过JavaScript刷新页面,但这是严重的用户代理筛选,而不是非常未来的证据,这让我很紧张.
即使在iOS 9.2上,我也遇到过类似的问题.
即使没有<video>标签,在冷启动后首次在页面上播放音频时,播放也会失真.重新加载后,它工作正常.
初始AudioContext似乎默认为48 kHz,这是失真发生的地方(即使我们的音频采样率为48 kHz).播放工作正常时,AudioContext采样率为44.1 kHz.
我找到了一个解决方法:可以AudioContext在播放初始声音后重新创建.新创建的AudioContext似乎具有正确的采样率.去做这个:
// inside the click/touch handler
var playInitSound = function playInitSound() {
var source = context.createBufferSource();
source.buffer = context.createBuffer(1, 1, 48000);
source.connect(context.destination);
if (source.start) {
source.start(0);
} else {
source.noteOn(0);
}
};
playInit();
if (context.sampleRate === 48000) {
context = new AudioContext();
playInit();
}
Run Code Online (Sandbox Code Playgroud)
小智 7
我发现HTML5视频的一个相关错误,并认为我发现了问题的根源.
我注意到,如果您使用<video>标签播放视频,它会将context.sampleRate值设置为视频音频编码的任何值.似乎iOS Safari有一个全局sampleRate用于所有内容.要查看此内容,请尝试以下操作:
// Play a video with audio encoded at 44100 Hz
video.play();
// This will console log 44100
var ctx = new webkitAudioContext();
console.log(ctx.sampleRate);
// Play a video with audio encoded at 48000 Hz
video2.play();
// This will console log 48000
var ctx = new webkitAudioContext();
console.log(ctx.sampleRate);
Run Code Online (Sandbox Code Playgroud)
此全局采样率似乎在页面加载中保持不变,并在选项卡和浏览器实例之间共享.因此,在另一个标签中播放YouTube视频可能会破坏所有已解码的音频.
当以一个采样率解码并在另一个采样率下播放时,音频会失真.
我不知道为什么它会在冷启动后发生.如果我不得不猜测,那就是Safari在你尝试使用它之前不会初始化这个全局采样率.
问题仍然存在于iOS 7上,所以我认为很快就会出现修复问题.我们一直坚持使用hacks,例如检查更改的采样率.