I am using AudioContext's decodeAudioData method to play back audio in Chrome, Firefox, and Opera. All browsers successfully decode and play audio that was recorded using Firefox. But when the audio was recorded using Chrome or Opera, only Firefox successfully decodes and plays it back. I get the following error when decoding the audio in Chrome or Opera:
Uncaught (in promise) DOMException: Unable to decode audio data.
I attempted to implement Ladislav Nevery's suggested fix mentioned here: decodeAudioData returning a null error
The implemented code executes his suggestion successfully (traversing through the buffer to find start points in the audio stream), but the decoding still fails in Chrome for the Firefox-recorded audio.
Any ideas why decoding is failing?
function syncStream(node){ // should be done by api itself. and hopefully will.
var buf8 = new Uint8Array(node.buf);
buf8.indexOf = Array.prototype.indexOf;
var i=node.sync, b=buf8;
while(1) {
node.retry++;
i=b.indexOf(0xFF,i); if(i==-1 || (b[i+1] & 0xE0 == 0xE0 )) break;
i++;
}
if(i!=-1) {
var tmp=node.buf.slice(i); //carefull there it returns copy
delete(node.buf); node.buf=null;
node.buf=tmp;
node.sync=i;
return true;
}
return false;
}
export function loadAudio(deckId) {
store.audioPlayerDomain.audioLoading = true;
let activeRecord = getActiveRecordByDeckId(deckId);
let path = `${deckId}/${activeRecord.id}`;
let context = getAudioContext();
let processFn = function(node){
return context.decodeAudioData(node.buf, function (decoded) {
return decoded;
},
function(){ // only on error attempt to sync on frame boundary
if(syncStream(node)){
return processFn(node);
};
});
};
return AudioPlayerWebAPI.default.getAudio(path, context)
.then((buffer) => {
let node = {};
node.buf=buffer;
node.sync=0;
node.retry=0;
return processFn(node);
}).then(function(decodedData) {
store.audioPlayerDomain.audio = decodedData;
store.audioPlayerDomain.audioLoading = false;
return true;
});
}
....
getAudio(path, context) {
return fetch(`/api/public/audio/${path}`)
.then(processResponse)
.then(function(response) {
if(response.message && response.message === 'non-existent'){
return null;
}else{
return response.arrayBuffer();
}
})
},