From d3f8543437a4909549f5bf98a9999f99269ed4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E5=9D=9A=E6=9E=9C?= <753610399@qq.com> Date: Wed, 4 Aug 2021 02:30:32 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B4=AF=E7=A7=AF=E6=9B=B4=E6=96=B0=EF=BC=9A?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=B9MediaStream=E7=9A=84=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E6=94=AF=E6=8C=81=EF=BC=8C=E5=A2=9E=E5=8A=A0BufferStr?= =?UTF-8?q?eamPlayer=E6=89=A9=E5=B1=95=E7=94=A8=E4=BA=8E=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E9=9F=B3=E9=A2=91=E7=89=87=E6=AE=B5=E6=96=87=E4=BB=B6=E6=92=AD?= =?UTF-8?q?=E6=94=BE=EF=BC=8C=E6=96=B0=E5=A2=9Epcm=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 302 ++++++++++-- app-support-sample/index.html | 34 +- ...6\345\275\274\344\270\200\346\227\266.mp4" | Bin 0 -> 220367 bytes assets/demo.png | Bin 1126 -> 924 bytes assets/header-leg__diygod.me.jpg | Bin 0 -> 572356 bytes assets/npm-home/hash-history.txt | 8 +- assets/runtime-codes/fragment.playbuffer.js | 2 + ...ch.realtime.decode_buffer_stream_player.js | 397 ++++++++++++++++ .../teach.realtime.encode_transfer.js | 29 +- .../teach.realtime.encode_transfer_mp3.js | 8 +- .../teach.source_stream.capture_stream.js | 131 +++++ assets/zdemo.index.webrtc.js | 10 +- ...0\201\345\210\206\345\217\221Runtime.html" | 12 +- dist/engine/beta-amr.js | 2 +- dist/engine/pcm.js | 6 + dist/engine/wav.js | 2 +- dist/extensions/buffer_stream.player.js | 6 + dist/recorder-core.js | 2 +- index.html | 136 +++++- recorder.mp3.min.js | 2 +- recorder.wav.min.js | 2 +- src/engine/pcm.js | 96 ++++ src/engine/wav.js | 4 +- src/extensions/buffer_stream.player.js | 448 ++++++++++++++++++ src/package-build.js | 2 + src/recorder-core.js | 191 +++++--- 26 files changed, 1676 insertions(+), 156 deletions(-) create mode 100644 "assets/audio/movie-\344\270\200\344\273\243\345\256\227\345\270\210-\346\255\244\344\270\200\346\227\266\345\275\274\344\270\200\346\227\266.mp4" create mode 100644 assets/header-leg__diygod.me.jpg create mode 100644 assets/runtime-codes/teach.realtime.decode_buffer_stream_player.js create mode 100644 assets/runtime-codes/teach.source_stream.capture_stream.js create mode 100644 dist/engine/pcm.js create mode 100644 dist/extensions/buffer_stream.player.js create mode 100644 src/engine/pcm.js create mode 100644 src/extensions/buffer_stream.player.js diff --git a/README.md b/README.md index b1cc66d..e822ec0 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ # :open_book:Recorder用于html5录音 -[​](?Ref=Desc&Start)[在线测试](https://xiangyuecn.gitee.io/recorder/),支持大部分已实现`getUserMedia`的移动端、PC端浏览器;主要包括:Chrome、Firefox、Safari、IOS 14.3+、Android WebView、腾讯Android X5内核(QQ、微信);不支持:~~UC系内核(典型的支付宝),大部分国产手机厂商自研套壳娱乐浏览器,低版本IOS(11.0-14.2)上除Safari外的其他任何形式的浏览器(含PWA、WebClip、任何App内网页)~~。 - +[​](?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/) ] @@ -30,18 +31,75 @@ [ [Android、IOS App源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample) ] +> [](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兼容、老旧国产手机自带浏览器上的使用限制等问题和兼容请参阅下面的知识库部分;打开录音后对音频播放的影响、录音中途来电话等问题也参阅下面的知识库。* + + -录音默认输出mp3格式,另外可选wav格式;有限支持ogg(beta)、webm(beta)、amr(beta)格式;支持任意格式扩展(前提有相应编码器)。 -mp3默认16kbps的比特率,2kb每秒的录音大小,音质还可以(如果使用8kbps可达到1kb每秒,不过音质太渣)。主要用于语音录制,双声道语音没有意义,特意仅对单声道进行支持。mp3和wav格式支持边录边转码,录音结束时转码速度极快,支持实时转码成小片段文件和实时传输,demo中已实现一个语音通话聊天,下面有介绍;其他格式录音结束时可能需要花费比较长的时间进行转码。 +[​](?) + +### 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)。小程序地址:[](https://jiebian.life/t/a);网页地址:[](https://jiebian.life/t/a) + +> 如果你的项目用到了这个库也想展示到这里,可以发个isuse,注明使用介绍和访问方式,我们收录在这里。 + + -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兼容、国产厂商自研套壳娱乐浏览器上的使用限制等问题和兼容请参阅下面的知识库部分;打开录音后对音频播放的影响、录音中途来电话等问题也参阅下面的知识库。* + +[​](?) + +[​](?) + +[​](?) + +[​](?) + +[​](?) + +[​](?) +

Recorder logo

@@ -63,6 +121,8 @@ mp3使用lamejs编码(CBR),压缩后的recorder.mp3.min.js文件150kb左右( [​](?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)下才能进行录音。 @@ -105,7 +165,7 @@ import 'recorder-core/src/extensions/waveview' ``` [​](?RefEnd) -## 【2】调用录音 +## 【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)}) @@ -113,7 +173,7 @@ import 'recorder-core/src/extensions/waveview' var rec; /**调用open打开录音请求好录音权限**/ var recOpen=function(success){//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了 - rec=Recorder({ + 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次本回调 @@ -188,6 +248,9 @@ recOpen(function(){ }); ``` + +[​](?) + ## 【附】录音上传示例 ``` javascript var TestApi="/test_request";//用来在控制台network中能看到请求数据,测试的请求结果无关紧要 @@ -259,39 +322,18 @@ $.ajax({ -## 案例演示 - -### 【在线Demo完整版】 -[](https://xiangyuecn.gitee.io/recorder/) https://xiangyuecn.gitee.io/recorder/ -> `github.io`可访问性太不尽人意,所以使用`gitee.io`镜像库的速度快多了。 - - -### 【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. [【Demo库】【文件合并】-mp3多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.mp3_merge) -7. [【Demo库】【文件合并】-wav多个片段文件合并](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.merge.wav_merge) -8. [【教程】实时多路音频混音](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.mix_multiple) -9. [【教程】变速变调音频转换](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform) -10. [【教程】DTMF(电话拨号按键信号)解码、编码](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.dtmf.decode_and_encode) -11. [【Demo库】PCM采样率提升](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=lib.samplerate.raise) -12. [【测试】音频可视化相关扩展测试](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization) -#### 【祝福贺卡助手】 -使用到这个库用于祝福语音的录制,已开通网页版和微信小程序版。专门针对IOS的微信中进行了兼容处理,IOS上微信环境中调用的微信的api(小程序、公众号api)。小程序地址:[](https://jiebian.life/t/a);网页地址:[](https://jiebian.life/t/a) -#### 【注】 -如果你的项目用到了这个库也想展示到这里,可以发个isuse,注明使用介绍和访问方式,我们收录在这里。 +[​](?) +[​](?) +[​](?) # :open_book:知识库 @@ -302,7 +344,7 @@ $.ajax({ **特别注**:低版本`IOS(11.X、12.X、13.X)`上只有`Safari`支持`getUserMedia`,低版本IOS上其他浏览器均不支持,唯一有点卵用的Safari `getUserMedia` 底层实现bug奇多(严重关切他们团队水准,临时工少发工资了吧),参考下面的已知问题。 -**特别注**:大部分国产手机厂商的浏览器(系统浏览器,都用的UC内核?)虽然支持`getUserMedia`方法,但并不能使用,表现为直接返回拒绝或者干脆没有任何回调;UC系列目测全部阵亡(含支付宝)。 +**特别注**:大部分2021年以前的老旧国产手机自带的浏览器(系统浏览器)虽然支持`getUserMedia`方法,但并不能使用,表现为直接返回拒绝或者干脆没有任何回调;UC系列目测全部阵亡(含支付宝)。 **留意中途来电话**:在移动端录音时,如果录音中途来电话,或者通话过程中打开录音,是不一定能进行录音的;经过简单测试发现,IOS上Safari将暂停返回音频数据,直到通话结束才开始继续有音频数据返回;小米上Chrome不管是来电还是通话中开始录音都能对麦克风输入的声音进行录音(听筒中的并不能录到,扬声器外放的会被明显降噪);只是简单测试,更多机器和浏览器并未做测试,不过整体上来看来电话或通话中进行录音的可行性并不理想,也不赞成在这种过程中进行录音;但只要通话结束后录音还是会正常进行,影响基本不大。 @@ -353,6 +395,13 @@ IOS其他浏览器|IOS 14.3+|IOS 14.3+ +[​](?) + +[​](?) + +[​](?) + + # :open_book:方法文档 ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_caller.png) @@ -382,6 +431,16 @@ set={ //注意,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提出。 @@ -401,11 +460,11 @@ set={ 注意:此方法回调是可能是同步的(异常、或者已持有资源时)也可能是异步的(浏览器弹出权限请求时);一般使用时打开,用完立即关闭;可重复调用,可用来测试是否能录音。 -另外:因为此方法会调起用户授权请求,如果仅仅想知道浏览器是否支持录音(比如:如果浏览器不支持就走另外一套录音方案),应使用`Recorder.Support()`方法。 +另外:麦克风录音时,因为此方法会调起用户授权请求,如果仅仅想知道浏览器是否支持录音(比如:如果浏览器不支持就走另外一套录音方案),应使用`Recorder.Support()`方法。 **注意:打开录音后,如果未调用close关闭,可能会影响audio音频的播放,表现为移动端audio播放有明显的杂音(麦克风的电流音?),因此如果你录音后有别的操作,尽量录完音就立即调用close关闭录音。** -> **特别注**: 鉴于UC系浏览器(大部分国产手机厂商系统浏览器)大概率表面支持录音但永远不会有任何回调、或者此浏览器支持第三种情况(用户忽略 并且 此浏览器认为此种情况不需要回调 并且程序员完美实现了);如果当前环境是移动端,可以在调用此方法`8秒`后如果未收到任何回调,弹出一个自定义提示框(只需要一个按钮),提示内容范本:`录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~`,按钮文本:`忽略`;当用户点击了按钮,直接手动执行`fail`逻辑,因为此时浏览器压根就没有弹移动端特有的模态话权限请求对话框;但如果收到了回调(可能是同步的,因此弹框必须在`rec.open`调用前准备好随时取消),需要把我们弹出的提示框自动关掉,不需要用户做任何处理。pc端的由于不是模态化的请求对话框,可能会被用户误点,所以尽量要判断一下是否是移动端。 +> **特别注**: 鉴于UC系浏览器(大部分老旧国产手机厂商系统浏览器)大概率表面支持录音但永远不会有任何回调、或者此浏览器支持第三种情况(用户忽略 并且 此浏览器认为此种情况不需要回调 并且程序员完美实现了);如果当前环境是移动端,可以在调用此方法`8秒`后如果未收到任何回调,弹出一个自定义提示框(只需要一个按钮),提示内容范本:`录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~`,按钮文本:`忽略`;当用户点击了按钮,直接手动执行`fail`逻辑,因为此时浏览器压根就没有弹移动端特有的模态话权限请求对话框;但如果收到了回调(可能是同步的,因此弹框必须在`rec.open`调用前准备好随时取消),需要把我们弹出的提示框自动关掉,不需要用户做任何处理。pc端的由于不是模态化的请求对话框,可能会被用户误点,所以尽量要判断一下是否是移动端。 `success`=fn(); @@ -415,7 +474,7 @@ set={ ### 【方法】rec.close(success) 关闭释放录音资源,释放完成后会调用`success()`回调。如果正在录音或者stop调用未完成前调用了close将会强制终止当前录音。 -注意:如果创建了多个Recorder对象并且调用了open(应避免同时有多个对象进行了open),只有最后一个新建的才有权限进行实际的资源释放(和多个对象close调用顺序无关),浏览器或设备的系统才会不再显示正在录音的提示。 +注意:麦克风录音时,如果创建了多个Recorder对象并且调用了open(应避免同时有多个对象进行了open),只有最后一个新建的才有权限进行实际的资源释放(和多个对象close调用顺序无关),浏览器或设备的系统才会不再显示正在录音的提示。 ### 【方法】rec.start() 开始录音,需先调用`open`;未close之前可以反复进行调用开始新的录音。 @@ -493,7 +552,7 @@ function transformOgg(pcmData){ 判断浏览器是否支持录音,随时可以调用。注意:仅仅是检测浏览器支持情况,不会判断和调起用户授权(rec.open()会判断用户授权),不会判断是否支持特定格式录音。 ### 【静态方法】Recorder.IsOpen() -由于Recorder持有的录音资源是全局唯一的,可通过此方法检测是否有Recorder已调用过open打开了录音功能。 +由于Recorder持有的麦克风录音资源是全局唯一的,可通过此方法检测是否有Recorder已调用过open打开了麦克风录音功能。 ### 【静态方法】Recorder.Destroy() 销毁已持有的所有全局资源(AudioContext、Worker),当要彻底移除Recorder时需要显式的调用此方法。大部分情况下不调用Destroy也不会造成问题。 @@ -504,12 +563,14 @@ function transformOgg(pcmData){ 设置为空字符串后将不参与统计,大部分情况下无需关闭统计,如果你网页的url私密性要求很高,请在调用Recorder之前将此url设为空字符串;本功能于2019-11-09添加,[点此](https://www.51.la/?20469973)前往51la查看统计概况。 ### 【静态属性】Recorder.BufferSize -录音时的AudioContext缓冲大小,默认值为4096。会影响H5录音时的onProcess调用速率,相对于AudioContext.sampleRate=48000时,4096接近12帧/s,调节此参数可生成比较流畅的回调动画。 +麦克风录音时全局的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) @@ -556,20 +617,29 @@ function transformOgg(pcmData){ `pcmLength`: pcm长度 -# :open_book:压缩合并一个自己需要的js文件 -可参考/src/package-build.js中如何合并的一个文件,比如mp3是由`recorder-core.js`,`engine/mp3.js`,`engine/mp3-engine.js`组成的。 -除了`recorder-core.js`其他引擎文件都是可选的,可以把全部编码格式合到一起也,也可以只合并几种,然后就可以支持相应格式的录音了。 -可以修改/src/package-build.js后,在src目录内执行压缩: -``` javascript -cnpm install -npm start -``` + + + + +[​](?) + +[​](?) + +[​](?) + # :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) @@ -620,6 +690,19 @@ Recorder({type:"aac"}) ``` + + + + + + +[​](?) + +[​](?) + +[​](?) + + # :open_book:扩展 在`src/extensions`目录内为扩展支持库,这些扩展库默认都没有合并到生成代码中,需单独引用(`dist`或`src`中的)才能使用。 @@ -766,6 +849,77 @@ set={ 输入音频数据,更新直方图显示。pcmData `[Int16,...]` 一维数组,为当前的录音数据片段,其他参数和`onProcess`回调相同。 + +## `BufferStreamPlayer`扩展 +[buffer_stream.player.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/buffer_stream.player.js),15kb大小源码,实时播放录音片段文件,把片段文件转换成MediaStream流,[参考此demo片段在线测试使用](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.realtime.decode_buffer_stream_player)。 + +BufferStreamPlayer可以通过input方法一次性输入整个音频文件,或者实时输入音频片段文件,然后播放出来;输入支持格式:pcm、wav、mp3等浏览器支持的音频格式,非pcm格式会自动解码成pcm(播放音质效果比pcm、wav格式差点);输入前输入后都可进行处理要播放的音频,比如:混音、变速、变调;输入的音频会写入到内部的MediaStream流中,完成将连续的音频片段文件转换成流。 + +### 可以用于 +1. Recorder onProcess等实时处理中,将实时处理好的音频片段转直接换成MediaStream,此流可以作为WebRTC的local流发送到对方,或播放出来; +2. 接收到的音频片段文件的实时播放,比如:WebSocket接收到的录音片段文件播放、WebRTC remote流(Recorder支持对这种流进行实时处理)实时处理后的播放。 + +### BufferStreamPlayer文档 +``` javascript +//【构造初始化】 +var stream=Recorder.BufferStreamPlayer({ + play:true //要播放声音,设为false不播放,只提供MediaStream + ,realtime:true /*默认为true实时模式,设为false为非实时模式 + 实时模式: + 如果有新的input输入数据,但之前输入的数据还未播放完,如果积压的数据量过大则积压的数据将会被直接丢弃,少量积压会和新数据一起加速播放,最终达到尽快播放新输入的数据的目的;这在网络不流畅卡顿时会发挥很大作用,可有效降低播放延迟 + 非实时模式: + 连续完整的播放完所有input输入的数据,之前输入的还未播放完又有新input输入会加入队列排队播放,比如用于:一次性同时输入几段音频完整播放 + */ + + //,onInputError:fn(errMsg, inputIndex) //当input输入出错时回调,参数为input第几次调用和错误消息 + + //,decode:false //input输入的数据在调用transform之前是否要进行一次音频解码成pcm [Int16,...] + //mp3、wav等都可以设为true,会自动解码成pcm + + //transform:fn(inputData,sampleRate,True,False) + //将input输入的data(如果开启了decode将是解码后的pcm)转换处理成要播放的pcm数据;如果没有解码也没有提供本方法,input的data必须是[Int16,...]并且设置set.sampleRate + //inputData:any input方法输入的任意格式数据,只要这个转换函数支持处理 + //sampleRate:123 如果设置了decode为解码后的采样率,否则为set.sampleRate || null + //True([Int16,...],sampleRate) 回调处理好的pcm数据和pcm的采样率 + //False(errMsg) 处理失败回调 + + //sampleRate:16000 //可选input输入的数据默认的采样率,当没有设置解码也没有提供transform时应当明确设置采样率 +}); + +//创建好后第一件事就是start打开流,打开后就会开始播放input输入的音频 +stream.start(()=>{ + //如果不要默认的播放,可以设置set.play为false,这种情况下只拿到MediaStream来用 + stream.getMediaStream() //通过getMediaStream方法得到MediaStream流,此流可以作为WebRTC的local流发送到对方,或者自己拿来作为audio.srcObject来播放(有提供更简单的getAudioSrc方法);未start时调用此方法将会抛异常 + + stream.getAudioSrc() //得到MediaStream流的字符串播放地址,可赋值给audio标签的src,直接播放音频;未start时调用此方法将会抛异常 +},(errMsg)=>{ + //start失败,无法播放 +}); + +//随时都能调用input,会等到start成功后播放出来,不停的调用input,就能持续的播放出声音了,需要暂停播放就不要调用input就行了 +stream.input(anyData); + +//不要播放了就调用stop停止播放,关闭所有资源 +stream.stop(); +``` + +### 【方法】stream.input(anyData) +输入任意格式的音频数据,未start前调用会等到start成功后生效。 +``` +anyData: any 具体类型取决于: + set.decode为false时: + 未提供set.transform,数据必须是pcm[Int16,...],此时的set必须提供sampleRate; + 提供了set.transform,数据为transform方法支持的任意格式。 + set.decode为true时: + 数据必须是ArrayBuffer,会自动解码成pcm[Int16,...];注意输入的每一片数据都应该是完整的一个音频片段文件,否则可能会解码失败。 + +关于anyData的二进制长度: + 如果是提供的pcm、wav格式数据,数据长度对播放无太大影响,很短的数据也能很好的连续播放。 + 如果是提供的mp3这种必须解码才能获得pcm的数据,数据应当尽量长点,测试发现片段有300ms以上解码后能很好的连续播放,低于100ms解码后可能会有明显的杂音,更低的可能会解码失败;当片段确实太小时,可以将本来会多次input调用的数据缓冲起来,等数据量达到了300ms再来调用一次input,能比较显著的改善播放音质。 +``` + + + ## `Sonic`扩展 [sonic.js](https://github.com/xiangyuecn/Recorder/blob/master/src/extensions/sonic.js),37kb大小源码(压缩版gzip后4.5kb),音频变速变调转换,[参考此demo片段在线测试使用](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=teach.sonic.transform)。此扩展从[Sonic.java](https://github.com/waywardgeek/sonic/blob/71c51195de71627d7443d05378c680ba756545e8/Sonic.java)移植,并做了适当精简。 @@ -842,8 +996,8 @@ sonic.flush(callback) //callback:fn(pcm),和同步方法相同,只是返回 prevIs:"" "":null {}:match 上次疑似检测到了什么 totalLen:0 总采样数,相对4khz pcm:[Int16,...] 4khz pcm数据 - - //可额外配置值,如:DTMF_Decode(.., .., prevChunk||{checkFactor:2}) + + //可额外配置值,如:DTMF_Decode(.., .., prevChunk||{checkFactor:2}) checkFactor:3 信号检查因子,取值1,2,3,默认为3不支持低于32ms的按键音检测,当需要检测时可以设为2,当信号更恶劣时设为1,这样将会减少检查的次数,导致错误识别率变高 debug:false 是否开启调试日志 } @@ -887,12 +1041,44 @@ EncodeMix对象: + + + + +[​](?) + +[​](?) + +[​](?) + + +# :open_book:压缩合并一个自己需要的js文件 +可参考/src/package-build.js中如何合并的一个文件,比如mp3是由`recorder-core.js`,`engine/mp3.js`,`engine/mp3-engine.js`组成的。 + +除了`recorder-core.js`其他引擎文件都是可选的,可以把全部编码格式合到一起也,也可以只合并几种,然后就可以支持相应格式的录音了。 + +可以修改/src/package-build.js后,在src目录内执行压缩: +``` javascript +cnpm install +npm start +``` + # :open_book:兼容性 对于支持录音的浏览器能够正常录音并返回录音数据;对于不支持的浏览器,引入js和执行相关方法都不会产生异常,并且进入相关的fail回调。一般在open的时候就能检测到是否支持或者被用户拒绝,可在用户开始录音之前提示浏览器不支持录音或授权。 + + + +[​](?) + +[​](?) + +[​](?) + + # :open_book:Android Hybrid App中录音示例 在Android Hybrid App中使用本库来录音,需要在App源码中实现以下两步分: @@ -933,6 +1119,15 @@ IOS 11.0-14.2:纯粹的H5录音在IOS WebView中是不支持的,需要有Nat + + +[​](?) + +[​](?) + +[​](?) + + # :open_book:语音通话聊天demo:实时编码、传输与播放验证 在[线测试Demo](https://xiangyuecn.gitee.io/recorder/)中包含了一个语音通话聊天的测试功能,没有服务器支持所以仅支持局域网内一对一语音。用两个设备(浏览器打开两个标签也可以)打开demo,勾选H5版语音通话聊天,按提示交换两个设备的信息即可成功进行P2P连接,然后进行语音。实际使用时数据传输可以用WebSocket,会简单好多。 @@ -957,6 +1152,15 @@ IOS 11.0-14.2:纯粹的H5录音在IOS WebView中是不支持的,需要有Nat ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_pcm_tool.png) + + + +[​](?) + +[​](?) + +[​](?) + # :open_book:关于微信JsSDK和RecordApp 微信内浏览器他家的[JsSDK](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)也支持录音,涉及笨重难调的公众号开发(光sdk初始化就能阻碍很多新奇想法的产生,signature限制太多),只能满足最基本的使用(大部分情况足够了)。获取音频数据必须绕一个大圈:录好音了->上传到微信服务器->自家服务器请求微信服务器多进行媒体下载->保存录音(微信小程序以前也是二逼路子,现在稍微好点能实时拿到录音mp3数据)。 diff --git a/app-support-sample/index.html b/app-support-sample/index.html index bdbb17e..17df85f 100644 --- a/app-support-sample/index.html +++ b/app-support-sample/index.html @@ -183,7 +183,7 @@