6 lines
16 KiB
JavaScript
Executable File
6 lines
16 KiB
JavaScript
Executable File
/*
|
||
录音
|
||
https://github.com/xiangyuecn/Recorder
|
||
src: recorder-core.js
|
||
*/
|
||
!function(I){"use strict";var d=function(){},P=function(e){return new t(e)};P.LM="2023-06-10 21:09";var w="Recorder",C="getUserMedia",U="srcSampleRate",W="sampleRate",L="catch";P.IsOpen=function(){var e=P.Stream;if(e){var t=e.getTracks&&e.getTracks()||e.audioTracks||[],r=t[0];if(r){var n=r.readyState;return"live"==n||n==r.LIVE}}return!1},P.BufferSize=4096,P.Destroy=function(){for(var e in z(w+" Destroy"),y(),r)r[e]()};var r={};P.BindDestroy=function(e,t){r[e]=t},P.Support=function(){var e=navigator.mediaDevices||{};return e[C]||(e=navigator)[C]||(e[C]=e.webkitGetUserMedia||e.mozGetUserMedia||e.msGetUserMedia),!!e[C]&&(P.Scope=e,!!P.GetContext())},P.GetContext=function(){var e=I.AudioContext;return e||(e=I.webkitAudioContext),e?(P.Ctx&&"closed"!=P.Ctx.state||(P.Ctx=new e,P.BindDestroy("Ctx",function(){var e=P.Ctx;e&&e.close&&(e.close(),P.Ctx=0)})),P.Ctx):null};var A="ConnectEnableWebM";P[A]=!0;var T="ConnectEnableWorklet";P[T]=!1;var S=function(e,c){var f,r,u,l=e.BufferSize||P.BufferSize,v=P.Ctx,p=e.Stream,i=function(e){var t=p._m=v.createMediaStreamSource(p);t.connect(e),e.connect(v.destination)},h="",g=p._call,m=function(e){for(var t in g){for(var r=e.length,n=new Int16Array(r),a=0,o=0;o<r;o++){var i=Math.max(-1,Math.min(1,e[o]));i=i<0?32768*i:32767*i,n[o]=i,a+=Math.abs(i)}for(var s in g)g[s](n,a);return}},d="ScriptProcessor",C="audioWorklet",s=w+" "+C,S="RecProc",y="MediaRecorder",_=y+".WebM.PCM",b=v.createScriptProcessor||v.createJavaScriptNode,k="。由于"+C+"内部1秒375次回调,在移动端可能会有性能问题导致回调丢失录音变短,PC端无影响,暂不建议开启"+C+"。",M=function(){r=p.isWorklet=!1,D(p),z("Connect采用老的"+d+","+(P[T]?"但已":"可")+"设置"+w+"."+T+"=true尝试启用"+C+h+k,3);var e=p._p=b.call(v,l,1,1);i(e),e.onaudioprocess=function(e){var t=e.inputBuffer.getChannelData(0);m(t)}},x=function(){f=p.isWebM=!1,O(p),r=p.isWorklet=!b||P[T];var t=I.AudioWorkletNode;if(r&&v[C]&&t){var n=function(){return r&&p._na},a=p._na=function(){""!==u&&(clearTimeout(u),u=setTimeout(function(){u=0,n()&&(z(C+"未返回任何音频,恢复使用"+d,3),b&&M())},500))},o=function(){if(n()){var e=p._n=new t(v,S,{processorOptions:{bufferSize:l}});i(e),e.port.onmessage=function(e){u&&(clearTimeout(u),u=""),n()?m(e.data.val):r||z(C+"多余回调",3)},z("Connect采用"+C+",设置"+w+"."+T+"=false可恢复老式"+d+h+k,3)}};v.resume()[g&&"finally"](function(){if(n())if(v[S])o();else{var e,t,r=(t="class "+S+" extends AudioWorkletProcessor{",t+="constructor "+(e=function(e){return e.toString().replace(/^function|DEL_/g,"").replace(/\$RA/g,s)})(function(e){DEL_super(e);var t=this,r=e.processorOptions.bufferSize;t.bufferSize=r,t.buffer=new Float32Array(2*r),t.pos=0,t.port.onmessage=function(e){e.data.kill&&(t.kill=!0,$C.log("$RA kill call"))},$C.log("$RA .ctor call",e)}),t+="process "+e(function(e,t,r){var n=this,a=n.bufferSize,o=n.buffer,i=n.pos;if((e=(e[0]||[])[0]||[]).length){o.set(e,i);var s=~~((i+=e.length)/a)*a;if(s){this.port.postMessage({val:o.slice(0,s)});var c=o.subarray(s,i);(o=new Float32Array(2*a)).set(c),i=c.length,n.buffer=o}n.pos=i}return!n.kill}),t=(t+='}try{registerProcessor("'+S+'", '+S+')}catch(e){$C.error("'+s+'注册失败",e)}').replace(/\$C\./g,"console."),"data:text/javascript;base64,"+btoa(unescape(encodeURIComponent(t))));v[C].addModule(r).then(function(e){n()&&(v[S]=1,o(),u&&a())})[L](function(e){z(C+".addModule失败",1,e),n()&&M()})}})}else M()};!function(){var e=I[y],t="ondataavailable",r="audio/webm; codecs=pcm";f=p.isWebM=P[A];var n=e&&t in e.prototype&&e.isTypeSupported(r);if(h=n?"":"(此浏览器不支持"+_+")",!c||!f||!n)return x();var a=function(){return f&&p._ra},o=(p._ra=function(){""!==u&&(clearTimeout(u),u=setTimeout(function(){a()&&(z(y+"未返回任何音频,降级使用"+C,3),x())},500))},Object.assign({mimeType:r},P.ConnectWebMOptions)),i=p._r=new e(p,o),s=p._rd={sampleRate:v[W]};i[t]=function(e){var t=new FileReader;t.onloadend=function(){if(a()){var e=F(new Uint8Array(t.result),s);if(!e)return;if(-1==e)return void x();u&&(clearTimeout(u),u=""),m(e)}else f||z(y+"多余回调",3)},t.readAsArrayBuffer(e.data)},i.start(~~(l/48)),z("Connect采用"+_+",设置"+w+"."+A+"=false可恢复使用"+C+"或老式"+d)}()},D=function(e){e._na=null,e._n&&(e._n.port.postMessage({kill:!0}),e._n.disconnect(),e._n=null)},O=function(e){e._ra=null,e._r&&(e._r.stop(),e._r=null)},y=function(e){var t=(e=e||P)==P,r=e.Stream;if(r&&(r._m&&(r._m.disconnect(),r._m=null),r._p&&(r._p.disconnect(),r._p.onaudioprocess=r._p=null),D(r),O(r),t)){for(var n=r.getTracks&&r.getTracks()||r.audioTracks||[],a=0;a<n.length;a++){var o=n[a];o.stop&&o.stop()}r.stop&&r.stop()}e.Stream=0};P.SampleData=function(e,t,r,n,a){n||(n={});var o=n.index||0,i=n.offset||0,s=n.frameNext||[];a||(a={});var c=a.frameSize||1;a.frameType&&(c="mp3"==a.frameType?1152:1);var f=e.length;f+1<o&&z("SampleData似乎传入了未重置chunk "+o+">"+f,3);for(var u=0,l=o;l<f;l++)u+=e[l].length;u=Math.max(0,u-Math.floor(i));var v=t/r;1<v?u=Math.floor(u/v):(v=1,r=t),u+=s.length;for(var p=new Int16Array(u),h=0,l=0;l<s.length;l++)p[h]=s[l],h++;for(;o<f;o++){for(var g=e[o],l=i,m=g.length;l<m;){var d=Math.floor(l),C=Math.ceil(l),S=l-d,y=g[d],_=C<m?g[C]:(e[o+1]||[y])[0]||0;p[h]=y+(_-y)*S,h++,l+=v}i=l-m}s=null;var b=p.length%c;if(0<b){var k=2*(p.length-b);s=new Int16Array(p.buffer.slice(k)),p=new Int16Array(p.buffer.slice(0,k))}return{index:o,offset:i,frameNext:s,sampleRate:r,data:p}},P.PowerLevel=function(e,t){var r=e/t||0;return r<1251?Math.round(r/1250*10):Math.round(Math.min(100,Math.max(0,100*(1+Math.log(r/1e4)/Math.log(10)))))},P.PowerDBFS=function(e){var t=Math.max(.1,e||0);return t=Math.min(t,32767),t=20*Math.log(t/32767)/Math.log(10),Math.max(-100,Math.round(t))},P.CLog=function(e,t){var r=new Date,n=("0"+r.getMinutes()).substr(-2)+":"+("0"+r.getSeconds()).substr(-2)+"."+("00"+r.getMilliseconds()).substr(-3),a=this&&this.envIn&&this.envCheck&&this.id,o=["["+n+" "+w+(a?":"+a:"")+"]"+e],i=arguments,s=I.console||{},c=2,f=s.log;for("number"==typeof t?f=1==t?s.error:3==t?s.warn:f:c=1;c<i.length;c++)o.push(i[c]);u?f&&f("[IsLoser]"+o[0],1<o.length?o:""):f.apply(s,o)};var z=function(){P.CLog.apply(this,arguments)},u=!0;try{u=!console.log.apply}catch(e){}var n=0;function t(e){this.id=++n,o();var t={type:"mp3",bitRate:16,sampleRate:16e3,onProcess:d};for(var r in e)t[r]=e[r];this.set=t,this._S=9,this.Sync={O:9,C:9}}P.Sync={O:9,C:9},P.prototype=t.prototype={CLog:z,_streamStore:function(){return this.set.sourceStream?this:P},open:function(e,r){var n=this,t=n.set,a=n._streamStore();e=e||d;var o=function(e,t){t=!!t,n.CLog("录音open失败:"+e+",isUserNotAllow:"+t,1),r&&r(e,t)},i=function(){n.CLog("open ok id:"+n.id),e(),n._SO=0},s=a.Sync,c=++s.O,f=s.C;n._O=n._O_=c,n._SO=n._S;var u=n.envCheck({envName:"H5",canProcess:!0});if(u)o("不能录音:"+u);else if(t.sourceStream){if(!P.GetContext())return void o("不支持此浏览器从流中获取录音");y(a),n.Stream=t.sourceStream,n.Stream._call={};try{S(a)}catch(e){return void o("从流中打开录音失败:"+e.message)}i()}else{var l=function(e,t){try{I.top.a}catch(e){return void o('无权录音(跨域,请尝试给iframe添加麦克风访问策略,如allow="camera;microphone")')}/Permission|Allow/i.test(e)?o("用户拒绝了录音权限",!0):!1===I.isSecureContext?o("浏览器禁止不安全页面录音,可开启https解决"):/Found/i.test(e)?o(t+",无可用麦克风"):o(t)};if(P.IsOpen())i();else if(P.Support()){var v=function(t){setTimeout(function(){t._call={};var e=P.Stream;e&&(y(),t._call=e._call),P.Stream=t,function(){if(f!=s.C||!n._O){var e="open被取消";return c==s.O?n.close():e="open被中断",o(e),!0}}()||(P.IsOpen()?(e&&n.CLog("发现同时多次调用open",1),S(a,1),i()):o("录音功能无效:无音频流"))},100)},p=function(e){var t=e.name||e.message||e.code+":"+e;n.CLog("请求录音权限错误",1,e),l(t,"无法录音:"+t)},h=t.audioTrackSet||{};h.sampleRate=P.Ctx.sampleRate;var g={audio:h};try{var m=P.Scope[C](g,v,p)}catch(e){n.CLog(C,3,e),g={audio:!0},m=P.Scope[C](g,v,p)}n.CLog(C+"("+JSON.stringify(g)+"),一般默认会降噪和回声消除,移动端可能会降低系统播放音量,请参阅文档中audioTrackSet配置"),m&&m.then&&m.then(v)[L](p)}else l("","此浏览器不支持录音")}},close:function(e){e=e||d;var t=this,r=t._streamStore();t._stop();var n=r.Sync;if(t._O=0,t._O_!=n.O)return t.CLog("close被忽略(因为同时open了多个rec,只有最后一个会真正close)",3),void e();n.C++,y(r),t.CLog("close"),e()},mock:function(e,t){var r=this;return r._stop(),r.isMock=1,r.mockEnvInfo=null,r.buffers=[e],r.recSize=e.length,r[U]=t,r},envCheck:function(e){var t,r=this.set,n="CPU_BE";if(t||P[n]||!I.Int8Array||new Int8Array(new Int32Array([1]).buffer)[0]||(o(n),t="不支持CPU_BE架构"),!t){var a=r.type;this[a+"_envCheck"]?t=this[a+"_envCheck"](e,r):r.takeoffEncodeChunk&&(t=a+"类型"+(this[a]?"":"(未加载编码器)")+"不支持设置takeoffEncodeChunk")}return t||""},envStart:function(e,t){var r=this,n=r.set;r.isMock=e?1:0,r.mockEnvInfo=e,r.buffers=[],r.recSize=0,r.envInLast=0,r.envInFirst=0,r.envInFix=0,r.envInFixTs=[];var a=n[W];if(t<a?n[W]=t:a=0,r[U]=t,r.CLog(U+": "+t+" set."+W+": "+n[W]+(a?" 忽略"+a:""),a?3:0),r.engineCtx=0,r[n.type+"_start"]){var o=r.engineCtx=r[n.type+"_start"](n);o&&(o.pcmDatas=[],o.pcmSize=0)}},envResume:function(){this.envInFixTs=[]},envIn:function(e,t){var a=this,o=a.set,i=a.engineCtx,r=a[U],n=e.length,s=P.PowerLevel(t,n),c=a.buffers,f=c.length;c.push(e);var u=c,l=f,v=Date.now(),p=Math.round(n/r*1e3);a.envInLast=v,1==a.buffers.length&&(a.envInFirst=v-p);var h=a.envInFixTs;h.splice(0,0,{t:v,d:p});for(var g=v,m=0,d=0;d<h.length;d++){var C=h[d];if(3e3<v-C.t){h.length=d;break}g=C.t,m+=C.d}var S=h[1],y=v-g;if(y/3<y-m&&(S&&1e3<y||6<=h.length)){var _=v-S.t-p;if(p/5<_){var b=!o.disableEnvInFix;if(a.CLog("["+v+"]"+(b?"":"未")+"补偿"+_+"ms",3),a.envInFix+=_,b){var k=new Int16Array(_*r/1e3);n+=k.length,c.push(k)}}}var M=a.recSize,x=n,I=M+x;if(a.recSize=I,i){var w=P.SampleData(c,r,o[W],i.chunkInfo);i.chunkInfo=w,I=(M=i.pcmSize)+(x=w.data.length),i.pcmSize=I,c=i.pcmDatas,f=c.length,c.push(w.data),r=w[W]}var L=Math.round(I/r*1e3),A=c.length,T=u.length,D=function(){for(var e=O?0:-x,t=null==c[0],r=f;r<A;r++){var n=c[r];null==n?t=1:(e+=n.length,i&&n.length&&a[o.type+"_encode"](i,n))}if(t&&i)for(r=l,u[0]&&(r=0);r<T;r++)u[r]=null;t&&(e=O?x:0,c[0]=null),i?i.pcmSize+=e:a.recSize+=e},O=0,z="rec.set.onProcess";try{O=o.onProcess(c,s,L,r,f,D)}catch(e){console.error(z+"回调出错是不允许的,需保证不会抛异常",e)}var F=Date.now()-v;if(10<F&&1e3<a.envInFirst-v&&a.CLog(z+"低性能,耗时"+F+"ms",3),!0===O){var R=0;for(d=f;d<A;d++)null==c[d]?R=1:c[d]=new Int16Array(0);R?a.CLog("未进入异步前不能清除buffers",3):i?i.pcmSize-=x:a.recSize-=x}else D()},start:function(){var t=this,r=P.Ctx,e=1;if(t.set.sourceStream?t.Stream||(e=0):P.IsOpen()||(e=0),e)if(t.CLog("开始录音"),t._stop(),t.state=3,t.envStart(null,r[W]),t._SO&&t._SO+1!=t._S)t.CLog("start被中断",3);else{t._SO=0;var n=function(){3==t.state&&(t.state=1,t.resume())};if("suspended"==r.state){var a="AudioContext resume: ";t.CLog(a+"wait..."),r.resume().then(function(){t.CLog(a+r.state),n()})[L](function(e){t.CLog(a+r.state+" 可能无法录音:"+e.message,1,e),n()})}else n()}else t.CLog("未open",1)},pause:function(){var e=this;e.state&&(e.state=2,e.CLog("pause"),delete e._streamStore().Stream._call[e.id])},resume:function(){var e,r=this;if(r.state){r.state=1,r.CLog("resume"),r.envResume();var t=r._streamStore().Stream;t._call[r.id]=function(e,t){1==r.state&&r.envIn(e,t)},(e=t)._na&&e._na(),e._ra&&e._ra()}},_stop:function(e){var t=this,r=t.set;t.isMock||t._S++,t.state&&(t.pause(),t.state=0),!e&&t[r.type+"_stop"]&&(t[r.type+"_stop"](t.engineCtx),t.engineCtx=0)},stop:function(r,t,e){var n,a=this,o=a.set,i=a.envInLast-a.envInFirst,s=i&&a.buffers.length;a.CLog("stop 和start时差"+(i?i+"ms 补偿"+a.envInFix+"ms envIn:"+s+" fps:"+(s/i*1e3).toFixed(1):"-"));var c=function(){a._stop(),e&&a.close()},f=function(e){a.CLog("结束录音失败:"+e,1),t&&t(e),c()},u=function(e,t){if(a.CLog("结束录音 编码花"+(Date.now()-n)+"ms 音频时长"+t+"ms 文件大小"+e.size+"b"),o.takeoffEncodeChunk)a.CLog("启用takeoffEncodeChunk后stop返回的blob长度为0不提供音频数据",3);else if(e.size<Math.max(100,t/2))return void f("生成的"+o.type+"无效");r&&r(e,t),c()};if(!a.isMock){var l=3==a.state;if(!a.state||l)return void f("未开始录音"+(l?",开始录音前无用户交互导致AudioContext未运行":""));a._stop(!0)}var v=a.recSize;if(v)if(a.buffers[0])if(a[o.type]){if(a.isMock){var p=a.envCheck(a.mockEnvInfo||{envName:"mock",canProcess:!1});if(p)return void f("录音错误:"+p)}var h=a.engineCtx;if(a[o.type+"_complete"]&&h){var g=Math.round(h.pcmSize/o[W]*1e3);return n=Date.now(),void a[o.type+"_complete"](h,function(e){u(e,g)},f)}n=Date.now();var m=P.SampleData(a.buffers,a[U],o[W]);o[W]=m[W];var d=m.data;g=Math.round(d.length/o[W]*1e3),a.CLog("采样"+v+"->"+d.length+" 花:"+(Date.now()-n)+"ms"),setTimeout(function(){n=Date.now(),a[o.type](d,function(e){u(e,g)},function(e){f(e)})})}else f("未加载"+o.type+"编码器");else f("音频buffers被释放");else f("未采集到录音")}},I[w]&&(z("重复引入"+w,3),I[w].Destroy()),I[w]=P;var F=function(e,t){t.pos||(t.pos=[0],t.tracks={},t.bytes=[]);var r=t.tracks,n=[t.pos[0]],a=function(){t.pos[0]=n[0]},o=t.bytes.length,i=new Uint8Array(o+e.length);if(i.set(t.bytes),i.set(e,o),t.bytes=i,!t._ht){if(B(i,n),N(i,n),!R(B(i,n),[24,83,128,103]))return;for(B(i,n);n[0]<i.length;){var s=B(i,n),c=N(i,n),f=[0],u=0;if(!c)return;if(R(s,[22,84,174,107])){for(;f[0]<c.length;){var l=B(c,f),v=N(c,f),p=[0],h={channels:0,sampleRate:0};if(R(l,[174]))for(;p[0]<v.length;){var g=B(v,p),m=N(v,p),d=[0];if(R(g,[215])){var C=E(m);h.number=C,r[C]=h}else if(R(g,[131])){var C=E(m);1==C?h.type="video":2==C?(h.type="audio",u||(t.track0=h),h.idx=u++):h.type="Type-"+C}else if(R(g,[134])){for(var S="",y=0;y<m.length;y++)S+=String.fromCharCode(m[y]);h.codec=S}else if(R(g,[225]))for(;d[0]<m.length;){var _=B(m,d),b=N(m,d);if(R(_,[181])){var C=0,k=new Uint8Array(b.reverse()).buffer;4==b.length?C=new Float32Array(k)[0]:8==b.length?C=new Float64Array(k)[0]:z("WebM Track !Float",1,b),h[W]=Math.round(C)}else R(_,[98,100])?h.bitDepth=E(b):R(_,[159])&&(h.channels=E(b))}}}t._ht=1,z("WebM Tracks",r),a();break}}}var M=t.track0;if(M){if(16==M.bitDepth&&/FLOAT/i.test(M.codec)&&(M.bitDepth=32,z("WebM 16改32位",3)),M[W]!=t[W]||32!=M.bitDepth||M.channels<1||!/(\b|_)PCM\b/i.test(M.codec))return t.bytes=[],t.bad||z("WebM Track非预期",3,t),-(t.bad=1);for(var x=[],I=0;n[0]<i.length;){var l=B(i,n),v=N(i,n);if(!v)break;if(R(l,[163])){var w=15&v[0],h=r[w];if(h){if(0===h.idx){for(var L=new Uint8Array(v.length-4),y=4;y<v.length;y++)L[y-4]=v[y];x.push(L),I+=L.length}}else z("WebM !Track"+w,1,r)}a()}if(I){var A=new Uint8Array(i.length-t.pos[0]);A.set(i.subarray(t.pos[0])),t.bytes=A,t.pos[0]=0;for(var L=new Uint8Array(I),y=0,T=0;y<x.length;y++)L.set(x[y],T),T+=x[y].length;var k=new Float32Array(L.buffer);if(1<M.channels){for(var D=[],y=0;y<k.length;)D.push(k[y]),y+=M.channels;k=new Float32Array(D)}return k}}},R=function(e,t){if(!e||e.length!=t.length)return!1;if(1==e.length)return e[0]==t[0];for(var r=0;r<e.length;r++)if(e[r]!=t[r])return!1;return!0},E=function(e){for(var t="",r=0;r<e.length;r++){var n=e[r];t+=(n<16?"0":"")+n.toString(16)}return parseInt(t,16)||0},B=function(e,t,r){var n=t[0];if(!(n>=e.length)){var a=e[n],o=("0000000"+a.toString(2)).substr(-8),i=/^(0*1)(\d*)$/.exec(o);if(i){var s=i[1].length,c=[];if(!(n+s>e.length)){for(var f=0;f<s;f++)c[f]=e[n],n++;return r&&(c[0]=parseInt(i[2]||"0",2)),t[0]=n,c}}}},N=function(e,t){var r=B(e,t,1);if(r){var n=E(r),a=t[0],o=[];if(n<2147483647){if(a+n>e.length)return;for(var i=0;i<n;i++)o[i]=e[a],a++}return t[0]=a,o}};P.TrafficImgUrl="//ia.51.la/go1?id=20469973&pvFlag=1";var o=P.Traffic=function(e){e=e?"/"+w+"/Report/"+e:"";var t=P.TrafficImgUrl;if(t){var r=P.Traffic,n=/^(https?:..[^\/#]*\/?)[^#]*/i.exec(location.href)||[],a=n[1]||"http://file/",o=(n[0]||a)+e;if(0==t.indexOf("//")&&(t=/^https:/i.test(o)?"https:"+t:"http:"+t),e&&(t=t+"&cu="+encodeURIComponent(a+e)),!r[o]){r[o]=1;var i=new Image;i.src=t,z("Traffic Analysis Image: "+(e||w+".TrafficImgUrl="+P.TrafficImgUrl))}}}}(window),"function"==typeof define&&define.amd&&define(function(){return Recorder}),"object"==typeof module&&module.exports&&(module.exports=Recorder); |