支持在大部分已实现getUserMedia的移动端、PC端浏览器麦克风录音、实时处理,主要包括:Chrome、Firefox、Safari、IOS 14.3+、Android WebView、腾讯Android X5内核(QQ、微信)、大部分2021年后更新的Android手机自带浏览器;不支持:UC系内核(典型的支付宝),大部分未更新的老旧国产手机自带浏览器,低版本IOS(11.0-14.2)上除Safari外的其他任何形式的浏览器(含PWA、WebClip、任何App内网页)。
支持对任意MediaStream进行音频录制、实时处理,包括:getUserMedia返回的流、WebRTC中的remote流、audio、video标签的captureStream方法返回的流、自己创建的流 等等。
提供多个扩展功能支持:拥有丰富的音频可视化、变速变调处理、音频流播放等;搭配上强大的实时处理支持,可用于各种网页应用:从简单的录音,到复杂的实时语音识别(ASR),甚至音频相关的游戏,都能从容应对。
音频文件的播放:可直接使用常规的Audio HTML标签来播放完整的音频文件,参考文档下面的【快速使用】部分,有播放例子;上传了的录音直接将音频链接赋值给audio.src即可播放;本地的blob音频文件可通过URL.createObjectURL来生成本地链接赋值给audio.src即可播放,或者将blob对象直接赋值给audio.srcObject(兼容性没有src高)。实时的音频片段文件播放,可以使用本库自带的BufferStreamPlayer扩展来播放,简单高效,或者采用别的途径播放。
录音默认输出mp3格式,另外可选wav、pcm格式;有限支持ogg(beta)、webm(beta)、amr(beta)格式;支持任意格式扩展(前提有相应编码器)。
mp3默认16kbps的比特率,2kb每秒的录音大小,音质还可以(如果使用8kbps可达到1kb每秒,不过音质太渣)。主要用于语音录制,双声道语音没有意义,特意仅对单声道进行支持。mp3、wav、pcm格式支持边录边转码,录音结束时转码速度极快,支持实时转码成小片段文件和实时传输,demo中已实现一个语音通话聊天,下面有介绍;其他格式录音结束时可能需要花费比较长的时间进行转码。
mp3使用lamejs编码(CBR),压缩后的recorder.mp3.min.js文件150kb左右(开启gzip后54kb)。如果对录音文件大小没有特别要求,可以仅仅使用录音核心+wav编码器(raw pcm format录音文件超大),压缩后的recorder.wav.min.js不足5kb。录音得到的mp3(CBR)、wav(PCM),均可简单拼接小的二进制录音片段文件来生成长的音频文件,具体参考下面这两种编码器的详细介绍。
你可以通过阅读和运行QuickStart.html文件来快速入门学习,直接将QuickStart.htmlcopy到你的(https、localhost)网站中,无需其他文件,就能正常开始测试了;注意:需要在https、localhost等安全环境下才能进行录音。
【1】加载框架
方式一:使用script标签引入
在需要录音功能的页面引入压缩好的recorder.xxx.min.js文件即可,JsDelivr CDN
<script src="recorder.mp3.min.js"></script> <!--已包含recorder-core和mp3格式支持, CDN: https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/recorder.mp3.min.js--> 或者直接使用源码(src内的为源码、dist内的为压缩后的),可以引用src目录中的recorder-core.js+相应类型的实现文件,比如要mp3录音: <script src="src/recorder-core.js"></script> <!--必须引入的录音核心,CDN: https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/dist/recorder-core.js--> <script src="src/engine/mp3.js"></script> <!--相应格式支持文件;如果需要多个格式支持,把这些格式的编码引擎js文件放到后面统统加载进来即可--> <script src="src/engine/mp3-engine.js"></script> <!--如果此格式有额外的编码引擎的话,也要加上--> <script src="src/extensions/waveview.js"></script> <!--可选的扩展支持项-->
方式二:通过import/require引入
通过 npm/cnpm 进行安装 npm install recorder-core ,如果直接clone的源码下面文件路径调整一下即可
//必须引入的核心,换成require也是一样的。注意:recorder-core会自动往window下挂载名称为Recorder对象,全局可调用window.Recorder,也许可自行调整相关源码清除全局污染 import Recorder from 'recorder-core' //需要使用到的音频格式编码引擎的js文件统统加载进来 import 'recorder-core/src/engine/mp3' import 'recorder-core/src/engine/mp3-engine' //以上三个也可以合并使用压缩好的recorder.xxx.min.js //比如 import Recorder from 'recorder-core/recorder.mp3.min' //已包含recorder-core和mp3格式支持 //可选的扩展支持项 import 'recorder-core/src/extensions/waveview'
【2】调用录音,播放结果
这里假设只录3秒,录完后立即播放,在线编辑运行此代码>>
//简单控制台直接测试方法:在任意(无CSP限制)页面内加载Recorder,加载成功后再执行一次本代码立即会有效果,import("https://xiangyuecn.gitee.io/recorder/recorder.mp3.min.js").then(function(s){console.log("import ok")}).catch(function(e){console.error("import fail",e)}) var rec; /**调用open打开录音请求好录音权限**/ var recOpen=function(success){//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了 rec=Recorder({ //本配置参数请参考下面的文档,有详细介绍 type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎 ,onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd){ //录音实时回调,大约1秒调用12次本回调 //可实时绘制波形(extensions目录内的waveview.js、wavesurfer.view.js、frequency.histogram.view.js扩展功能) //可利用extensions/sonic.js扩展实时变速变调,此扩展计算量巨大,onProcess需要返回true开启异步模式 //可实时上传(发送)数据,配合Recorder.SampleData方法,将buffers中的新数据连续的转换成pcm上传,或使用mock方法将新数据连续的转码成其他格式上传,可以参考文档里面的:Demo片段列表 -> 实时转码并上传-通用版;基于本功能可以做到:实时转发数据、实时保存数据、实时语音识别(ASR)等 } }); //var dialog=createDelayDialog(); 我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码 rec.open(function(){//打开麦克风授权获得相关资源 //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消 //rec.start() 此处可以立即开始录音,但不建议这样编写,因为open是一个延迟漫长的操作,通过两次用户操作来分别调用open和start是推荐的最佳流程 success&&success(); },function(msg,isUserNotAllow){//用户拒绝未授权或不支持 //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消 console.log((isUserNotAllow?"UserNotAllow,":"")+"无法录音:"+msg); }); }; /**开始录音**/ function recStart(){//打开了录音后才能进行start、stop调用 rec.start(); }; /**结束录音**/ function recStop(){ rec.stop(function(blob,duration){ console.log(blob,(window.URL||webkitURL).createObjectURL(blob),"时长:"+duration+"ms"); rec.close();//释放录音资源,当然可以不释放,后面可以连续调用start;但不释放时系统或浏览器会一直提示在录音,最佳操作是录完就close掉 rec=null; //已经拿到blob文件对象想干嘛就干嘛:立即播放、上传 /*** 【立即播放例子】 ***/ var audio=document.createElement("audio"); audio.controls=true; document.body.appendChild(audio); //简单利用URL生成播放地址,注意不用了时需要revokeObjectURL,否则霸占内存 audio.src=(window.URL||webkitURL).createObjectURL(blob); audio.play(); },function(msg){ console.log("录音失败:"+msg); rec.close();//可以通过stop方法的第3个参数来自动调用close rec=null; }); }; //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调 /*伪代码: function createDelayDialog(){ if(Is Mobile){//只针对移动端 return new Alert Dialog Component .Message("录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~") .Button("忽略") .OnClick(function(){//明确是用户点击的按钮,此时代表浏览器没有发起任何权限请求 //此处执行fail逻辑 console.log("无法录音:权限请求被忽略"); }) .OnCancel(NOOP)//自动取消的对话框不需要任何处理 .Delay(8000); //延迟8秒显示,这么久还没有操作基本可以判定浏览器有毛病 }; }; */ //这里假设立即运行,只录3秒,录完后立即播放,本段代码copy到控制台内可直接运行 recOpen(function(){ recStart(); setTimeout(recStop,3000); });
【附】录音上传示例
var TestApi="/test_request";//用来在控制台network中能看到请求数据,测试的请求结果无关紧要 var rec=Recorder();rec.open(function(){rec.start();setTimeout(function(){rec.stop(function(blob,duration){ //-----↓↓↓以下才是主要代码↓↓↓------- //本例子假设使用jQuery封装的请求方式,实际使用中自行调整为自己的请求方式 //录音结束时拿到了blob文件对象,可以用FileReader读取出内容,或者用FormData上传 var api=TestApi; /***方式一:将blob文件转成base64纯文本编码,使用普通application/x-www-form-urlencoded表单上传***/ var reader=new FileReader(); reader.onloadend=function(){ $.ajax({ url:api //上传接口地址 ,type:"POST" ,data:{ mime:blob.type //告诉后端,这个录音是什么格式的,可能前后端都固定的mp3可以不用写 ,upfile_b64:(/.+;\s*base64\s*,\s*(.+)$/i.exec(reader.result)||[])[1] //录音文件内容,后端进行base64解码成二进制 //...其他表单参数 } ,success:function(v){ console.log("上传成功",v); } ,error:function(s){ console.error("上传失败",s); } }); }; reader.readAsDataURL(blob); /***方式二:使用FormData用multipart/form-data表单上传文件***/ var form=new FormData(); form.append("upfile",blob,"recorder.mp3"); //和普通form表单并无二致,后端接收到upfile参数的文件,文件名为recorder.mp3 //...其他表单参数 $.ajax({ url:api //上传接口地址 ,type:"POST" ,contentType:false //让xhr自动处理Content-Type header,multipart/form-data需要生成随机的boundary ,processData:false //不要处理data,让xhr自动处理 ,data:form ,success:function(v){ console.log("上传成功",v); } ,error:function(s){ console.error("上传失败",s); } }); //-----↑↑↑以上才是主要代码↑↑↑------- },function(msg){console.log("录音失败:"+msg);});},3000);},function(msg){console.log("无法录音:"+msg);});