audioContext.decodeAudioData 返回null 错误

 

此问题并非100%出现。没想到国外大神已经有处理此问题的经验javascript

原贴地址: https://stackoverflow.com/questions/10365335/decodeaudiodata-returning-a-null-errorjava

 

看了大神的解决办法,受到了启发,node

此错误大概就是XMLHttpRequest请求回来的数据缺乏必要的数据头,致使.decodeAudioData  没法成功解析音乐文件。web

根据本身当前的状况,我将音乐长度延长到1s+(以前不足0.2s),使用Adobe Audition从新输出后,问题再没有复现。api

若是你的音乐是动态合成或者本身没法控制的,能够按国外大神的办法尝试处理(项目时间紧张,目前仅先记录到bolg 并无测试他的代码)app

 

 

为了不原贴失效或没法访问,这里直接搬一下测试

The real reason is that both createBuffer and decodeAudioData right now have a Bug and throw weird vague DOM exception 12 for files they should normally play. But we should be aware that this is new and evolving technology and be thankful even for web audio api as it is now since its small miracle that happened to us.this

They are missing stream syncing on header boundary that any reasonable decoder of streaming audio format should start with. And mp3 or many aac/adts files are streaming fileformats. streaming means that you can cut them anywhere or insert append anything (various tags even image artwork) decoder shouldnt care about unknown data. decoder should just seek until he finds header he knows and can decode.url

I thrown together this temporary solution that seeks to nearest frame header start and passes data from this offset only.prototype

mp3 or mp2 all start header for every audio frame (every around 200bytes) with 0XFFE and aac(adts) on oxFFF syncword that is there just for this reason. therefore both will sync on 0xFFE. Here is the code I currently use to play previously not played files.

What I hate is that arrayBuffer doesnt have subarray() like its typed childs to return just different view from different offset instead of whole new array copy that slice() returns. if only webaudio api accepted typedarrays as input but unfortunately the only way to create arraybuffer back seems huge slice() copy. thankfully usually only one or two seeks are needed.

 

Forcing Web Audio Api to not being Picky about files

node={};
node.url='usual_mp3_with_tags_or_album_artwork.mp3';

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;
}

function decode(node) {
    try{
        context.decodeAudioData(node.buf,
        function(decoded){
            node.source  = context.createBufferSource();
            node.source.connect(context.destination);
            node.source.buffer=decoded; 
            node.source.noteOn(0);
        },
        function(){ // only on error attempt to sync on frame boundary
            if(syncStream(node)) decode(node);
        });
    } catch(e) {
        log('decode exception',e.message);
    }
}

function playSound(node) { 
    node.xhr = new XMLHttpRequest();
    node.xhr.onload=function(){  
        node.buf=node.xhr.response;
        node.sync=0;
        node.retry=0;
        decode(node);
    }
    node.xhr.open("GET", node.url, true); 
    node.xhr.responseType = "arraybuffer"; 
    node.xhr.send();
}
相关文章
相关标签/搜索