528 lines
15 KiB
JavaScript
528 lines
15 KiB
JavaScript
|
/*
|
|||
|
mp3编码器,需带上src/engine/mp3-engine.js引擎使用
|
|||
|
https://github.com/xiangyuecn/Recorder
|
|||
|
|
|||
|
当然最佳推荐使用mp3、wav格式,代码也是优先照顾这两种格式
|
|||
|
浏览器支持情况
|
|||
|
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
|
|||
|
*/
|
|||
|
(function(factory){
|
|||
|
var browser=typeof window=="object" && !!window.document;
|
|||
|
var win=browser?window:Object; //非浏览器环境,Recorder挂载在Object下面
|
|||
|
var rec=win.Recorder,ni=rec.i18n;
|
|||
|
factory(rec,ni,ni.$T,browser);
|
|||
|
}(function(Recorder,i18n,$T,isBrowser){
|
|||
|
"use strict";
|
|||
|
|
|||
|
var SampleS="48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000";
|
|||
|
var BitS="8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 192, 224, 256, 320";
|
|||
|
Recorder.prototype.enc_mp3={
|
|||
|
stable:true,takeEC:"full"
|
|||
|
,getTestMsg:function(){
|
|||
|
return $T("Zm7L::采样率范围:{1};比特率范围:{2}(不同比特率支持的采样率范围不同,小于32kbps时采样率需小于32000)",0,SampleS,BitS);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var NormalizeSet=function(set){
|
|||
|
var bS=set.bitRate, sS=set.sampleRate,s=sS;
|
|||
|
if((" "+BitS+",").indexOf(" "+bS+",")==-1){
|
|||
|
Recorder.CLog($T("eGB9::{1}不在mp3支持的取值范围:{2}",0,"bitRate="+bS,BitS),3);
|
|||
|
}
|
|||
|
if((" "+SampleS+",").indexOf(" "+sS+",")==-1){//engine SmpFrqIndex函数会检测
|
|||
|
var arr=SampleS.split(", "),vs=[];
|
|||
|
for(var i=0;i<arr.length;i++) vs.push({v:+arr[i],s:Math.abs(arr[i]-sS)});
|
|||
|
vs.sort(function(a,b){return a.s-b.s}); s=vs[0].v;
|
|||
|
|
|||
|
set.sampleRate=s;
|
|||
|
Recorder.CLog($T("zLTa::sampleRate已更新为{1},因为{2}不在mp3支持的取值范围:{3}",0,s,sS,SampleS),3);
|
|||
|
}
|
|||
|
};
|
|||
|
var ImportEngineErr=function(){
|
|||
|
return $T.G("NeedImport-2",["mp3.js","src/engine/mp3-engine.js"]);
|
|||
|
};
|
|||
|
//是否支持web worker
|
|||
|
var HasWebWorker=isBrowser && typeof Worker=="function";
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//*******标准UI线程转码支持函数************
|
|||
|
|
|||
|
Recorder.prototype.mp3=function(res,True,False){
|
|||
|
var This=this,set=This.set,size=res.length;
|
|||
|
if(!Recorder.lamejs){
|
|||
|
False(ImportEngineErr()); return;
|
|||
|
};
|
|||
|
|
|||
|
//优先采用worker编码,非worker时用老方法提供兼容
|
|||
|
if(HasWebWorker){
|
|||
|
var ctx=This.mp3_start(set);
|
|||
|
if(ctx){
|
|||
|
if(ctx.isW){
|
|||
|
This.mp3_encode(ctx,res);
|
|||
|
This.mp3_complete(ctx,True,False,1);
|
|||
|
return;
|
|||
|
}
|
|||
|
This.mp3_stop(ctx);
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
NormalizeSet(set);
|
|||
|
//https://github.com/wangpengfei15975/recorder.js
|
|||
|
//https://github.com/zhuker/lamejs bug:采样率必须和源一致,不然8k时没有声音,有问题fix:https://github.com/zhuker/lamejs/pull/11
|
|||
|
var mp3=new Recorder.lamejs.Mp3Encoder(1,set.sampleRate,set.bitRate);
|
|||
|
|
|||
|
var blockSize=57600;
|
|||
|
var memory=new Int8Array(500000), mOffset=0;
|
|||
|
|
|||
|
var idx=0;
|
|||
|
var run=function(){
|
|||
|
try{
|
|||
|
if(idx<size){
|
|||
|
var buf=mp3.encodeBuffer(res.subarray(idx,idx+blockSize));
|
|||
|
}else{
|
|||
|
var buf=mp3.flush();
|
|||
|
};
|
|||
|
}catch(e){ //精简代码调用了abort
|
|||
|
console.error(e);
|
|||
|
False("MP3 Encoder: "+e.message);
|
|||
|
return;
|
|||
|
};
|
|||
|
var bufLen=buf.length;
|
|||
|
if(bufLen>0){
|
|||
|
if(mOffset+bufLen>memory.length){
|
|||
|
var tmp=new Int8Array(memory.length+Math.max(500000,bufLen));
|
|||
|
tmp.set(memory.subarray(0, mOffset));
|
|||
|
memory=tmp;
|
|||
|
}
|
|||
|
memory.set(buf,mOffset);
|
|||
|
mOffset+=bufLen;
|
|||
|
};
|
|||
|
|
|||
|
if(idx<size){
|
|||
|
idx+=blockSize;
|
|||
|
setTimeout(run);//尽量避免卡ui
|
|||
|
}else{
|
|||
|
var data=[memory.buffer.slice(0,mOffset)];
|
|||
|
//去掉开头的标记信息帧
|
|||
|
var meta=mp3TrimFix.fn(data,mOffset,size,set.sampleRate);
|
|||
|
mp3TrimFixSetMeta(meta,set);
|
|||
|
|
|||
|
True(data[0]||new ArrayBuffer(0),"audio/mp3");
|
|||
|
};
|
|||
|
};
|
|||
|
run();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//********边录边转码(Worker)支持函数,如果提供就代表可能支持,否则只支持标准转码*********
|
|||
|
|
|||
|
//全局共享一个Worker,后台串行执行。如果每次都开一个新的,编码速度可能会慢很多,可能是浏览器运行缓存的因素,并且可能瞬间产生多个并行操作占用大量cpu
|
|||
|
var mp3Worker;
|
|||
|
Recorder.BindDestroy("mp3Worker",function(){
|
|||
|
if(mp3Worker){
|
|||
|
Recorder.CLog("mp3Worker Destroy");
|
|||
|
mp3Worker.terminate();
|
|||
|
mp3Worker=null;
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
|
|||
|
Recorder.prototype.mp3_envCheck=function(envInfo,set){//检查环境下配置是否可用
|
|||
|
var errMsg="";
|
|||
|
//需要实时编码返回数据,此时需要检查是否可实时编码
|
|||
|
if(set.takeoffEncodeChunk){
|
|||
|
if(!newContext()){//浏览器不能创建实时编码环境
|
|||
|
errMsg=$T("yhUs::当前浏览器版本太低,无法实时处理");
|
|||
|
};
|
|||
|
};
|
|||
|
if(!errMsg && !Recorder.lamejs){
|
|||
|
errMsg=ImportEngineErr();
|
|||
|
};
|
|||
|
return errMsg;
|
|||
|
};
|
|||
|
Recorder.prototype.mp3_start=function(set){//如果返回null代表不支持
|
|||
|
return newContext(set);
|
|||
|
};
|
|||
|
var openList={id:0};
|
|||
|
var newContext=function(setOrNull,_badW){
|
|||
|
//独立运行的函数,scope.wkScope worker.onmessage 字符串会被替换
|
|||
|
var run=function(e){
|
|||
|
var ed=e.data;
|
|||
|
var wk_ctxs=scope.wkScope.wk_ctxs;
|
|||
|
var wk_lame=scope.wkScope.wk_lame;
|
|||
|
var wk_mp3TrimFix=scope.wkScope.wk_mp3TrimFix;
|
|||
|
|
|||
|
var cur=wk_ctxs[ed.id];
|
|||
|
if(ed.action=="init"){
|
|||
|
wk_ctxs[ed.id]={
|
|||
|
sampleRate:ed.sampleRate
|
|||
|
,bitRate:ed.bitRate
|
|||
|
,takeoff:ed.takeoff
|
|||
|
|
|||
|
,pcmSize:0
|
|||
|
,memory:new Int8Array(500000), mOffset:0
|
|||
|
,encObj:new wk_lame.Mp3Encoder(1,ed.sampleRate,ed.bitRate)
|
|||
|
};
|
|||
|
}else if(!cur){
|
|||
|
return;
|
|||
|
};
|
|||
|
var addBytes=function(buf){
|
|||
|
var bufLen=buf.length;
|
|||
|
if(cur.mOffset+bufLen>cur.memory.length){
|
|||
|
var tmp=new Int8Array(cur.memory.length+Math.max(500000,bufLen));
|
|||
|
tmp.set(cur.memory.subarray(0, cur.mOffset));
|
|||
|
cur.memory=tmp;
|
|||
|
}
|
|||
|
cur.memory.set(buf,cur.mOffset);
|
|||
|
cur.mOffset+=bufLen;
|
|||
|
};
|
|||
|
|
|||
|
switch(ed.action){
|
|||
|
case "stop":
|
|||
|
cur.encObj=null;
|
|||
|
delete wk_ctxs[ed.id];
|
|||
|
break;
|
|||
|
case "encode":
|
|||
|
cur.pcmSize+=ed.pcm.length;
|
|||
|
try{
|
|||
|
var buf=cur.encObj.encodeBuffer(ed.pcm);
|
|||
|
}catch(e){ //精简代码调用了abort
|
|||
|
cur.err=e;
|
|||
|
console.error(e);
|
|||
|
};
|
|||
|
if(buf && buf.length>0){
|
|||
|
if(cur.takeoff){
|
|||
|
worker.onmessage({action:"takeoff",id:ed.id,chunk:buf});
|
|||
|
}else{
|
|||
|
addBytes(buf);
|
|||
|
};
|
|||
|
};
|
|||
|
break;
|
|||
|
case "complete":
|
|||
|
try{
|
|||
|
var buf=cur.encObj.flush();
|
|||
|
}catch(e){ //精简代码调用了abort
|
|||
|
cur.err=e;
|
|||
|
console.error(e);
|
|||
|
};
|
|||
|
if(buf && buf.length>0){
|
|||
|
if(cur.takeoff){
|
|||
|
worker.onmessage({action:"takeoff",id:ed.id,chunk:buf});
|
|||
|
}else{
|
|||
|
addBytes(buf);
|
|||
|
};
|
|||
|
};
|
|||
|
if(cur.err){
|
|||
|
worker.onmessage({action:ed.action,id:ed.id
|
|||
|
,err:"MP3 Encoder: "+cur.err.message});
|
|||
|
break;
|
|||
|
};
|
|||
|
|
|||
|
var data=[cur.memory.buffer.slice(0,cur.mOffset)];
|
|||
|
//去掉开头的标记信息帧
|
|||
|
var meta=wk_mp3TrimFix.fn(data,cur.mOffset,cur.pcmSize,cur.sampleRate);
|
|||
|
|
|||
|
worker.onmessage({
|
|||
|
action:ed.action
|
|||
|
,id:ed.id
|
|||
|
,blob:data[0]||new ArrayBuffer(0)
|
|||
|
,meta:meta
|
|||
|
});
|
|||
|
break;
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
var initOnMsg=function(isW){
|
|||
|
worker.onmessage=function(e){
|
|||
|
var data=e; if(isW)data=e.data;
|
|||
|
var ctx=openList[data.id];
|
|||
|
if(ctx){
|
|||
|
if(data.action=="takeoff"){
|
|||
|
//取走实时生成的mp3数据
|
|||
|
ctx.set.takeoffEncodeChunk(new Uint8Array(data.chunk.buffer));
|
|||
|
}else{
|
|||
|
//complete
|
|||
|
ctx.call&&ctx.call(data);
|
|||
|
ctx.call=null;
|
|||
|
};
|
|||
|
};
|
|||
|
};
|
|||
|
};
|
|||
|
var initCtx=function(){
|
|||
|
var ctx={worker:worker,set:setOrNull};
|
|||
|
if(setOrNull){
|
|||
|
ctx.id=++openList.id;
|
|||
|
openList[ctx.id]=ctx;
|
|||
|
|
|||
|
NormalizeSet(setOrNull);
|
|||
|
|
|||
|
worker.postMessage({
|
|||
|
action:"init"
|
|||
|
,id:ctx.id
|
|||
|
,sampleRate:setOrNull.sampleRate
|
|||
|
,bitRate:setOrNull.bitRate
|
|||
|
,takeoff:!!setOrNull.takeoffEncodeChunk
|
|||
|
|
|||
|
,x:new Int16Array(5)//低版本浏览器不支持序列化TypedArray
|
|||
|
});
|
|||
|
}else{
|
|||
|
worker.postMessage({
|
|||
|
x:new Int16Array(5)//低版本浏览器不支持序列化TypedArray
|
|||
|
});
|
|||
|
};
|
|||
|
return ctx;
|
|||
|
};
|
|||
|
var scope,worker=mp3Worker;
|
|||
|
|
|||
|
//非浏览器,不支持worker,或者开启失败,使用UI线程处理
|
|||
|
if(_badW || !HasWebWorker){
|
|||
|
Recorder.CLog($T("k9PT::当前环境不支持Web Worker,mp3实时编码器运行在主线程中"),3);
|
|||
|
worker={ postMessage:function(ed){ run({data:ed}); } };
|
|||
|
scope={wkScope:{
|
|||
|
wk_ctxs:{}, wk_lame:Recorder.lamejs, wk_mp3TrimFix:mp3TrimFix
|
|||
|
}};
|
|||
|
initOnMsg();
|
|||
|
return initCtx();
|
|||
|
};
|
|||
|
|
|||
|
try{
|
|||
|
if(!worker){
|
|||
|
//创建一个新Worker
|
|||
|
var onmsg=(run+"").replace(/[\w\$]+\.onmessage/g,"self.postMessage");
|
|||
|
onmsg=onmsg.replace(/[\w\$]+\.wkScope/g,"wkScope");
|
|||
|
var jsCode=");wk_lame();self.onmessage="+onmsg;
|
|||
|
jsCode+=";var wkScope={ wk_ctxs:{},wk_lame:wk_lame";
|
|||
|
jsCode+=",wk_mp3TrimFix:{rm:"+mp3TrimFix.rm+",fn:"+mp3TrimFix.fn+"} }";
|
|||
|
|
|||
|
var lamejsCode=Recorder.lamejs.toString();
|
|||
|
var url=(window.URL||webkitURL).createObjectURL(new Blob(["var wk_lame=(",lamejsCode,jsCode], {type:"text/javascript"}));
|
|||
|
|
|||
|
worker=new Worker(url);
|
|||
|
setTimeout(function(){
|
|||
|
(window.URL||webkitURL).revokeObjectURL(url);//必须要释放,不然每次调用内存都明显泄露内存
|
|||
|
},10000);//chrome 83 file协议下如果直接释放,将会使WebWorker无法启动
|
|||
|
initOnMsg(1);
|
|||
|
};
|
|||
|
|
|||
|
var ctx=initCtx(); ctx.isW=1;
|
|||
|
mp3Worker=worker;
|
|||
|
return ctx;
|
|||
|
}catch(e){//出错了就不要提供了
|
|||
|
worker&&worker.terminate();
|
|||
|
console.error(e);
|
|||
|
return newContext(setOrNull, 1);//切换到UI线程处理
|
|||
|
};
|
|||
|
};
|
|||
|
Recorder.prototype.mp3_stop=function(startCtx){
|
|||
|
if(startCtx&&startCtx.worker){
|
|||
|
startCtx.worker.postMessage({
|
|||
|
action:"stop"
|
|||
|
,id:startCtx.id
|
|||
|
});
|
|||
|
startCtx.worker=null;
|
|||
|
delete openList[startCtx.id];
|
|||
|
|
|||
|
//疑似泄露检测 排除id
|
|||
|
var opens=-1;
|
|||
|
for(var k in openList){
|
|||
|
opens++;
|
|||
|
};
|
|||
|
if(opens){
|
|||
|
Recorder.CLog($T("fT6M::mp3 worker剩{1}个未stop",0,opens),3);
|
|||
|
};
|
|||
|
};
|
|||
|
};
|
|||
|
Recorder.prototype.mp3_encode=function(startCtx,pcm){
|
|||
|
if(startCtx&&startCtx.worker){
|
|||
|
startCtx.worker.postMessage({
|
|||
|
action:"encode"
|
|||
|
,id:startCtx.id
|
|||
|
,pcm:pcm
|
|||
|
});
|
|||
|
};
|
|||
|
};
|
|||
|
Recorder.prototype.mp3_complete=function(startCtx,True,False,autoStop){
|
|||
|
var This=this;
|
|||
|
if(startCtx&&startCtx.worker){
|
|||
|
startCtx.call=function(data){
|
|||
|
if(autoStop){
|
|||
|
This.mp3_stop(startCtx);
|
|||
|
};
|
|||
|
if(data.err){
|
|||
|
False(data.err);
|
|||
|
}else{
|
|||
|
mp3TrimFixSetMeta(data.meta,startCtx.set);
|
|||
|
True(data.blob,"audio/mp3");
|
|||
|
};
|
|||
|
};
|
|||
|
startCtx.worker.postMessage({
|
|||
|
action:"complete"
|
|||
|
,id:startCtx.id
|
|||
|
});
|
|||
|
}else{
|
|||
|
False($T("mPxH::mp3编码器未start"));
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//*******辅助函数************
|
|||
|
|
|||
|
/*读取lamejs编码出来的mp3信息,只能读特定格式,如果读取失败返回null
|
|||
|
mp3Buffers=[ArrayBuffer,...]
|
|||
|
length=mp3Buffers的数据二进制总长度
|
|||
|
*/
|
|||
|
Recorder.mp3ReadMeta=function(mp3Buffers,length){
|
|||
|
//kill babel-polyfill ES6 Number.parseInt 不然放到Worker里面找不到方法,也不能用typeof(x)==object 会被替换成 _typeof
|
|||
|
var parseInt_ES3=typeof(window)!="undefined"&&window.parseInt||typeof(self)!="undefined"&&self.parseInt||parseInt;
|
|||
|
|
|||
|
var u8arr0=new Uint8Array(mp3Buffers[0]||[]);
|
|||
|
if(u8arr0.length<4){
|
|||
|
return null;
|
|||
|
};
|
|||
|
var byteAt=function(idx,u8){
|
|||
|
return ("0000000"+((u8||u8arr0)[idx]||0).toString(2)).substr(-8);
|
|||
|
};
|
|||
|
var b2=byteAt(0)+byteAt(1);
|
|||
|
var b4=byteAt(2)+byteAt(3);
|
|||
|
|
|||
|
if(!/^1{11}/.test(b2)){//未发现帧同步
|
|||
|
return null;
|
|||
|
};
|
|||
|
var version=({"00":2.5,"10":2,"11":1})[b2.substr(11,2)];
|
|||
|
var layer=({"01":3})[b2.substr(13,2)];//仅支持Layer3
|
|||
|
var sampleRate=({ //lamejs -> Tables.samplerate_table
|
|||
|
"1":[44100, 48000, 32000]
|
|||
|
,"2":[22050, 24000, 16000]
|
|||
|
,"2.5":[11025, 12000, 8000]
|
|||
|
})[version];
|
|||
|
sampleRate&&(sampleRate=sampleRate[parseInt_ES3(b4.substr(4,2),2)]);
|
|||
|
var bitRate=[ //lamejs -> Tables.bitrate_table
|
|||
|
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] //MPEG 2 2.5
|
|||
|
,[0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]//MPEG 1
|
|||
|
][version==1?1:0][parseInt_ES3(b4.substr(0,4),2)];
|
|||
|
|
|||
|
if(!version || !layer || !bitRate || !sampleRate){
|
|||
|
return null;
|
|||
|
};
|
|||
|
|
|||
|
var duration=Math.round(length*8/bitRate);
|
|||
|
var frame=layer==1?384:layer==2?1152:version==1?1152:576;
|
|||
|
var frameDurationFloat=frame/sampleRate*1000;
|
|||
|
var frameSize=Math.floor((frame*bitRate)/8/sampleRate*1000);
|
|||
|
|
|||
|
//检测是否存在Layer3帧填充1字节。这里只获取第二帧的填充信息,首帧永远没有填充。其他帧可能隔一帧出现一个填充,或者隔很多帧出现一个填充;目测是取决于frameSize未舍入时的小数部分,因为有些采样率的frameSize会出现小数(11025、22050、44100 典型的除不尽),然后字节数无法表示这种小数,就通过一定步长来填充弥补小数部分丢失
|
|||
|
var hasPadding=0,seek=0;
|
|||
|
for(var i=0;i<mp3Buffers.length;i++){
|
|||
|
//寻找第二帧
|
|||
|
var buf=mp3Buffers[i];
|
|||
|
seek+=buf.byteLength;
|
|||
|
if(seek>=frameSize+3){
|
|||
|
var buf8=new Uint8Array(buf);
|
|||
|
var idx=buf.byteLength-(seek-(frameSize+3)+1);
|
|||
|
var ib4=byteAt(idx,buf8);
|
|||
|
hasPadding=ib4.charAt(6)=="1";
|
|||
|
break;
|
|||
|
};
|
|||
|
};
|
|||
|
if(hasPadding){
|
|||
|
frameSize++;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
return {
|
|||
|
version:version //1 2 2.5 -> MPEG1 MPEG2 MPEG2.5
|
|||
|
,layer:layer//3 -> Layer3
|
|||
|
,sampleRate:sampleRate //采样率 hz
|
|||
|
,bitRate:bitRate //比特率 kbps
|
|||
|
|
|||
|
,duration:duration //音频时长 ms
|
|||
|
,size:length //总长度 byte
|
|||
|
,hasPadding:hasPadding //是否存在1字节填充,首帧永远没有,这个值其实代表的第二帧是否有填充,并不代表其他帧的
|
|||
|
,frameSize:frameSize //每帧最大长度,含可能存在的1字节padding byte
|
|||
|
,frameDurationFloat:frameDurationFloat //每帧时长,含小数 ms
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
//去掉lamejs开头的标记信息帧,免得mp3解码出来的时长比pcm的长太多
|
|||
|
var mp3TrimFix={//minfiy keep name
|
|||
|
rm:Recorder.mp3ReadMeta
|
|||
|
,fn:function(mp3Buffers,length,pcmLength,pcmSampleRate){
|
|||
|
var meta=this.rm(mp3Buffers,length);
|
|||
|
if(!meta){
|
|||
|
return {err:"mp3 unknown format"};
|
|||
|
};
|
|||
|
var pcmDuration=Math.round(pcmLength/pcmSampleRate*1000);
|
|||
|
|
|||
|
//开头多出这么多帧,移除掉;正常情况下最多为2帧
|
|||
|
var num=Math.floor((meta.duration-pcmDuration)/meta.frameDurationFloat);
|
|||
|
if(num>0){
|
|||
|
var size=num*meta.frameSize-(meta.hasPadding?1:0);//首帧没有填充,第二帧可能有填充,这里假设最多为2帧(测试并未出现3帧以上情况),其他帧不管,就算出现了并且导致了错误后面自动容错
|
|||
|
length-=size;
|
|||
|
var arr0=0,arrs=[];
|
|||
|
for(var i=0;i<mp3Buffers.length;i++){
|
|||
|
var arr=mp3Buffers[i];
|
|||
|
if(size<=0){
|
|||
|
break;
|
|||
|
};
|
|||
|
if(size>=arr.byteLength){
|
|||
|
size-=arr.byteLength;
|
|||
|
arrs.push(arr);
|
|||
|
mp3Buffers.splice(i,1);
|
|||
|
i--;
|
|||
|
}else{
|
|||
|
mp3Buffers[i]=arr.slice(size);
|
|||
|
arr0=arr;
|
|||
|
size=0;
|
|||
|
};
|
|||
|
};
|
|||
|
var checkMeta=this.rm(mp3Buffers,length);
|
|||
|
if(!checkMeta){
|
|||
|
//还原变更,应该不太可能会出现
|
|||
|
arr0&&(mp3Buffers[0]=arr0);
|
|||
|
for(var i=0;i<arrs.length;i++){
|
|||
|
mp3Buffers.splice(i,0,arrs[i]);
|
|||
|
};
|
|||
|
meta.err="mp3 fix error: 已还原,错误原因不明"; //worker里面没$T翻译
|
|||
|
};
|
|||
|
|
|||
|
var fix=meta.trimFix={};
|
|||
|
fix.remove=num;
|
|||
|
fix.removeDuration=Math.round(num*meta.frameDurationFloat);
|
|||
|
fix.duration=Math.round(length*8/meta.bitRate);
|
|||
|
};
|
|||
|
return meta;
|
|||
|
}
|
|||
|
};
|
|||
|
var mp3TrimFixSetMeta=function(meta,set){
|
|||
|
var tag="MP3 Info: ";
|
|||
|
if(meta.sampleRate&&meta.sampleRate!=set.sampleRate || meta.bitRate&&meta.bitRate!=set.bitRate){
|
|||
|
Recorder.CLog(tag+$T("uY9i::和设置的不匹配{1},已更新成{2}",0,"set:"+set.bitRate+"kbps "+set.sampleRate+"hz","set:"+meta.bitRate+"kbps "+meta.sampleRate+"hz"),3,set);
|
|||
|
set.sampleRate=meta.sampleRate;
|
|||
|
set.bitRate=meta.bitRate;
|
|||
|
};
|
|||
|
|
|||
|
var trimFix=meta.trimFix;
|
|||
|
if(trimFix){
|
|||
|
tag+=$T("iMSm::Fix移除{1}帧",0,trimFix.remove)+" "+trimFix.removeDuration+"ms -> "+trimFix.duration+"ms";
|
|||
|
if(trimFix.remove>2){
|
|||
|
meta.err=(meta.err?meta.err+", ":"")+$T("b9zm::移除帧数过多");
|
|||
|
};
|
|||
|
}else{
|
|||
|
tag+=(meta.duration||"-")+"ms";
|
|||
|
};
|
|||
|
|
|||
|
if(meta.err){
|
|||
|
Recorder.CLog(tag,1,meta.err,meta);
|
|||
|
}else{
|
|||
|
Recorder.CLog(tag,meta);
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}));
|