6 lines
16 KiB
JavaScript
6 lines
16 KiB
JavaScript
/*
|
||
录音
|
||
https://github.com/xiangyuecn/Recorder
|
||
src: recorder-core.js
|
||
*/
|
||
!function(x){"use strict";var d=function(){},U=function(e){return new t(e)};U.LM="2022-08-06 20:51";var A="Recorder",S="getUserMedia",P="srcSampleRate",E="sampleRate";U.IsOpen=function(){var e=U.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},U.BufferSize=4096,U.Destroy=function(){for(var e in z(A+" Destroy"),y(),r)r[e]()};var r={};U.BindDestroy=function(e,t){r[e]=t},U.Support=function(){var e=x.AudioContext;if(e||(e=x.webkitAudioContext),!e)return!1;var t=navigator.mediaDevices||{};return t[S]||(t=navigator)[S]||(t[S]=t.webkitGetUserMedia||t.mozGetUserMedia||t.msGetUserMedia),!!t[S]&&(U.Scope=t,U.Ctx&&"closed"!=U.Ctx.state||(U.Ctx=new e,U.BindDestroy("Ctx",function(){var e=U.Ctx;e&&e.close&&(e.close(),U.Ctx=0)})),!0)};var L="ConnectEnableWebM";U[L]=!0;var T="ConnectEnableWorklet";U[T]=!1;var _=function(e,c){var f,i,u,l=e.BufferSize||U.BufferSize,v=U.Ctx,p=e.Stream,s=function(e){var t=p._m=v.createMediaStreamSource(p),r=v.destination,n="createMediaStreamDestination";v[n]&&(r=v[n]()),t.connect(e),e.connect(r)},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",S="audioWorklet",_=A+" "+S,y="RecProc",C="MediaRecorder",b=C+".WebM.PCM",k=v.createScriptProcessor||v.createJavaScriptNode,M="。由于"+S+"内部1秒375次回调,在移动端可能会有性能问题导致回调丢失录音变短,PC端无影响,暂不建议开启"+S+"。",I=function(){i=p.isWorklet=!1,D(p),z("Connect采用老的"+d+","+(U[T]?"但已":"可")+"设置"+A+"."+T+"=true尝试启用"+S+h+M,3);var e=p._p=k.call(v,l,1,1);s(e);var t="_D220626",r=U[t];r&&z("Use "+A+"."+t,3),e.onaudioprocess=function(e){var t=e.inputBuffer.getChannelData(0);r?(t=new Float32Array(t),setTimeout(function(){m(t)})):m(t)}},w=function(){f=p.isWebM=!1,O(p),i=p.isWorklet=!k||U[T];var t=x.AudioWorkletNode;if(i&&v[S]&&t){var n=function(){return i&&p._na},a=p._na=function(){""!==u&&(clearTimeout(u),u=setTimeout(function(){u=0,n()&&(z(S+"未返回任何音频,恢复使用"+d,3),k&&I())},500))},o=function(){if(n()){var e=p._n=new t(v,y,{processorOptions:{bufferSize:l}});s(e),e.port.onmessage=function(e){u&&(clearTimeout(u),u=""),n()?m(e.data.val):i||z(S+"多余回调",3)},z("Connect采用"+S+",设置"+A+"."+T+"=false可恢复老式"+d+h+M,3)}};v.resume()[g&&"finally"](function(){if(n())if(v[y])o();else{var e,t,r=(t="class "+y+" extends AudioWorkletProcessor{",t+="constructor "+(e=function(e){return e.toString().replace(/^function|DEL_/g,"").replace(/\$RA/g,_)})(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,console.log("$RA kill call"))},console.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+='}try{registerProcessor("'+y+'", '+y+')}catch(e){console.error("'+_+'注册失败",e)}',"data:text/javascript;base64,"+btoa(unescape(encodeURIComponent(t))));v[S].addModule(r).then(function(e){n()&&(v[y]=1,o(),u&&a())})[g&&"catch"](function(e){z(S+".addModule失败",1,e),n()&&I()})}})}else I()};!function(){var e=x[C],t="ondataavailable",r="audio/webm; codecs=pcm";f=p.isWebM=U[L];var n=e&&t in e.prototype&&e.isTypeSupported(r);if(h=n?"":"(此浏览器不支持"+b+")",!c||!f||!n)return w();var a=function(){return f&&p._ra},o=(p._ra=function(){""!==u&&(clearTimeout(u),u=setTimeout(function(){a()&&(z(C+"未返回任何音频,降级使用"+S,3),w())},500))},Object.assign({mimeType:r},U.ConnectWebMOptions)),i=p._r=new e(p,o),s=p._rd={sampleRate:v[E]};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 w();u&&(clearTimeout(u),u=""),m(e)}else f||z(C+"多余回调",3)},t.readAsArrayBuffer(e.data)},i.start(~~(l/48)),z("Connect采用"+b+",设置"+A+"."+L+"=false可恢复使用"+S+"或老式"+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||U)==U,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};U.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),S=Math.ceil(l),_=l-d,y=g[d],C=S<m?g[S]:(e[o+1]||[y])[0]||0;p[h]=y+(C-y)*_,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}},U.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)))))};var z=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+" "+A+(a?":"+a:"")+"]"+e],i=arguments,s=x.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)},u=!0;try{u=!console.log.apply}catch(e){}U.CLog=z;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}}U.Sync={O:9,C:9},U.prototype=t.prototype={CLog:z,_streamStore:function(){return this.set.sourceStream?this:U},open:function(e,r){var n=this,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 t=n.envCheck({envName:"H5",canProcess:!0});if(t)o("不能录音:"+t);else if(n.set.sourceStream){if(!U.Support())return void o("不支持此浏览器从流中获取录音");y(a),n.Stream=n.set.sourceStream,n.Stream._call={};try{_(a)}catch(e){return void o("从流中打开录音失败:"+e.message)}i()}else{var u=function(e,t){try{x.top.a}catch(e){return void o('无权录音(跨域,请尝试给iframe添加麦克风访问策略,如allow="camera;microphone")')}/Permission|Allow/i.test(e)?o("用户拒绝了录音权限",!0):!1===x.isSecureContext?o("浏览器禁止不安全页面录音,可开启https解决"):/Found/i.test(e)?o(t+",无可用麦克风"):o(t)};if(U.IsOpen())i();else if(U.Support()){var l=function(t){setTimeout(function(){t._call={};var e=U.Stream;e&&(y(),t._call=e._call),U.Stream=t,function(){if(f!=s.C||!n._O){var e="open被取消";return c==s.O?n.close():e="open被中断",o(e),!0}}()||(U.IsOpen()?(e&&n.CLog("发现同时多次调用open",1),_(a,1),i()):o("录音功能无效:无音频流"))},100)},v=function(e){var t=e.name||e.message||e.code+":"+e;n.CLog("请求录音权限错误",1,e),u(t,"无法录音:"+t)},p={noiseSuppression:!1,echoCancellation:!1},h=n.set.audioTrackSet;for(var g in h)p[g]=h[g];p.sampleRate=U.Ctx.sampleRate;try{var m=U.Scope[S]({audio:p},l,v)}catch(e){n.CLog(S,3,e),m=U.Scope[S]({audio:!0},l,v)}m&&m.then&&m.then(l)[e&&"catch"](v)}else u("","此浏览器不支持录音")}},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[P]=t,r},envCheck:function(e){var t,r=this.set,n="CPU_BE";if(t||U[n]||!x.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[E];if(t<a?n[E]=t:a=0,r[P]=t,r.CLog(P+": "+t+" set."+E+": "+n[E]+(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[P],n=e.length,s=U.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 S=h[d];if(3e3<v-S.t){h.length=d;break}g=S.t,m+=S.d}var _=h[1],y=v-g;if(y/3<y-m&&(_&&1e3<y||6<=h.length)){var C=v-_.t-p;if(p/5<C){var b=!o.disableEnvInFix;if(a.CLog("["+v+"]"+(b?"":"未")+"补偿"+C+"ms",3),a.envInFix+=C,b){var k=new Int16Array(C*r/1e3);n+=k.length,c.push(k)}}}var M=a.recSize,I=n,w=M+I;if(a.recSize=w,i){var x=U.SampleData(c,r,o[E],i.chunkInfo);i.chunkInfo=x,w=(M=i.pcmSize)+(I=x.data.length),i.pcmSize=w,c=i.pcmDatas,f=c.length,c.push(x.data),r=x[E]}var A=Math.round(w/r*1e3),L=c.length,T=u.length,D=function(){for(var e=O?0:-I,t=null==c[0],r=f;r<L;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?I:0,c[0]=null),i?i.pcmSize+=e:a.recSize+=e},O=0,z="rec.set.onProcess";try{O=o.onProcess(c,s,A,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<L;d++)null==c[d]?R=1:c[d]=new Int16Array(0);R?a.CLog("未进入异步前不能清除buffers",3):i?i.pcmSize-=I:a.recSize-=I}else D()},start:function(){var e=this,t=U.Ctx,r=1;if(e.set.sourceStream?e.Stream||(r=0):U.IsOpen()||(r=0),r)if(e.CLog("开始录音"),e._stop(),e.state=3,e.envStart(null,t[E]),e._SO&&e._SO+1!=e._S)e.CLog("start被中断",3);else{e._SO=0;var n=function(){3==e.state&&(e.state=1,e.resume())};"suspended"==t.state?(e.CLog("wait ctx resume..."),t.resume().then(function(){e.CLog("ctx resume"),n()})):n()}else e.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[E]*1e3);return n=Date.now(),void a[o.type+"_complete"](h,function(e){u(e,g)},f)}n=Date.now();var m=U.SampleData(a.buffers,a[P],o[E]);o[E]=m[E];var d=m.data;g=Math.round(d.length/o[E]*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("未采集到录音")}},x[A]&&(z("重复引入"+A,3),x[A].Destroy()),x[A]=U;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 S=W(m);h.number=S,r[S]=h}else if(R(g,[131])){var S=W(m);1==S?h.type="video":2==S?(h.type="audio",u||(t.track0=h),h.idx=u++):h.type="Type-"+S}else if(R(g,[134])){for(var _="",y=0;y<m.length;y++)_+=String.fromCharCode(m[y]);h.codec=_}else if(R(g,[225]))for(;d[0]<m.length;){var C=B(m,d),b=N(m,d);if(R(C,[181])){var S=0,k=new Uint8Array(b.reverse()).buffer;4==b.length?S=new Float32Array(k)[0]:8==b.length?S=new Float64Array(k)[0]:z("WebM Track !Float",1,b),h[E]=Math.round(S)}else R(C,[98,100])?h.bitDepth=W(b):R(C,[159])&&(h.channels=W(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[E]!=t[E]||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 I=[],w=0;n[0]<i.length;){var l=B(i,n),v=N(i,n);if(!v)break;if(R(l,[163])){var x=15&v[0],h=r[x];if(0===h.idx){for(var A=new Uint8Array(v.length-4),y=4;y<v.length;y++)A[y-4]=v[y];I.push(A),w+=A.length}}a()}if(w){var L=new Uint8Array(i.length-t.pos[0]);L.set(i.subarray(t.pos[0])),t.bytes=L,t.pos[0]=0;for(var A=new Uint8Array(w),y=0,T=0;y<I.length;y++)A.set(I[y],T),T+=I[y].length;var k=new Float32Array(A.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},W=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=W(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}};U.TrafficImgUrl="";var o=U.Traffic=function(e){e=e?"/"+A+"/Report/"+e:"";var t=U.TrafficImgUrl;if(t){var r=U.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||A+".TrafficImgUrl="+U.TrafficImgUrl))}}}}(window),"function"==typeof define&&define.amd&&define(function(){return Recorder}),"object"==typeof module&&module.exports&&(module.exports=Recorder); |