此問題並非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.
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(); }