ios - WebKit 音频在 iOS 6 (iPhone 5) 上第一次在电源循环后失真

标签 ios html audio webkit webkitaudiocontext

我一直在与 iOS 6 下 HTML5 中使用 webkitAudioContext 的难以捉摸的音频失真错误作斗争。在其他情况下可能会发生这种情况,但我能获得 100% 重现的唯一方法是在电源循环后第一次访问我的页面时设备。似乎如果您在访问此页面之前访问任何支持音频的页面,问题就不会发生。

失真仅发生在由 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 &quot;Loading...&quot; below to change to
                &quot;Start&quot;.</li>
            <li>Tap &quot;Start&quot;.</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>

注意:正文表明这仅发生在 iOS 6.1.4 上,但我的意思是说该问题仅在这种情况下的电源循环时发生。我在 6.1.3 下的 iPad Mini 上也遇到过这个问题,但在电源循环时没有。

编辑:我尝试过的一些事情...推迟缓冲区源的创建没有任何区别。使用不同的转码器生成它播放的 .mp3 文件没有区别。作为第一个声音播放一次性静音没有任何区别,因为每个 decodeAudioData 声音都会继续失真,直到页面重新加载。如果 createMediaElementSource 和 createBufferSource 源在同一页面中混合,则只有 createBufferSource 音频(使用 decodeAudioData)会失真。当我在失败案例和非失败案例中检查 request.response.byteLength 时,它们是相同的,这表明 XMLHttpRequest 没有返回不正确的数据,尽管我认为数据损坏会损坏 MP3 header 并呈现文件无论如何都无法播放。

故障情况和非故障情况之间存在一个明显的区别。只读值 context.sampleRate 在失败状态下为 48000,在非失败状态下为 44100。 (然而,失败状态听起来比非失败状态音调低。)我唯一想到的是一个 hack,如果在应该报告 44100 的浏览器上检测到 48000,我通过 JavaScript 刷新页面,但这是严重的 userAgent筛选而不是 future 的证据,这让我很紧张。

最佳答案

即使在 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();
}

关于ios - WebKit 音频在 iOS 6 (iPhone 5) 上第一次在电源循环后失真,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17892345/

相关文章:

ipad - 如何让弹出窗口来自选项卡而不是 View

html - 如何使用 css 单独打印页面中的多个元素?

android - 按下电源按钮时播放音频

audio - 具有同步播放功能的 mp3 网站播放器(非流式传输)

android - 如何在Android中比较音频?

ios - Xcode 10 : Ambiguous Constraints Error When Adding Simple Constraints

ios - 从API加载图像

ios - 在 OCUnit 中使用核心数据类的 Apple Mach-O 链接器错误

python - 如何通过 gmail-api for python 发送 HTML 格式的电子邮件

javascript - 将 HTML 表从 iframe 导出到 CSV