Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why certain .wav files cannot be decoded in Firefox

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.

like image 895
laertiades Avatar asked Oct 02 '14 21:10

laertiades


1 Answers

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.

like image 197
DeZeA Avatar answered Sep 22 '22 05:09

DeZeA