2013-07-26 49 views
11

Tôi đã đấu tranh với một lỗi biến dạng âm thanh khó nắm bắt bằng cách sử dụng webkitAudioContext trong HTML5 trong iOS 6. Nó có thể xảy ra trong các trường hợp khác, nhưng cách duy nhất tôi có thể nhận được 100% repro là lần đầu tiên ghé thăm trang của tôi sau khi đi xe đạp điện thoại. Dường như bạn truy cập bất kỳ trang có khả năng âm thanh nào trước khi truy cập trang này, sự cố sẽ không xảy ra.WebKit Âm thanh biến dạng trên iOS 6 (iPhone 5) lần đầu tiên sau khi đi xe đạp điện

Biến dạng chỉ xảy ra với âm thanh được tạo bởi webkitAudioContext.decodeAudioData() và sau đó được phát qua webkitAudioContext.createBufferSource(). Phát lại âm thanh của webkitAudioContext.createMediaElementSource() sẽ không bị sai lệch.

Tôi có thiếu một số bước khởi tạo không? Dưới đây là đoạn code và HTML trong toàn bộ mà tôi nộp cho Apple như một báo cáo lỗi (nhưng đã không nhận được trả lời):

<!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> 

Lưu ý: Các văn bản cơ thể gợi ý này chỉ xảy ra trên iOS 6.1.4, nhưng tôi muốn nói để nói rằng vấn đề chỉ xảy ra khi đi xe đạp điện trong tình huống này. Tôi đã gặp sự cố trên iPad Mini dưới 6.1.3, nhưng không phải khi đi xe đạp điện.

Chỉnh sửa: một vài điều tôi đã thử ... Trì hoãn việc tạo nguồn đệm không có sự khác biệt. Sử dụng các trình chuyển mã khác nhau để tạo tệp .mp3 mà nó phát không tạo ra sự khác biệt nào. Chơi im lặng khi âm thanh đầu tiên không tạo ra sự khác biệt vì sự biến dạng tiếp tục cho mỗi âm thanh decodeAudioData cho đến khi trang tải lại. Nếu nguồn createMediaElementSource và createBufferSource được trộn lẫn trong cùng một trang, chỉ âm thanh createBufferSource (sử dụng decodeAudioData) sẽ làm méo. Khi tôi kiểm tra request.response.byteLength trong trường hợp lỗi và trường hợp không thất bại, chúng giống nhau, cho thấy XMLHttpRequest không trả về dữ liệu không chính xác, mặc dù tôi nghĩ rằng tham nhũng của dữ liệu sẽ làm hỏng tiêu đề MP3 và hiển thị tệp không thể phát được.

Có một sự khác biệt quan sát giữa điều kiện lỗi và điều kiện không bị lỗi. Giá trị chỉ đọc context.sampleRate sẽ là 48000 trong trạng thái lỗi và 44100 ở trạng thái không thất bại. Điều duy nhất xảy ra với tôi là một hack trong đó tôi làm mới trang thông qua JavaScript nếu 48000 được phát hiện trên một trình duyệt mà nên báo cáo 44100, nhưng đó là nghiêm trọng userAgent sàng lọc và không phải là bằng chứng trong tương lai, điều đó khiến tôi lo lắng.

Trả lời

7

Tôi đã tìm thấy lỗi liên quan với video HTML5 và nghĩ rằng tôi đã khám phá ra gốc của sự cố.
Tôi nhận thấy rằng nếu bạn phát video bằng cách sử dụng thẻ <video>, nó sẽ đặt giá trị context.sampleRate thành bất kỳ âm thanh nào của video được mã hóa. Dường như iOS Safari có một mẫu toàn cục mà nó sử dụng cho mọi thứ. Để xem điều này, hãy thử các cách sau:

// 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); 

Tỷ lệ mẫu chung này sẽ duy trì trên các lần tải trang và được chia sẻ giữa các tab và phiên bản trình duyệt. Vì vậy, việc phát video youtube trong một tab khác có thể phá vỡ tất cả âm thanh đã giải mã của bạn.

Âm thanh trở nên bị méo khi được giải mã ở một tốc độ mẫu và phát ở một tốc độ mẫu khác.

  1. Giải mã âm thanh và lưu trữ bộ đệm
  2. làm cái gì đó để thay đổi tỷ lệ mẫu, chẳng hạn như chơi một đoạn video hoặc tập tin âm thanh
  3. Chơi đệm (méo)

Tôi không biết tại sao nó xảy ra sau một khởi đầu lạnh lùng. Nếu tôi đã đoán, đó là Safari không khởi tạo tỷ lệ mẫu toàn cầu này cho đến khi bạn cố gắng sử dụng nó.

Sự cố vẫn còn trên iOS 7, vì vậy tôi không nghĩ rằng bản sửa lỗi sẽ sớm xuất hiện. Chúng tôi đang mắc kẹt với hack trong thời gian có nghĩa là như kiểm tra cho một tỷ lệ mẫu thay đổi.

+2

Nó vẫn là một vấn đề trên IOS 8. –

+1

Cũng như 9.2.1 (phiên bản mới nhất của bài viết này) –

8

Tôi đã gặp sự cố tương tự, ngay cả trên iOS 9.2.

Ngay cả khi không có thẻ <video>, phát lại bị méo khi lần đầu tiên phát âm thanh trên trang sau khi khởi động nguội. Sau khi tải lại, nó hoạt động tốt.

Ban đầu AudioContext dường như mặc định là 48 kHz, đó là nơi biến dạng xảy ra (ngay cả với âm thanh của chúng tôi ở tốc độ mẫu 48 kHz). Khi phát lại hoạt động bình thường, AudioContext có tốc độ lấy mẫu là 44,1 kHz.

Tôi đã tìm được cách giải quyết: có thể tạo lại AudioContext sau khi phát âm thanh ban đầu. Các mới được tạo ra AudioContext dường như có tỷ lệ mẫu chính xác. Để làm điều này:

// 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(); 
} 
+0

Làm việc cho tôi, cảm ơn! Đặt điều này trong một trình xử lý touchEnd ban đầu cũng để bỏ chặn âm thanh web iOS. –

+0

Điều này thực sự giúp tôi! cảm ơn rất nhiều – iownthegame