Why certain .wav files cannot be decoded in Firefo

2019-05-03 05:16发布

问题:

I have a web page which decodes wave files for certain reasons. Chrome and Safari seem to work fine. Firefox occasionally is unable to decode the file and gives the error: "The buffer passed to decodeAudioData contains invalid content which cannot be decoded successfully." I have created a jsfiddle which illustrates the issue:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source;
function getData() {
  source = audioCtx.createBufferSource();
  request = new XMLHttpRequest();
  request.open('GET', 'https://mpclubtest.s3.amazonaws.com/Malice_Bass.wav', true);
  request.responseType = 'arraybuffer';
  request.onload = function() {
    var audioData = request.response;
    audioCtx.decodeAudioData(audioData, function(buffer) {
        source.buffer = buffer;
        source.connect(audioCtx.destination);
      },
      function(e){"Error with decoding audio data" + e.err});
  }
  request.send();
}
getData();
source.start(0);

Can anyone tell me what the issue is and if there is any way to circumvent? Many Thanks.

EDIT Thanks to the substantial contributions of Michael Chaney I was able to implement some javascript which processes the wave so that it can be played in Firefox. The code trims any part of the "fmt" chunk over 16 bytes. Code located at: jfiddle

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source;
function getData() {
  source = audioCtx.createBufferSource();
  request = new XMLHttpRequest();
  request.open('GET', 'https://mpclubtest.s3.amazonaws.com/Malice_Bass.wav', true);
  request.responseType = 'arraybuffer';
  request.onload = function() {
      var audioData = request.response;
      var dv = new DataView(audioData);
      var junk = 0;
      var position = 12;
      do {
          var header = String.fromCharCode.apply(null, Uint8Array(audioData, position, 4));
          var length = dv.getUint32(position + 4, true);
          if (header.trim() === 'fmt') {
              junk = junk + length - 16;
          }
          position = position + 8 + length;
      }while(position < audioData.byteLength);
      var productArray = new Uint8Array(audioData.byteLength - junk);
      productArray.set(new Uint8Array(audioData, 0, 12));
      var newPosition = 12;
      position = 12;
      var fmt_length_spot;
      do {
          var header = String.fromCharCode.apply(null, Uint8Array(audioData, position, 4));
          var length = dv.getUint32(position + 4, true);
          if (header.trim() === 'fmt') {
              productArray.set(new Uint8Array(audioData, position, 24), newPosition);
              fmt_length_spot = newPosition + 4;
              newPosition = newPosition + 24;
          }
          else {
              productArray.set(new Uint8Array(audioData, position, length + 8), newPosition);
              newPosition = newPosition + 8 + length;
          }
          position = position + 8 + length;
      }while(position < audioData.byteLength);
      audioData = productArray.buffer;
      dv = new DataView(audioData);
      dv.setUint32(4, audioData.byteLength - 8, true);
      dv.setUint32(fmt_length_spot, 16, true);
      audioCtx.decodeAudioData(audioData, function(buffer) {
          source.buffer = buffer;
          source.connect(audioCtx.destination);
        },
        function(e){"Error with decoding audio data" + e.err});
    }
    request.send();
}
getData();
source.start(0);

Thanks Michael.

回答1:

It might be the JUNK chunk at the start of the file. You can run it through sox to clean out extraneous chunks like this:

sox Malice_Bass.wav Malice_Bass_simple.wav

Here's what my personal parser says about the file:

RIFF - WAVE (36467192 bytes)
   JUNK (92)
   bext (602)
         Description:       
         Originator:        Pro Tools
         Originator Ref:    jicj!dad1ofaaaGk
         Origination Date:  2014-09-09
         Origination Time:  20:46:43
         Time Ref Low:      0
         Time Ref High:     0
         BWF Version:       0
         SMPTE UMID Bytes:  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
         Coding History:    
   fmt (40)
         Format Tag:        1
         Channels:          2
         Samples per sec:   48000
         Avg bytes per sec: 192000
         Block align:       4
         Bits per sample:   16
   minf (16)
   elm1 (214)
   data (36466048)
   regn (92)
   umid (24)

When I clean it up using sox Firefox quits complaining about it but still doesn't play it. I confirmed that it loads the file but doesn't seem to play it.



回答2:

I've recently had this problem with Firefox not reading wav files using the browser's audio api and found out that the problem was the bit depth of the audio file which should not exceed 16bits in order to be recognized by Firefox. I've also found out that this is a 8 years old Firefox "bug" which is quite surprising (https://bugzilla.mozilla.org/show_bug.cgi?id=524109)

My soultion was to downgrade any wav files with 32 bit depth to 16bit via sox commandline like this: sox input.wav -b 16 output.wav. You could obviously use ffmpeg or any other application which can do that under Linux. Hope that helps.



回答3:

That wav file is silent for first 20 seconds. I just downloaded it :

wget https://mpclubtest.s3.amazonaws.com/Malice_Bass.wav

I tried using chrome and the fiddle was silent, initially I thought due to fact I'm just using laptop speakers. A FFT using audacity says its just very low freqs starting after 20 sec of silence.

Web Audio API uses the computer's default sampling rate, which is typically 44.1kHz Since the file is using 48 kHz, is your machine configured with a 48 kHz smple rate ? If you resample that file which is 48 kHz down to 44.1kHz which is a typical computer's sample rate it'll probably work.