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();
}
})
},
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();
}
})
},
Share
Improve this question
edited May 23, 2017 at 11:54
CommunityBot
11 silver badge
asked Mar 11, 2017 at 18:39
Jacob MyersJacob Myers
331 gold badge1 silver badge6 bronze badges
2
-
Why do you not use
.decodeAudioData().then()
instead of trying to return a value from callback function version of.decodeAudioData(callbackFunction)
?callbackFunction
is asynchronous, yes? – guest271314 Commented Mar 11, 2017 at 18:49 -
Wouldn't it be worth tackling this from the opposite direction and figure out why Chrome records in a different format and how to change that? You might want to luse
ffprobe
to check your file format. You can also useffmpeg
or a cloud based solution (there are several) to trans-code your file to make sure that it is always playable. – Marc Rohloff Commented Mar 11, 2017 at 23:13
1 Answer
Reset to default 3Until very recently, decodeAudioData
could not decode the result of Chrome's MediaRecorder
. Try a Chrome canary or beta to see if this is fixed. If you still have a problem, provide a more plete (but simple) example of what's not working.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745042867a4607917.html
评论列表(0条)