UNPKG

recorder-core-rlian

Version:

Recorder库:html5 js 录音 mp3 wav ogg webm amr 格式,支持pc和Android、ios部分浏览器、和Hybrid App(提供Android IOS App源码),微信也是支持的,提供H5版语音通话聊天示例 和DTMF编解码

1,121 lines (783 loc) 118 kB
# Recorder:recorder-core 用于html5录音 GitHub: [https://github.com/xiangyuecn/Recorder](https://github.com/xiangyuecn/Recorder),详细使用方法和支持请参考Recorder的GitHub仓库。npm recorder这个名字已被使用,因此在Recorder基础上增加后缀-core,就命名为recorder-core,和Recorder核心文件同名。 [​](?本文件为动态生成文件,请勿直接编辑,需要编辑请修改npm-home中的README) [​](?本文件为动态生成文件,请勿直接编辑,需要编辑请修改npm-home中的README) [​](?本文件为动态生成文件,请勿直接编辑,需要编辑请修改npm-home中的README) 支持在大部分已实现`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方法返回的流`、`自己创建的流` 等等。 [​](?) **Recorder H5** : [ [H5在线测试](https://xiangyuecn.gitee.io/recorder/) ] [ [H5 QuickStart](https://xiangyuecn.gitee.io/recorder/QuickStart.html) ] [ [H5 vue](https://xiangyuecn.gitee.io/recorder/assets/demo-vue) ] **工具集** : [ [Recorder代码运行和静态分发](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8C%E5%92%8C%E9%9D%99%E6%80%81%E5%88%86%E5%8F%91Runtime.html) ] [ [裸(RAW、WAV)PCM转WAV播放测试和转码](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E8%A3%B8PCM%E8%BD%ACWAV%E6%92%AD%E6%94%BE%E6%B5%8B%E8%AF%95.html) ] [ [无用户操作测试](https://xiangyuecn.gitee.io/recorder/assets/ztest_no_user_operation.html) ] [ [Can I Use查看浏览器支持情况](https://caniuse.com/#search=getUserMedia) ] **RecordApp**[即将废弃] : [ [RecordApp测试](https://jiebian.life/web/h5/github/recordapp.aspx) ] [ [App QuickStart](https://jiebian.life/web/h5/github/recordapp.aspx?path=/app-support-sample/QuickStart.html) ] [ [App vue](https://jiebian.life/web/h5/github/recordapp.aspx?path=/assets/demo-vue/recordapp.html) ] [ [Android、IOS App源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample) ] > [<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/demo.png" width="100px">](https://xiangyuecn.gitee.io/recorder/) 扫一扫在线测试,`github.io`可访问性太不尽人意,所以使用`gitee.io`镜像库的速度快多了。 [​](?) 录音默认输出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),均可简单拼接小的二进制录音片段文件来生成长的音频文件,具体参考下面这两种编码器的详细介绍。 > 如需在Hybrid App内使用(支持IOS、Android),或提供低版本IOS微信的支持,请参阅[app-support-sample](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample)目录。 > > *低版本IOS兼容、老旧国产手机自带浏览器上的使用限制等问题和兼容请参阅下面的知识库部分;打开录音后对音频播放的影响、录音中途来电话等问题也参阅下面的知识库。* [​](?) ### Demo片段列表 1. [【Demo库】【格式转换】-mp3格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.mp32other) 2. [【Demo库】【格式转换】-wav格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.wav2other) 3. [【Demo库】【格式转换】-amr格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.amr2other) 4. [【教程】【音频流】实时转码并上传-通用版](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.encode_transfer) 5. [【教程】【音频流】实时转码并上传-mp3专版](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.encode_transfer_mp3) 6. [【教程】【音频流】实时解码播放音频片段](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.decode_buffer_stream_player) 7. [【教程】实时录制处理audio、video标签的captureStream流](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.source_stream.capture_stream) 8. [【Demo库】【文件合并】-mp3多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.mp3_merge) 9. [【Demo库】【文件合并】-wav多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.wav_merge) 10. [【教程】实时多路音频混音](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.mix_multiple) 11. [【教程】变速变调音频转换](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform) 12. [【教程】DTMF(电话拨号按键信号)解码、编码](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.dtmf.decode_and_encode) 13. [【Demo库】PCM采样率提升](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.samplerate.raise) 14. [【测试】音频可视化相关扩展测试](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization) ### App Demo Android Demo App : [下载APK](https://gitee.com/xiangyuecn/Recorder/blob/master/app-support-sample/demo_android/app-debug.apk.zip)(40kb,删除.zip后缀, [源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_android)) IOS Demo App :[下载源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_ios) 自行编译 ### 小程序WebView 使用到这个库用于祝福语音的录制,已开通网页版和微信小程序版。专门针对IOS的微信中进行了兼容处理,IOS上微信环境中调用的微信的api(小程序、公众号api)。小程序地址:[<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/jiebian.life-xcx.png" width="100px">](https://jiebian.life/t/a);网页地址:[<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/jiebian.life-web.png" width="100px">](https://jiebian.life/t/a) > 如果你的项目用到了这个库也想展示到这里,可以发个isuse,注明使用介绍和访问方式,我们收录在这里。 [​](?) [​](?) [​](?) [​](?) [​](?) [​](?) <p align="center"><a href="https://github.com/xiangyuecn/Recorder"><img width="100" src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/icon.png" alt="Recorder logo"></a></p> <p align="center"> Basic: <a title="Stars" href="https://github.com/xiangyuecn/Recorder"><img src="https://img.shields.io/github/stars/xiangyuecn/Recorder?color=0b1&logo=github" alt="Stars"></a> <a title="Forks" href="https://github.com/xiangyuecn/Recorder"><img src="https://img.shields.io/github/forks/xiangyuecn/Recorder?color=0b1&logo=github" alt="Forks"></a> <a title="npm Version" href="https://www.npmjs.com/package/recorder-core"><img src="https://img.shields.io/npm/v/recorder-core?color=0b1&logo=npm" alt="npm Version"></a> <a title="License" href="https://github.com/xiangyuecn/Recorder/blob/master/LICENSE"><img src="https://img.shields.io/github/license/xiangyuecn/Recorder?color=0b1&logo=github" alt="License"></a> </p> <p align="center"> Traffic: <a title="npm Downloads" href="https://www.npmjs.com/package/recorder-core"><img src="https://img.shields.io/npm/dt/recorder-core?color=f60&logo=npm" alt="npm Downloads"></a> <a title="cnpm" href="https://npm.taobao.org/package/recorder-core"><img src="https://img.shields.io/badge/cnpm-available-1690CD" alt="cnpm"></a><a title="cnpm" href="https://npm.taobao.org/package/recorder-core"><img src="https://npm.taobao.org/badge/d/recorder-core.svg" alt="cnpm"></a> <a title="JsDelivr CDN" href="https://www.jsdelivr.com/package/gh/xiangyuecn/Recorder"><img src="https://data.jsdelivr.com/v1/package/gh/xiangyuecn/Recorder/badge" alt="JsDelivr CDN"></a> <a title="51LA" href="https://www.51.la/?20469973"><img src="https://img.shields.io/badge/51LA-available-0b1" alt="cnpm"></a> </p> # 如何使用 **注意:[需要在https等安全环境下才能进行录音](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Privacy_and_security)** ## 【1】通过npm安装 ``` npm install recorder-core ``` ## 【2】引入Recorder库 **方式一**:通过import/require引入 ``` javascript //必须引入的核心,换成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' ``` **方式二**:使用script标签引入 这种方式和GitHub上的代码使用没有差别,请阅读[GitHub仓库](https://github.com/xiangyuecn/Recorder)获得更详细的使用文档。 ``` html <script src="你项目中的路径/src/recorder-core.js"></script> <!--必须引入的录音核心--> <script src="你项目中的路径/src/engine/mp3.js"></script> <!--相应格式支持文件--> <script src="你项目中的路径/src/engine/mp3-engine.js"></script> <!--如果此格式有额外的编码引擎的话,也要加上--> <script src="你项目中的路径/src/extensions/waveview.js"></script> <!--可选的扩展支持项--> ``` 或者在需要录音功能的页面引入压缩好的recorder.xxx.min.js文件减小代码体积 ``` html <script src="你项目中的路径/recorder.mp3.min.js"></script> <!--已包含recorder-core和mp3格式支持--> ``` ## 【3】调用录音 这里假设只录3秒,录完后立即播放,[在线编辑运行此代码>>](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8C%E5%92%8C%E9%9D%99%E6%80%81%E5%88%86%E5%8F%91Runtime.html?idf=self_base_demo) ``` javascript //简单控制台直接测试方法:在任意(无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扩展实时绘制波形 //可利用extensions/sonic.js扩展实时变速变调,此扩展计算量巨大,onProcess需要返回true开启异步模式 } }); //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); }); ``` [​](?) ## 【附】录音上传示例 ``` javascript 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);}); ``` ## WaveView的调用方式 引入`src/extensions/waveview.js`,再通过Recorder.WaveView调用即可,录音时动态显示波形,详细的使用请参考下面详细的README。 ``` javascript var wave; var rec=Recorder({ onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate){ wave.input(buffers[buffers.length-1],powerLevel,bufferSampleRate);//输入音频数据,更新显示波形 } }); rec.open(function(){ wave=Recorder.WaveView({elem:".elem"}); //创建wave对象,写这里面浏览器妥妥的 rec.start(); }); ``` 【附】部分扩展使用效果图([在线运行观看](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization)): ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_wave.gif) ## WaveSurferView的调用方式 引入`src/extensions/wavesurfer.view.js`,再通过Recorder.WaveSurferView调用即可,录音时动态显示波形,详细的使用请参考下面详细的README。 ## FrequencyHistogramView的调用方式 引入`src/extensions/frequency.histogram.view.js`+`lib.fft.js`,再通过Recorder.FrequencyHistogramView调用即可,音频可视化频率直方图显示,详细的使用请参考下面详细的README。 ## Sonic的调用方式 引入`src/extensions/sonic.js`,再通过Recorder.Sonic调用即可,音频变速变调转换,详细的使用请参考下面详细的README。 ## DTMF的调用方式 引入`src/extensions/dtmf.decode.js`+`lib.fft.js`:DTMF(电话拨号按键信号)解码器,解码得到按键值;`src/extensions/dtmf.encode.js`:编码生成器,生成按键对应的音频PCM信号;详细的使用请参考下面详细的README。 ## RecordApp的调用方式 **方式一**:通过import/require引入 ``` javascript //可选的独立配置文件,提供这些文件时可免去修改app.js源码。这些配置文件需要自己编写,参考https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample 目录内的这两个演示用的配置文件代码。 //你可以直接copy /app-support-sample 目录内的两个演示配置文件改改后,就能正常使用了 import '你的配置文件目录/native-config.js' //可选开启native支持的相关配置 import '你的配置文件目录/ios-weixin-config.js' //可选开启ios weixin支持的相关配置 /********加载RecordApp需要用到的支持文件*********/ //必须引入的app核心文件,换成require也是一样的。注意:app.js会自动往window下挂载名称为RecordApp对象,全局可调用window.RecordApp,也许可自行调整相关源码清除全局污染 import RecordApp from 'recorder-core/src/app-support/app' //可选开启Native支持,需要引入此文件 import 'recorder-core/src/app-support/app-native-support' //可选开启IOS上微信录音支持,需要引入此文件 import 'recorder-core/src/app-support/app-ios-weixin-support' /*********加载Recorder需要的文件***********/ //必须引入的核心,所有需要的文件都应当引入,引入后会检测到组件已自动加载 //不引入也可以,app.js会去用script动态加载,应确保app.js内BaseFolder目录的正确性(参阅RecordAppBaseFolder),否则会导致404 js加载失败 import 'recorder-core' //需要使用到的音频格式编码引擎的js文件统统加载进来 import 'recorder-core/src/engine/mp3' import 'recorder-core/src/engine/mp3-engine' //由于大部分情况下ios-weixin的支持需要用到amr解码器,应当把amr引擎也加载进来 import 'recorder-core/src/engine/beta-amr' import 'recorder-core/src/engine/beta-amr-engine' import 'recorder-core/src/engine/wav' //amr依赖了wav引擎 //可选的扩展支持项 import 'recorder-core/src/extensions/waveview' ``` **方式二**:使用script标签引入 这种方式和GitHub上的代码使用没有差别,请阅读[GitHub仓库内RecordApp](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample)获得更详细的使用文档。 ``` html <!-- 可选的独立配置文件,参考上面import的解释 --> <script src="你的配置文件目录/native-config.js"></script> <script src="你的配置文件目录/ios-weixin-config.js"></script> <!-- 在需要录音功能的页面引入`app-support/app.js`文件即可。 app.js会自动加载实现文件、Recorder核心、编码引擎,应确保app.js内BaseFolder目录的正确性(参阅RecordAppBaseFolder)。 (如何避免自动加载:使用时可以把所有支持文件全部手动引入,或者压缩时可以把所有支持文件压缩到一起,会检测到组件已加载,就不会再进行自动加载;会自动默认加载哪些文件,请查阅app.js内所有Platform的paths配置) (**注意:需要在https等安全环境下才能进行录音**) --> <script src="你项目中的路径/src/app-support/app.js"></script> <!-- 可选的扩展支持项的引入 方法一:我们可以先直接引入Recorder核心,然后再引入扩展支持,这样会自动检测到组件已加载 <script src="你项目中的路径/src/recorder-core.js"></script> <script src="你项目中的路径/src/extensions/waveview.js"></script> 方法二:通过注入到Default实现的paths中让RecordApp去自动加载 <script> RecordApp.Platforms.Default.Config.paths.push({ url:"你项目中的路径/src/extensions/waveview.js" ,lazyBeforeStart:1 //开启延迟加载,在Start调用前任何时间进行加载都行 ,check:function(){return !Recorder.WaveView} //检测是否需要加载 }); </script> 方法三:直接修改app.js源码中RecordApp.Platforms.Default.Config.paths,添加需要加载的js --> ``` ### 调用录音 然后使用,假设立即运行,只录3秒,会自动根据环境使用Native录音、微信JsSDK录音、H5录音 ``` javascript //var dialog=createDelayDialog(); 开启可选的弹框伪代码,需先于权限请求前执行,因为回调不确定是同步还是异步的 //请求录音权限 RecordApp.RequestPermission(function(){ //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消 RecordApp.Start({//如果需要的组件还在延迟加载,Start调用会等待这些组件加载完成后才会调起底层平台的Start方法,可通绑定RecordApp.Current.OnLazyReady事件来确定是否已完成组件的加载,或者设置RecordApp.UseLazyLoad=false来关闭延迟加载(会阻塞Install导致RequestPermission变慢) type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把支持文件到Platforms.Default内注册 ,onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd){ //如果当前环境支持实时回调(RecordApp.Current.CanProcess()),收到录音数据时就会实时调用本回调方法 //可利用extensions/waveview.js扩展实时绘制波形 //可利用extensions/sonic.js扩展实时变速变调,此扩展计算量巨大,onProcess需要返回true开启异步模式 } },function(){ setTimeout(function(){ RecordApp.Stop(function(blob,duration){//到达指定条件停止录音和清理资源 console.log(blob,(window.URL||webkitURL).createObjectURL(blob),"时长:"+duration+"ms"); //已经拿到blob文件对象想干嘛就干嘛:立即播放、上传 },function(msg){ console.log("录音失败:"+msg); }); },3000); },function(msg){ console.log("开始录音失败:"+msg); }); },function(msg,isUserNotAllow){//用户拒绝未授权或不支持 //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消 console.log((isUserNotAllow?"UserNotAllow,":"")+"无法录音:"+msg); }); //我们可以选择性的弹一个对话框:为了防止当移动端浏览器使用Recorder H5录音时存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调 /*伪代码: function createDelayDialog(){ if(Is Mobile){//只针对移动端 return new Alert Dialog Component .Message("录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~") .Button("忽略") .OnClick(function(){//明确是用户点击的按钮,此时代表浏览器没有发起任何权限请求 //此处执行fail逻辑 console.log("无法录音:权限请求被忽略"); }) .OnCancel(NOOP)//自动取消的对话框不需要任何处理 .Delay(8000); //延迟8秒显示,这么久还没有操作基本可以判定浏览器有毛病 }; }; */ ``` -------- > 以下文档为GitHub仓库内的README原文,可能更新不及时,请到[GitHub仓库](https://github.com/xiangyuecn/Recorder)内查看最新文档 **【[源GitHub仓库](https://github.com/xiangyuecn/Recorder)】 | 【[Gitee镜像库](https://gitee.com/xiangyuecn/Recorder)】如果本文档图片没有显示,请手动切换到Gitee镜像库阅读文档。** # :open_book:Recorder用于html5录音 [​](?Ref=Desc&Start)支持在大部分已实现`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方法返回的流`、`自己创建的流` 等等。 [​](?) **Recorder H5** : [ [H5在线测试](https://xiangyuecn.gitee.io/recorder/) ] [ [H5 QuickStart](https://xiangyuecn.gitee.io/recorder/QuickStart.html) ] [ [H5 vue](https://xiangyuecn.gitee.io/recorder/assets/demo-vue) ] **工具集** : [ [Recorder代码运行和静态分发](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8C%E5%92%8C%E9%9D%99%E6%80%81%E5%88%86%E5%8F%91Runtime.html) ] [ [裸(RAW、WAV)PCM转WAV播放测试和转码](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E8%A3%B8PCM%E8%BD%ACWAV%E6%92%AD%E6%94%BE%E6%B5%8B%E8%AF%95.html) ] [ [无用户操作测试](https://xiangyuecn.gitee.io/recorder/assets/ztest_no_user_operation.html) ] [ [Can I Use查看浏览器支持情况](https://caniuse.com/#search=getUserMedia) ] **RecordApp**[即将废弃] : [ [RecordApp测试](https://jiebian.life/web/h5/github/recordapp.aspx) ] [ [App QuickStart](https://jiebian.life/web/h5/github/recordapp.aspx?path=/app-support-sample/QuickStart.html) ] [ [App vue](https://jiebian.life/web/h5/github/recordapp.aspx?path=/assets/demo-vue/recordapp.html) ] [ [Android、IOS App源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample) ] > [<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/demo.png" width="100px">](https://xiangyuecn.gitee.io/recorder/) 扫一扫在线测试,`github.io`可访问性太不尽人意,所以使用`gitee.io`镜像库的速度快多了。 [​](?) 录音默认输出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),均可简单拼接小的二进制录音片段文件来生成长的音频文件,具体参考下面这两种编码器的详细介绍。 > 如需在Hybrid App内使用(支持IOS、Android),或提供低版本IOS微信的支持,请参阅[app-support-sample](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample)目录。 > > *低版本IOS兼容、老旧国产手机自带浏览器上的使用限制等问题和兼容请参阅下面的知识库部分;打开录音后对音频播放的影响、录音中途来电话等问题也参阅下面的知识库。* [​](?) ### Demo片段列表 1. [【Demo库】【格式转换】-mp3格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.mp32other) 2. [【Demo库】【格式转换】-wav格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.wav2other) 3. [【Demo库】【格式转换】-amr格式转成其他格式](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.amr2other) 4. [【教程】【音频流】实时转码并上传-通用版](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.encode_transfer) 5. [【教程】【音频流】实时转码并上传-mp3专版](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.encode_transfer_mp3) 6. [【教程】【音频流】实时解码播放音频片段](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.decode_buffer_stream_player) 7. [【教程】实时录制处理audio、video标签的captureStream流](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.source_stream.capture_stream) 8. [【Demo库】【文件合并】-mp3多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.mp3_merge) 9. [【Demo库】【文件合并】-wav多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.wav_merge) 10. [【教程】实时多路音频混音](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.mix_multiple) 11. [【教程】变速变调音频转换](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform) 12. [【教程】DTMF(电话拨号按键信号)解码、编码](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.dtmf.decode_and_encode) 13. [【Demo库】PCM采样率提升](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.samplerate.raise) 14. [【测试】音频可视化相关扩展测试](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization) ### App Demo Android Demo App : [下载APK](https://gitee.com/xiangyuecn/Recorder/blob/master/app-support-sample/demo_android/app-debug.apk.zip)(40kb,删除.zip后缀, [源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_android)) IOS Demo App :[下载源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_ios) 自行编译 ### 小程序WebView 使用到这个库用于祝福语音的录制,已开通网页版和微信小程序版。专门针对IOS的微信中进行了兼容处理,IOS上微信环境中调用的微信的api(小程序、公众号api)。小程序地址:[<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/jiebian.life-xcx.png" width="100px">](https://jiebian.life/t/a);网页地址:[<img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/jiebian.life-web.png" width="100px">](https://jiebian.life/t/a) > 如果你的项目用到了这个库也想展示到这里,可以发个isuse,注明使用介绍和访问方式,我们收录在这里。 [​](?) [​](?) [​](?) [​](?) [​](?) [​](?) <p align="center"><a href="https://github.com/xiangyuecn/Recorder"><img width="100" src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/icon.png" alt="Recorder logo"></a></p> <p align="center"> Basic: <a title="Stars" href="https://github.com/xiangyuecn/Recorder"><img src="https://img.shields.io/github/stars/xiangyuecn/Recorder?color=0b1&logo=github" alt="Stars"></a> <a title="Forks" href="https://github.com/xiangyuecn/Recorder"><img src="https://img.shields.io/github/forks/xiangyuecn/Recorder?color=0b1&logo=github" alt="Forks"></a> <a title="npm Version" href="https://www.npmjs.com/package/recorder-core"><img src="https://img.shields.io/npm/v/recorder-core?color=0b1&logo=npm" alt="npm Version"></a> <a title="License" href="https://github.com/xiangyuecn/Recorder/blob/master/LICENSE"><img src="https://img.shields.io/github/license/xiangyuecn/Recorder?color=0b1&logo=github" alt="License"></a> </p> <p align="center"> Traffic: <a title="npm Downloads" href="https://www.npmjs.com/package/recorder-core"><img src="https://img.shields.io/npm/dt/recorder-core?color=f60&logo=npm" alt="npm Downloads"></a> <a title="cnpm" href="https://npm.taobao.org/package/recorder-core"><img src="https://img.shields.io/badge/cnpm-available-1690CD" alt="cnpm"></a><a title="cnpm" href="https://npm.taobao.org/package/recorder-core"><img src="https://npm.taobao.org/badge/d/recorder-core.svg" alt="cnpm"></a> <a title="JsDelivr CDN" href="https://www.jsdelivr.com/package/gh/xiangyuecn/Recorder"><img src="https://data.jsdelivr.com/v1/package/gh/xiangyuecn/Recorder/badge" alt="JsDelivr CDN"></a> <a title="51LA" href="https://www.51.la/?20469973"><img src="https://img.shields.io/badge/51LA-available-0b1" alt="cnpm"></a> </p> [​](?RefEnd) # :open_book:快速使用 你可以通过阅读和运行[QuickStart.html](https://xiangyuecn.gitee.io/recorder/QuickStart.html)文件来快速入门学习,直接将`QuickStart.html`copy到你的(https、localhost)网站中,无需其他文件,就能正常开始测试了;注意:需要在https、localhost等[安全环境](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Privacy_and_security)下才能进行录音。 ## 【1】加载框架 **方式一**:使用script标签引入 在需要录音功能的页面引入压缩好的recorder.xxx.min.js文件即可,[JsDelivr CDN](https://www.jsdelivr.com/features) ``` html <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录音: ``` html <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的源码下面文件路径调整一下即可 [​](?Ref=ImportCode&Start) ``` javascript //必须引入的核心,换成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' ``` [​](?RefEnd) ## 【2】调用录音,播放结果 [​](?Ref=Codes&Start)这里假设只录3秒,录完后立即播放,[在线编辑运行此代码>>](https://xiangyuecn.gitee.io/recorder/assets/%E5%B7%A5%E5%85%B7-%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8C%E5%92%8C%E9%9D%99%E6%80%81%E5%88%86%E5%8F%91Runtime.html?idf=self_base_demo) ``` javascript //简单控制台直接测试方法:在任意(无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扩展实时绘制波形 //可利用extensions/sonic.js扩展实时变速变调,此扩展计算量巨大,onProcess需要返回true开启异步模式 } }); //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); }); ``` [​](?) ## 【附】录音上传示例 ``` javascript 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);}); ``` [​](?RefEnd) ## 【附】问题排查 - 打开[Demo页面](https://xiangyuecn.gitee.io/recorder/)试试看,是不是也有同样的问题。 - 检查是不是在https之类的安全环境下调用的。 - 检查是不是低版本IOS系统,确认[caniuse](https://caniuse.com/#search=getUserMedia)IOS对`getUserMedia`的支持情况。 - 检查上面第1步是否把框架加载到位,在[Demo页面](https://xiangyuecn.gitee.io/recorder/)有应该加载哪些js的提示。 - 提交Issue,热心网友帮你解答。 ## 【QQ群】交流与支持 欢迎加QQ群:781036591,纯小写口令:`recorder` <img src="https://gitee.com/xiangyuecn/Recorder/raw/master/assets/qq_group_781036591.png" width="220px"> [​](?) [​](?) [​](?) # :open_book:知识库 本库期待的使用场景是语音录制,因此音质只要不比高品质的感觉差太多就行;1分钟的语音进行编码是很快的,但如果录制超长的录音,比如10分钟以上,不同类型的编码可能会花费比较长的时间,因为只有边录边转码(Worker)支持的类型才能进行极速转码。另外未找到双声道语音录制存在的意义(翻倍录音数据大小,并且拉低音质),因此特意仅对单声道进行支持。 浏览器Audio Media[兼容性](https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats#Browser_compatibility)mp3最好,wav还行,其他要么不支持播放,要么不支持编码;因此本库最佳推荐使用mp3、wav格式,代码也是优先照顾这两种格式。 **特别注**:低版本`IOS(11.X、12.X、13.X)`上只有`Safari`支持`getUserMedia`,低版本IOS上其他浏览器均不支持,唯一有点卵用的Safari `getUserMedia` 底层实现bug奇多(严重关切他们团队水准,临时工少发工资了吧),参考下面的已知问题。 **特别注**:大部分2021年以前的老旧国产手机自带的浏览器(系统浏览器)虽然支持`getUserMedia`方法,但并不能使用,表现为直接返回拒绝或者干脆没有任何回调;UC系列目测全部阵亡(含支付宝)。 **留意中途来电话**:在移动端录音时,如果录音中途来电话,或者通话过程中打开录音,是不一定能进行录音的;经过简单测试发现,IOS上Safari将暂停返回音频数据,直到通话结束才开始继续有音频数据返回;小米上Chrome不管是来电还是通话中开始录音都能对麦克风输入的声音进行录音(听筒中的并不能录到,扬声器外放的会被明显降噪);只是简单测试,更多机器和浏览器并未做测试,不过整体上来看来电话或通话中进行录音的可行性并不理想,也不赞成在这种过程中进行录音;但只要通话结束后录音还是会正常进行,影响基本不大。 **录音时对播放音频的影响**:仅在移动端,录音过程中尽量不要去播放音频,正在播放的也应该暂停播放,否则不同手机系统、浏览器环境可能表现会出乎意料;已知IOS Safari上录音打开后,如果播放音频,声音会[变得非常小](https://www.cnblogs.com/cocoajin/p/7591068.html);Android上也有可能声音被切换到听筒播放,而不是扬声器大喇叭上播放导致声音也会变小;更多可能的情况需要更多设备、浏览器的测试数据才能发掘;PC上似乎无此影响。 **特别注**:如果在`iframe`里面调用的录音功能,并且和上层的网页是不同的域(跨域了),如果未设置相应策略,权限永远是被拒绝的,[参考此处](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#Privacy_and_security)。另外如果要在`非跨域的iframe`里面使用,最佳实践应该是让window.top去加载Recorder(异步加载js),iframe里面使用top.Recorder,免得各种莫名其妙(比如微信里面的各种渣渣功能,搞多了就习惯了)。 > 如果需要最大限度的兼容低版本IOS(仅增加微信支持),可以使用`RecordApp`,它已包含`Recorder`,源码在`src/app-support`、`app-support-sample`中,但此兼容库需要服务器端提供微信JsSDK的签名、下载素材接口,涉及微信公众(订阅)号的开发。 支持|Recorder|[RecordApp](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample) -:|:-:|:-: PC浏览器|√|√ Android Chrome Firefox|√|√ Android微信(含小程序)|√|√ Android Hybrid App|√|√ Android其他浏览器|未知|未知 IOS Safari|√|√ IOS微信(含小程序)|IOS 14.3+|√ IOS Hybrid App|IOS 14.3+|√ IOS其他浏览器|IOS 14.3+|IOS 14.3+ 开发难度|简单|复杂 第三方依赖|无|依赖微信公众号 ## 已知问题 *2018-09-19* [caniuse](https://caniuse.com/#search=getUserMedia) 注明`IOS` `11.X - 12.X(13.X)` 上 只有`Safari`支持调用`getUserMedia`,其他App下WKWebView(UIWebView?)([相关资料](https://forums.developer.apple.com/thread/88052))均不支持(2021-2-15 IOS 14.3+已无此问题)。经用户测试验证IOS 12上chrome、UC都无法录音,部分IOS 12 Safari可以获取到并且能正常录音,但部分不行,原因未知,参考[ios 12 支不支持录音了](https://www.v2ex.com/t/490695)。在IOS上不支持录音的环境下应该采用其他解决方案,参考`案例演示`、`关于微信JsSDK`部分。 *2019-02-28* [issues#14](https://github.com/xiangyuecn/Recorder/issues/14) 如果`getUserMedia`返回的[`MediaStreamTrack.readyState == "ended"`,`"ended" which indicates that the input is not giving any more data and will never provide new data.`](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack) ,导致无法录音。如果产生这种情况,目前在`rec.open`方法调用时会正确检测到,并执行`fail`回调。造成`issues#14` `ended`原因是App源码中`AndroidManifest.xml`中没有声明`android.permission.MODIFY_AUDIO_SETTINGS`权限,导致腾讯X5不能正常录音。 *2019-03-09* 在Android上QQ、微信里,请求授权使用麦克风的提示,经过长时间观察发现,他们的表现很随机、很奇特。可能每次在调用`getUserMedia`时候都会弹选择,也可能选择一次就不会再弹提示,也可能重启App后又会弹。如果用户拒绝了,可能第二天又会弹,或者永远都不弹了,要么重置(装)App。使用腾讯X5内核的App测试也是一样奇特表现,拒绝权限后可能必须要重置(装)。这个问题貌似跟X5内核自动升级的版本有关。QQ浏览器更加惨不忍睹,2019-08-16测试发现卸载重装、拒绝权限后永远无法弹出授权,通过浏览器设置-清理-清理地理位置授权才能恢复,重启、重装、清理系统垃圾、删除根目录文件夹(腾讯那个大文件不敢删,毒瘤)垃圾均无效,奇葩。 *2019-06-14* 经[#29](https://github.com/xiangyuecn/Recorder/issues/29)反馈,稍微远程真机测试了部分厂商的比较新的Android手机系统浏览器的录音支持情况;华为:直接返回拒绝,小米:没有回调,OPPO:好像是没有回调,vivo:好像是没有回调;另外专门测试了一下UC最新版(支付宝):直接返回拒绝。另[参考](https://www.jianshu.com/p/6cd5a7fa562c)。也许他们都商量好了或者本身都是用的UC?至于没有任何回调的,此种浏览器没有良心。 *2019-07-22* 对[#34](https://github.com/xiangyuecn/Recorder/issues/34)反馈研究后发现,问题一:~~macOS、IOS的Safari对连续调用录音(中途未调用close)是有问题的,但只要调用close后再重复录音就没有问题~~(已通过特殊手段解决)。问题二:IOS上如果录音之前先播放了任何Audio,录音过程可能会变得很诡异,但如果先录音,就不存在此问题(19-09-18 Evan:QQ1346751357反馈发现本问题并非必现,[功能页面](https://hft.bigdatahefei.com/LocateSearchService/sfc/index),但本库的Demo内却必现,原因不明)。chrome、firefox正常的很。目测这两个问题是非我等屌丝能够解决的,于是报告给苹果家程序员看看,因此发了个[帖子](https://forums.developer.apple.com/message/373108),顺手在`Feedback Assistant`提交了`bug report`,但好几天过去了没有任何回应(顺带给微软一个好评)。问题一目前已通过全局共享一个MediaStream连接来解决,原因在于Safari上MediaStream断开后就无法再次进行连接使用(表现为静音),改成了全局只连接一次就避免了此问题;全局处理也有利于屏蔽底层细节,start时无需再调用底层接口,提升兼容、可靠性。 *2019-10-26* 针对[#51](https://github.com/xiangyuecn/Recorder/issues/51)的问题研究后发现,如果录音时设备偶尔出现很卡的情况下(CPU被其他程序大量占用),浏览器采集到的音频是断断续续的,导致10秒的录音可能就只返回了5秒的数据量,这个时候最终编码得到的音频时长明显变短,播放时的效果就像快放一样。此问题能够稳定复现(使用别的程序大量占用CPU来模拟),目前已在`envIn`内部函数中进行了补偿处理,在浏览器两次传入PCM数据之间填充一段静默数据已弥补丢失的时长;最终编码得到的音频时长将和实际录音时长基本一致,消除了快放效果,但由于丢失的音频已被静默数据代替,听起来就是数据本身的断断续续的效果。在设备不卡时录音没有此问题。 *2019-11-03* lamejs原版编码器编码出来的mp3文件首尾存在填充数据并且会占据一定时长(这种数据播放时静默,记录的信息数据或者填充),同一录音mp3格式的时长会比wav格式的时长要长0-100ms左右,大部分情况下不会有影响,但如果涉及到实时转码并传输的话,这些数据将会造成多段mp3片段的总时长比实际录音要长,最终播放时会均匀的感觉到停顿,并且mp3片段越小越明显。本库已对lamejs编码出来的mp3文件进行了处理,去掉了头部的非音频数据,但由于编码出来的mp3每一帧数据都有固定时长,文件结尾最后一帧可能录音的时长不能刚好填满,就会产生填充数据;因此本库编码出来的mp3文件会比wav格式长0-30ms左右,多出来的时长在mp3的结尾处;mp3解码出来的pcm数据直接去掉结尾多出来的部分,就和wav中的pcm数据基本一致了;另外可以通过调节待编码的pcm数据长度以达到刚好填满最后一帧来规避此问题,参考`Recorder.SampleData`方法提供的连续转码针对此问题的处理(但小的mp3片段拼接起来停顿导致的杂音还是非常明显,实时处理时使用`takeoffEncodeChunk`选项可完全避免此问题)。[参考wiki](https://github.com/xiangyuecn/Recorder/wiki/lamejs编码出来的mp3时长修正)。 *2020-04-26* Safari Bug:据QQ群内`1048506792`、`190451148`开发者反馈研究发现,IOS ?-13.X Safari内打开录音后,如果切换到了其他标签、或其他App并且播放了任何声音,此时将会中断已打开的录音(系统级的?),切换回正在录音的页面,这个页面的录音功能将会彻底失效,并且刷新也无法恢复录音;表现为关闭录音后再次打开录音,能够正常获得权限,但浏览器返回的采集到的音频为静默的PCM,此时地址栏也并未显示出麦克风图标,刷新这个标签也也是一样不能正常获得录音,只有关掉此标签新打开页面才可正常录音。如果打开录音后关闭了录音,然后切换到其他标签或App播放声音,然后返回录音页面,不会出现此问题。此为Safari的底层Bug(也许是少给临时工工钱了吧,无能为力)。使用长按录音类似的用户交互可大幅度避免踩到这坨翔。 [​](?) [​](?) [​](?) # :open_book:方法文档 ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_caller.png) ### 【构造】rec=Recorder(set) 构造函数,拿到`Recorder`的实例,然后可以进行请求获取麦克风权限和录音。 `set`参数为配置对象,默认配置值如下: ``` javascript set={ type:"mp3" //输出类型:mp3,wav等,使用一个类型前需要先引入对应的编码引擎 ,bitRate:16 //比特率,必须是数字 wav(位):16、8,MP3(单位kbps):8kbps时文件大小1k/s,16kbps 2k/s,录音文件很小 ,sampleRate:16000 //采样率,必须是数字,wav格式(8位)文件大小=sampleRate*时间;mp3此项对低比特率文件大小有影响,高比特率几乎无影响。 //wav任意值,mp3取值范围:48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 ,onProcess:NOOP //接收到录音数据时的回调函数:fn(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd) //返回值:onProcess如果返回true代表开启异步模式,在某些大量运算的场合异步是必须的,必须在异步处理完成时调用asyncEnd(不能真异步时需用setTimeout包裹);返回其他值或者不返回为同步模式(需避免在回调内执行耗时逻辑);如果开启异步模式,在onProcess执行后新增的buffer会全部替换成空数组,因此本回调开头应立即将newBufferIdx到本次回调结尾位置的buffer全部保存到另外一个数组内,处理完成后写回buffers中本次回调的结尾位置。 //buffers=[[Int16,...],...]:缓冲的PCM数据,为从开始录音到现在的所有pcm片段,每次回调可能增加0-n个不定量的pcm片段。 //powerLevel:当前缓冲的音量级别0-100。 //bufferDuration:已缓冲时长。 //bufferSampleRate:缓冲使用的采样率(当type支持边录边转码(Worker)时,此采样率和设置的采样率相同,否则不一定相同)。 //newBufferIdx:本次回调新增的buffer起始索引。 //asyncEnd:fn() 如果onProcess是异步的(返回值为true时),处理完成时需要调用此回调,如果不是异步的请忽略此参数,此方法回调时必须是真异步(不能真异步时需用setTimeout包裹)。 //如果需要绘制波形之类功能,需要实现此方法即可,使用以计算好的powerLevel可以实现音量大小的直观展示,使用buffers可以达到更高级效果 //注意,buffers数据的采样率和set.sampleRate不一定相同,可能为浏览器提供的原始采样率rec.srcSampleRate,也可能为已转换好的采样率set.sampleRate;如需浏览器原始采样率的数据,请使用rec.buffers原始数据,而不是本回调的参数;如需明确和set.sampleRate完全相同采样率的数据,请在onProcess中自行连续调用采样率转换函数Recorder.SampleData(),配合mock方法可实现实时转码和压缩语音传输;修改或替换buffers内的数据将会改变最终生成的音频内容(注意不能改变第一维数组长度),比如简单有限的实现实时静音、降噪、混音等处理,详细参考下面的rec.buffers //*******高级设置****** //,sourceStream:MediaStream Object //可选直接提供一个媒体流,从这个流中录制、实时处理音频数据(当前Recorder实例独享此流);不提供时为普通的麦克风录音,由getUserMedia提供音频流(所有Recorder实例共享同一个流) //比如:audio、video标签dom节点的captureStream方法(实验特性,不同浏览器支持程度不高)返回的流;WebRTC中的remote流;自己创建的流等 //注意:流内必须至少存在一条音轨(Audio Track),比如audio标签必须等待到可以开始播放后才会有音轨,否则open会失败 //,audioTrackSet:{ deviceId:"",groupId:"", autoGainControl:true, echoCancellation:true, noiseSuppression:true } //普通麦克风录音时getUserMedia方法的audio配置参数,比如指定设备id,回声消除、降噪开关;注意:提供的任何配置值都不一定会生效 //由于麦克风是全局共享的,所以新配置后需要close掉以前的再重新open //更多参考: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints //,disableEnvInFix:false 内部参数,禁用设备卡顿时音频输入丢失补偿功能,如果不清楚作用请勿随意使用 //,takeoffEncodeChunk:NOOP //fn(chunkBytes) chunkBytes=[Uint8,...]:实时编码环境下接管编码器输出,当编码器实时编码出一块有效的二进制音频数据时实时回调此方法;参数为二进制的Uint8Array,就是编码出来的音频数据片段,所有的chunkBytes拼接在一起即为完整音频。本实现的想法最初由QQ2543775048提出。 //当提供此回调方法时,将接管编码器的数据输出,编码器内部将放弃存储生成的音频数据;环境要求比较苛刻:如果当前环境不支持实时编码处理,将在open时直接走fail逻辑 //因此提供此回调后调用stop方法将无法获得有效的音频数据,因为编码器内没有音频数据,因此stop时返回的blob将是一个字节长度为0的blob //目前只有mp3格式实现了实时编码,在支持实时处理的环境中将会实时的将编码出来的mp3片段通过此方法回调,所有的chunkBytes拼接到一起即为完整的mp3,此种拼接的结果比mock方法实时生成的音质更加,因为天然避免了首尾的静默 //目前除mp3外其他格式不可以提供此回调,提供了将在open时直接走fail逻辑 } ``` **注意:set内是数字的明确传数字**,不要传字符串之类的导致不可预测的异常,其他有配置的地方也是一样(感谢`214282049@qq.com`19-01-10发的反馈邮件)。 *注:如果录音结束后生成的音频文件的比特率和采样率和set中的不同,将会把set中的bitRate、sampleRate更新成音频文件的。* ### 【方法】rec.open(success,fail) 请求打开录音资源,如果浏览器不支持录音、用户拒绝麦克风权限、或者非安全环境(非https、file等)将会调用`fail`;打开后需要调用`close`来关闭,因为浏览器或设备的系统可能会显示正在录音。 注意:此方法回调是可能是同步的(异常、或者已持有资源时)也可能是异步的(浏览器弹出权限请求时);一般使用时打开,用完立即关闭;可重复调用,可用来测试是否能录音。 另外:普通的麦克风录音时,因为此方法会调起用户授权请求,如果仅仅想知道浏览器是否支持录音(比如:如果浏览器不支持就走另外一套录音方案),应使用`Recorder.Support()`方法。 **注意:打开普通麦克风录音后,如果未调用close关闭,可能会影响audio音频的播放,表现为移动端audio播放有明显的杂音(麦克风的电流音?),因此如果你录音后有别的操作,尽量录完音就立即调用close关闭录音。** > **特别注**: 鉴于UC系浏览器(大部分老旧国产手机厂商系统浏览器)大概率表面支持录音但永远不会有任何回调、或者此浏览器支持第三种情况(用户忽略 并且 此浏览器认为此种情况不需要回调 并且程序员完美实现了);如果当前环境是移动端,可以在调用此方法`8秒`后如果未收到任何回调,弹出一个自定义提示框(只需要一个按钮),提示内容范本:`录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~`,按钮文本:`忽略`;当用户点击了按钮,直接手动执行`fail`逻辑,因为此时浏览器压根就没有弹移动端特有的模态话权限请求对话框;但如果收到了回调(可能是同步的,因此弹框必须在`rec.open`调用前准备好随时取消),需要把我们弹出的提示框自动关掉,不需要用户做任何处理。pc端的由于不是模态化的请求对话框,可能会被用户误点,所以尽量要判断一下是否是移动端。 `success`=fn(); `fail`=fn(errMsg,isUserNotAllow); 如果是用户主动拒绝的录音权限,除了有错误消息外,isUserNotAllow=true,方便程序中做不同的提示,提升用户主动授权概率 ### 【方法】rec.close(success) 关闭释放录音资源,释放完成后会调用`success()`回调。如果正在录音或者stop调用未完成前调用了close将会强制终止当前录音。 注意:普通的麦克风录音时(所有Recorder实例共享同一个流),如果创建了多个Recorder对象并且调用了open(应避免同时有多个对象进行了open),只有最后一个新建的才有权限进行实际的资源释放(和多个对象close调用顺序无关),浏览器或设备的系统才会不再显示正在录音的提示;直接提供的流 set.sourceStream 无此问题(当前Recorder实例独享此流)。 ### 【方法】rec.start() 开始录音,需先调用`open`;未close之前可以反复进行调用开始新的录音。 只要open成功后,调用此方法是安全的,如果未open强行调用导致的内部错误将不会有任何提示,stop时自然能得到错误;另外open操作可能需要花费比较长时间,如果中途调用了stop,open完成时(同步)的任何start调用将会被自动阻止,也是不会有提示的。 ### 【方法】rec.stop(success,fail,autoClose) 结束录音并返回录音数据`blob对象`,拿到blob对象就可以为所欲为了,不限于立即播放、上传 `success(blob,duration)`:`blob`:录音数据audio/mp3|wav...格式,`duration`:录音时长,单位毫秒 `fail(errMsg)`:录音出错回调 `autoClose`:`false` 可选,是否自动调用`close`,默认为`false`不调用 提示:stop时会进行音频编码,根据类型的不同音频编码花费的时间也不相同。对于支持边录边转码(Worker)的类型,将极速完成编码并回调;对于不支持的10几秒录音花费2秒左右算是正常,但内部采用了分段编码+setTimeout来处理,界面卡顿不明显。 ### 【方法】rec.pause() 暂停录音。 ### 【方法】rec.resume() 恢复继续录音。 ### 【属性】rec.buffers 此数据为从开始录音到现在为止的所有已缓冲的PCM片段列表,`buffers` `=` `[[Int16,...],...]` 为二维数组;在没有边录边转码的支持时(mock调用、非mp3等),录音stop时会使用此完整数据进行转码成指定的格式。 buffers中的PCM数据为浏览器采集的原始音频数据,采样率为浏览器提供的原始采样率`rec.srcSampleRate`;在`rec.set.onProcess`回调中`buffers`参数就是此数据或者此数据重新采样后的新数据;修改或替换`onProcess`回调中`buffers`参数可以改变最终生成的音频内容,但修改`rec.buffers`不一定会有效,因此你可以在`onProcess`中修改或替换`buffers`参数里面的内容,注意只能修改或替换上次回调以来新增的buffer(不允许修改已处理过的,不允许增删第一维数组,允许将第二维数组任意修改替换成空数组也可以);以此可以简单有限的实现实时静音、降噪、混音等处理。 如果你需要长时间实时录音(如长时间语音通话),并且不需要得到最终完整编码的音频文件: 1. 未提供set.takeoffEncodeChunk时,Recorder初始化时应当使用一个未知的类型进行初始化(如: type:"unknown",仅仅用于初始化而已,实时转码可以手动转成有效格式,因为有效格式可能内部还有其他类型的缓冲,`unknown`类型`onProcess buffers`和`rec.buffers`是同一个数组);提供set.takeoffEncodeChunk接管了编码器实时输出时,无需特殊处理,因为编码器内部将不会使用缓冲; 2. 实时在`onProcess`中修改`buffers`参数数组,可以只保留最后两个元素,其他元素设为null(代码:`onProcess: buffers[buffers.length-3]=null`),不保留也行,全部设为null,以释放占用的内存;`rec.buffers`将会自动清理,无需手动清理;注意:提供set.takeoffEncodeChunk时,应当延迟一下清理,不然buffers被清理掉时,这个buffers还未推入编码器进行编码; 3. 录音结束时可以不用调用`stop`,直接调用`close`丢弃所有数据即可。只要buffers[0]==null时调用`stop`永远会直接走fail回调。 ### 【属性】rec.srcSampleRate 浏览器提供的原始采样率,只有start或mock调用后才会有值,此采样率就是rec.buffers数据的采样率。 ### 【方法】rec.mock(pcmData,pcmSampleRate) 模拟一段录音数据,后面可以调用stop进行编码。需提供pcm数据 `pcmData` `=` `[Int16,...]` 为一维数组,和pcm数据的采样率 `pcmSampleRate`。 提示:在录音实时回调中配合`Recorder.SampleData()`方法使用效果更佳,可实时生成小片段语音文件。 **注意:pcmData为一维数组,如果提供二维数组将会产生不可预料的错误**;如果需要使用类似`onProcess`回调的`buffers`或者`rec.buffers`这种pcm列表(二维数组)时,可自行展开成一维,或者使用`Recorder.SampleData()`方法转换成一维。 本方法可用于将一个音频解码出来的pcm数据方便的转换成另外一个格式: ``` javascript var amrBlob=...;//amr音频blob对象 var amrSampleRate=8000;//amr音频采样率 //解码amr得到pcm数据 var reader=new FileReader(); reader.onload=function(){ Recorder.AMR.decode(new Uint8Array(reader.result),function(pcm){ transformOgg(pcm); }); }; reader.readAsArrayBuffer(amrBlob); //将pcm转成ogg function transformOgg(pcmData){ Recorder({type:"ogg",bitRate:64,sampleRate:32000}) .mock(pcmData,amrSampleRate) .stop(function(blob,duration){ //我们就得到了新采样率和比特率的ogg文件 console.log(blob,duration); }); }; ``` ### 【静态方法】Recorder.Support() 判断浏览器是否支持录音,随时可以调用。注意:仅仅是检测浏览器支持情况,不会判断和调起用户授权(rec.open()会判断用户授权),不会判断是否支持特定格式录音。 ### 【静态方法】Recorder.IsOpen() 由于Recorder持有的普通麦克风录音资源是全局唯一的,可通过此方法检测是否有Recorder已调用过open打开了麦克风录音功能。 ### 【静态方法】Recorder.Destroy() 销毁已持有的所有全局资源(AudioContext、Worker),当要彻底移除Recorder时需要显式的调用此方法。大部分情况下不调用Destroy也不会造成问题。 ### 【静态属性】Recorder.TrafficImgUrl 流量统计用1像素图片地址,在Recorder首次被实例化时将往这个地址发送一个请求,请求是通过Image对象来发送,安全可靠;默认开启统计,url为本库的51la统计用图片地址,为空响应流量消耗非常小,因此对使用几乎没有影响。 设置为空字符串后将不参与统计,大部分情况下无需关闭统计,如果你网页的url私密性要求很高,请在调用Recorder之前将此url设为空字符串;本功能于2019-11-09添加,[点此](https://www.51.la/?20469973)前往51la查看统计概况。 ### 【静态属性】Recorder.BufferSize 普通的麦克风录音时全局的AudioContext缓冲大小,默认值为4096。会影响H5录音时的onProcess调用速率,相对于AudioContext.sampleRate=48000时,4096接近12帧/s,调节此参数可生成比较流畅的回调动画。 取值256, 512, 1024, 2048, 4096, 8192, or 16384 注意:取值不能过低,2048开始不同浏览器可能回调速率跟不上造成音质问题。一般无需调整,调整后需要先close掉已打开的录音,再open时才会生效。 *如果是直接提供的流 set.sourceStream,不是默认的从麦克风录音时,这个属性可以改成由Recorder的实例提供,比如rec.BufferSize=1024,这样就不会受全局干扰。* *这个属性在旧版Recorder中是放在已废弃的set.bufferSize中,后面因为兼容处理Safari上MediaStream断开后就无法再次进行连接使用的问题(表现为静音),把MediaStream连接也改成了全局只连接一次,因此set.bufferSize就移出来变成了Recorder的属性* ### 【静态方法】Recorder.SampleData(pcmDatas,pcmSampleRate,newSampleRate,prevChunkInfo,option) 对pcm数据的采样率进行转换,配合mock方法使用效果更佳,比如实时转换成小片段语音文件。 注意:本方法只会将高采样率的pcm转成低采样率的pcm,当newSampleRate>pcmSampleRate想转成更高采样率的pcm时,本方法将不会进行转换处理(由低的采样率转成高的采样率没有存在的意义);在特殊场合下如果确实需要提升采样率,比如8k必须转成16k,可参考[【Demo库】PCM采样率提升](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.samplerate.raise)自行编写代码转换一下即可。 `pcmDatas`: [[Int16,...]] pcm片段列表,二维数组,比如可以是:rec.buffers、onProcess中的buffers `pcmSampleRate`:48000 pcm数据的采样率,比如用:rec.srcSampleRate、onProcess中的bufferSampleRate `newSampleRate`:16000 需要转换成的采样率,newSampleRate>=pcmSampleRate时不会进行任何处理,小于时会进行重新采样 `prevChunkInfo`:{} 可选,上次调用时的返回值,用于连续转换,本次调用将从上次结束位置开始进行处理。或可自行定义一个ChunkInfo从pcmDatas指定的位置开始进行转换 `option`: ``` javascript option:{ 可选,配置项 frameSize:123456 帧大小,每帧的PCM Int16的数量,采样率转换后的pcm长度为frameSize的整数倍,用于连续转换。目前仅在mp3格式时才有用,frameSize取值为1152,这样编码出来的mp3时长和pcm的时长完全一致,否则会因为mp3最后一帧录音不够填满时添加填充数据导致mp3的时长变长。 frameType:"" 帧类型,一般为rec.set.type,提供此参数时无需提供frameSize,会自动使用最佳的值给frameSize赋值,目前仅支持mp3=1152(MPEG1 Layer3的每帧采采样数),其他类型=1。 以上两个参数用于连续转换时使用,最多使用一个,不提供时不进行帧的特殊处理,提供时必须同时提供prevChunkInfo才有作用。最后一段数据处理时无需提供帧大小以便输出最后一丁点残留数据。 } ``` 返回值ChunkInfo ``` javascript { //可定义,从指定位置开始转换到结尾 index:0 pcmDatas已处理到的索引 offset:0.0 已处理到的index对应的pcm中的偏移的下一个位置 //仅作为返回值 frameNext:null||[Int16,...] 下一帧的部分数据,frameSize设置了的时候才可能会有 sampleRate:16000 结果的采样率,<=newSampleRate data:[Int16,...] 转换后的PCM结果,为一维数组;如果是连续转换,并且pcmDatas中并没有新数据时,data的长度可能为0 } ``` ### 【静态方法】Recorder.PowerLevel(pcmAbsSum,pcmLength) 计算音量百分比的一个方法,返回值:0-100,主要当做百分比用;注意:这个不是分贝,因此没用volume当做名称。 `pcmAbsSum`: pcm Int16所有采样的绝对值的和 `pcmLength`: pcm长度 [​](?) [​](?) [​](?) # :open_book:关于现有编码器 如果你有其他格式的编码器并且想贡献出来,可以提交新增格式文件的PR(文件放到/src/engine中),我们升级它。 ## pcm pcm编码器输出的数据其实就是Recorder中的buffers原始数据(经过了重新采样),16位时为LE小端模式(Little Endian),并未经过任何编码处理;pcm为未封装的原始音频数据,pcm数据文件无法直接播放,pcm加上一个44字节wav头即成wav文件,可通过wav格式来正常播放。两个参数相同的pcm文件直接二进制拼接在一起即可成为长的pcm文件。 ### Recorder.pcm2wav(data,True,False) 已实现的一个把pcm转成wav格式来播放的方法,`data = { sampleRate:16000 pcm的采样率 , bitRate:16 pcm的位数 取值:8 或 16 , blob:pcm的blob对象 }`,`True=fn(wavBlob,duration)`。要使用此方法需要带上`wav`格式编码器。 ## wav (raw pcm format) wav格式编码器时参考网上资料写的,会发现代码和别人家的差不多。源码2kb大小。[wav转其他格式参考和测试](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.transform.wav2other) ### wav转pcm 生成的wav文件内音频数据的编码为未压缩的pcm数据(raw pcm),只是在pcm数据前面加了一个44字节的wav头;因此直接去掉前面44字节就能得到原始的pcm数据,如:`blob.slice(44,blob.size,"audio/pcm")`; ### 简单将多段小的wav片段合成长的wav文件 由于RAW格式的wav内直接就是pcm数据,因此将小的wav片段文件去掉wav头后得到的原始pcm数据合并到一起,再加上新的wav头即可合并出长的wav文件;要求待合成的所有wav片段的采样率和位数需一致。[wav合并参考和测试+可移植源码](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.wav_merge) ## mp3 (CBR) 采用的是[lamejs](https://github.com/zhuker/lamejs)(LGPL License)这个库的代码,`https://github.com/zhuker/lamejs/blob/bfb7f6c6d7877e0fe1ad9