From 3bca23571a492cf3005f9eaead0bd57587e2d046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E5=9D=9A=E6=9E=9C?= <753610399@qq.com> Date: Thu, 14 Apr 2022 09:06:26 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3=EF=BC=8C?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2README=E5=9B=BE=E7=89=87=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 27 ++++++------ app-support-sample/README.md | 12 +++--- app-support-sample/demo_android/README.md | 2 +- app-support-sample/demo_ios/README.md | 2 +- assets/npm-home/README.md | 6 ++- index.html | 50 +++++++++++------------ src/extensions/buffer_stream.player.js | 11 +++-- src/package-build.js | 18 +++++++- src/recorder-core.js | 23 +++++++++-- 9 files changed, 95 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 0d74faf..467dce2 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ [ [Android、IOS App源码](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample) ] -> [](https://xiangyuecn.gitee.io/recorder/) 扫一扫在线测试,`github.io`可访问性太不尽人意,所以使用`gitee.io`镜像库的速度快多了。 +> [](https://xiangyuecn.gitee.io/recorder/) 扫一扫在线测试,`github.io`可访问性太不尽人意,所以使用`gitee.io`镜像库的速度快多了。 [​](?) @@ -89,7 +89,7 @@ Android Demo App : 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) +使用到这个库用于祝福语音的录制,已开通网页版和微信小程序版。专门针对IOS的微信中进行了兼容处理,IOS上微信环境中调用的微信的api(小程序、公众号api)。小程序地址:[](https://jiebian.life/t/a);网页地址:[](https://jiebian.life/t/a) > 如果你的项目用到了这个库也想展示到这里,可以发个isuse,注明使用介绍和访问方式,我们收录在这里。 @@ -111,7 +111,7 @@ IOS Demo App :[下载源码](https://github.com/xiangyuecn/Recorder/tree/maste [​](?) -

Recorder logo

+

Recorder logo

Basic: @@ -329,7 +329,7 @@ $.ajax({ 欢迎加QQ群:781036591,纯小写口令:`recorder` - + @@ -415,7 +415,7 @@ IOS其他浏览器|IOS 14.3+|IOS 14.3+ # :open_book:方法文档 -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_caller.png) +![](assets/use_caller.png) ### 【构造】rec=Recorder(set) @@ -741,7 +741,7 @@ Recorder({type:"aac"}) 【附】部分扩展使用效果图([在线运行观看](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization)): -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_wave.gif) +![](assets/use_wave.gif) ## `WaveView`扩展 @@ -890,7 +890,8 @@ BufferStreamPlayer可以通过input方法一次性输入整个音频文件,或 ### 可以用于 1. Recorder onProcess等实时处理中,将实时处理好的音频片段转直接换成MediaStream,此流可以作为WebRTC的local流发送到对方,或播放出来; -2. 接收到的音频片段文件的实时播放,比如:WebSocket接收到的录音片段文件播放、WebRTC remote流(Recorder支持对这种流进行实时处理)实时处理后的播放。 +2. 接收到的音频片段文件的实时播放,比如:WebSocket接收到的录音片段文件播放、WebRTC remote流(Recorder支持对这种流进行实时处理)实时处理后的播放; +3. 单个音频文件的实时播放处理,比如:播放一段音频,并同时进行可视化绘制(其实自己解码+播放绘制比直接调用这个更有趣,但这个省事、配套功能多点)。 ### BufferStreamPlayer文档 ``` javascript @@ -922,9 +923,9 @@ var stream=Recorder.BufferStreamPlayer({ //创建好后第一件事就是start打开流,打开后就会开始播放input输入的音频 stream.start(()=>{ //如果不要默认的播放,可以设置set.play为false,这种情况下只拿到MediaStream来用 - stream.getMediaStream() //通过getMediaStream方法得到MediaStream流,此流可以作为WebRTC的local流发送到对方,或者自己拿来作为audio.srcObject来播放(有提供更简单的getAudioSrc方法);未start时调用此方法将会抛异常 + stream.getMediaStream() //通过getMediaStream方法得到MediaStream流,此流可以作为WebRTC的local流发送到对方,或者直接拿来赋值给audio.srcObject来播放(和赋值audio.src作用一致);未start时调用此方法将会抛异常 - stream.getAudioSrc() //得到MediaStream流的字符串播放地址,可赋值给audio标签的src,直接播放音频;未start时调用此方法将会抛异常 + stream.getAudioSrc() //【已过时】超低版本浏览器中得到MediaStream流的字符串播放地址,可赋值给audio标签的src,直接播放音频;未start时调用此方法将会抛异常;新版本浏览器已停止支持将MediaStream转换成url字符串,调用本方法新浏览器会抛异常,因此在不需要兼容不支持srcObject的超低版本浏览器时,请直接使用getMediaStream然后赋值给auido.srcObject来播放 },(errMsg)=>{ //start失败,无法播放 }); @@ -1174,7 +1175,7 @@ iOS 11.0-14.2:纯粹的H5录音在iOS WebView中是不支持的,需要有Nat 另外除wav外MP3等格式编码出来的音频的播放时间比PCM原始数据要长一些或短一些,如果涉及到解码或拼接时,这个地方需要注意(如果类型支持,实时处理时使用`takeoffEncodeChunk`选项可完全避免此问题)。 -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_webrtc.png) +![](assets/use_webrtc.png) # :open_book:工具:代码运行和静态分发Runtime @@ -1182,13 +1183,13 @@ iOS 11.0-14.2:纯粹的H5录音在iOS WebView中是不支持的,需要有Nat 我们不传输、不存储数据,我们只是代码的可靠搬运工。看图: -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_runtime.gif) +![](assets/use_runtime.gif) # :open_book:工具:裸(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),本工具用来对原始的PCM音频数据进行封装、播放、转码,操作极其简单,免去了动用二进制编辑工具操作的麻烦。比如加工一下Android AudioRecord(44100)采集的音频。源码在`assets/工具-裸PCM转WAV播放测试.html`; -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_pcm_tool.png) +![](assets/use_pcm_tool.png) @@ -1217,4 +1218,4 @@ iOS 11.0-14.2:纯粹的H5录音在iOS WebView中是不支持的,需要有Nat 您也可以使用支付宝或微信打赏作者: -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/donate-alipay.png) ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/donate-weixin.png) \ No newline at end of file +![](assets/donate-alipay.png) ![](assets/donate-weixin.png) \ No newline at end of file diff --git a/app-support-sample/README.md b/app-support-sample/README.md index de2b796..63905d1 100644 --- a/app-support-sample/README.md +++ b/app-support-sample/README.md @@ -193,12 +193,12 @@ function createDelayDialog(){ 欢迎加QQ群:781036591,纯小写口令:`recorder` - + ## 【截图】运行效果图 - + @@ -216,12 +216,12 @@ function createDelayDialog(){ [demo_android](https://github.com/xiangyuecn/Recorder/tree/master/app-support-sample/demo_android)目录内包含Android App测试源码,和核心文件 [RecordAppJsBridge.java](https://github.com/xiangyuecn/Recorder/blob/master/app-support-sample/demo_android/app/src/main/java/com/github/xianyuecn/recorder/RecordAppJsBridge.java) ,详细的原生实现、权限配置等请阅读这个目录内的README;目录内 [app-debug.apk.zip](https://gitee.com/xiangyuecn/Recorder/blob/master/app-support-sample/demo_android/app-debug.apk.zip) 为打包好的debug包(40kb,删掉.zip后缀),或者clone后自行用`Android Studio`编译打包。本demo为java代码,兼容API Level 15+,已测试Android 9.0。 ### 【IOS微信】H5测试 -[](https://jiebian.life/web/h5/github/recordapp.aspx) https://jiebian.life/web/h5/github/recordapp.aspx +[](https://jiebian.life/web/h5/github/recordapp.aspx) https://jiebian.life/web/h5/github/recordapp.aspx 此demo页面为代理页面([源](https://xiangyuecn.gitee.io/recorder/app-support-sample/)),受[微信JsSDK](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)的域名限制,直接在`github.io|gitee.io`上访问将导致`JsSDK`无法调用。 ### 【IOS微信】小程序WebView测试 -[](https://jiebian.life/t/a) +[](https://jiebian.life/t/a) 1. 在小程序页面内,找任意一个文本输入框,输入`::apitest`,然后点一下别的地方让输入框失去焦点,此时会提示`命令已处理`。 2. 重启小程序,会发现丑陋的控制台已经显示出来了,在控制台命令区域输入`location.href="/web/h5/github/recordapp.aspx"`并运行。 @@ -288,7 +288,7 @@ IOS其他浏览器|IOS 14.3+|IOS 14.3+ # :open_book:方法文档 -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_caller.png) +![](../assets/use_caller.png) ## 【静态方法】RecordApp.RequestPermission(success,fail) 请求录音权限,如果当前环境不支持录音或用户拒绝将调用错误回调;调用`RecordApp.Start`前需先至少调用一次此方法,用于准备好必要的环境;请求权限后如果不使用了,不管有没有调用`Start`,至少要调用一次`Stop`来清理可能持有的资源。 @@ -460,4 +460,4 @@ rec中的方法不一定都能使用,主要用来获取内部缓冲用的, 您也可以使用支付宝或微信打赏作者: -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/donate-alipay.png) ![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/donate-weixin.png) \ No newline at end of file +![](../assets/donate-alipay.png) ![](../assets/donate-weixin.png) \ No newline at end of file diff --git a/app-support-sample/demo_android/README.md b/app-support-sample/demo_android/README.md index b7bbad5..dae7103 100644 --- a/app-support-sample/demo_android/README.md +++ b/app-support-sample/demo_android/README.md @@ -14,7 +14,7 @@ ## 【截图】 -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_native_android.gif) +![](../../assets/use_native_android.gif) ## 【限制】 diff --git a/app-support-sample/demo_ios/README.md b/app-support-sample/demo_ios/README.md index 1e604ed..294e8d5 100644 --- a/app-support-sample/demo_ios/README.md +++ b/app-support-sample/demo_ios/README.md @@ -12,7 +12,7 @@ ## 【截图】 -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_native_ios.gif) +![](../../assets/use_native_ios.gif) ## 【限制】 diff --git a/assets/npm-home/README.md b/assets/npm-home/README.md index c8cef40..007b319 100644 --- a/assets/npm-home/README.md +++ b/assets/npm-home/README.md @@ -46,7 +46,7 @@ npm install recorder-core 【附】部分扩展使用效果图([在线运行观看](https://xiangyuecn.gitee.io/recorder/assets/工具-代码运行和静态分发Runtime.html?jsname=test.extensions.visualization)): -![](https://gitee.com/xiangyuecn/Recorder/raw/master/assets/use_wave.gif) +![](assets/use_wave.gif) ## WaveSurferView的调用方式 @@ -57,6 +57,10 @@ npm install recorder-core 引入`src/extensions/frequency.histogram.view.js`+`lib.fft.js`,再通过Recorder.FrequencyHistogramView调用即可,音频可视化频率直方图显示,详细的使用请参考下面详细的README。 +## BufferStreamPlayer的调用方式 +引入`src/extensions/buffer_stream.player.js`,在通过Recorder.BufferStreamPlayer调用即可,用于实时播放录音片段文件、把片段文件转换成MediaStream流,详细的使用请参考下面详细的README。 + + ## Sonic的调用方式 引入`src/extensions/sonic.js`,再通过Recorder.Sonic调用即可,音频变速变调转换,详细的使用请参考下面详细的README。 diff --git a/index.html b/index.html index 629514b..4320630 100644 --- a/index.html +++ b/index.html @@ -357,6 +357,22 @@ +

+ 启用AudioWorklet : + + +
音频采集连接方式:未启用时使用ScriptProcessor(默认),启用时使用AudioWorklet;通过设置Recorder.ConnectEnableWorklet=true启用。
+
+ 已知:AudioWorklet在一定条件下会导致某些浏览器崩溃 + 测试 + (坑已填好)。 +
+
+
+
变速变调 : @@ -385,6 +401,15 @@
+
+ 丢失补偿 : + +
issues#51如果没有进行补偿,录音时设备偶尔出现很卡的情况下(CPU被其他程序大量占用),浏览器采集到的音频是断断续续的,导致10秒的录音可能就只返回了5秒的数据量,这个时候最终编码得到的音频时长明显变短,播放时的效果就像快放一样。未禁用时会在卡顿时自动补偿静默音频,消除了快放效果,但由于丢失的音频已被静默数据代替,听起来就是数据本身的断断续续的效果。在设备不卡时录音没有此问题。
+
+
DTMF电话按键信号 : @@ -410,31 +435,6 @@
- -
- 启用AudioWorklet : - - -
音频采集连接方式:未启用时使用ScriptProcessor(默认),启用时使用AudioWorklet;通过设置Recorder.ConnectEnableWorklet=true启用。
-
- 已知:AudioWorklet在一定条件下会导致某些浏览器崩溃 - 测试 - (坑已填好)。 -
-
-
- -
- 丢失补偿 : - -
issues#51如果没有进行补偿,录音时设备偶尔出现很卡的情况下(CPU被其他程序大量占用),浏览器采集到的音频是断断续续的,导致10秒的录音可能就只返回了5秒的数据量,这个时候最终编码得到的音频时长明显变短,播放时的效果就像快放一样。未禁用时会在卡顿时自动补偿静默音频,消除了快放效果,但由于丢失的音频已被静默数据代替,听起来就是数据本身的断断续续的效果。在设备不卡时录音没有此问题。
-
测试App : diff --git a/src/extensions/buffer_stream.player.js b/src/extensions/buffer_stream.player.js index bcab683..c94cef0 100644 --- a/src/extensions/buffer_stream.player.js +++ b/src/extensions/buffer_stream.player.js @@ -7,16 +7,17 @@ BufferStreamPlayer可以通过input方法一次性输入整个音频文件,或 BufferStreamPlayer可以用于: 1. Recorder onProcess等实时处理中,将实时处理好的音频片段转直接换成MediaStream,此流可以作为WebRTC的local流发送到对方,或播放出来; - 2. 接收到的音频片段文件的实时播放,比如:WebSocket接收到的录音片段文件播放、WebRTC remote流(Recorder支持对这种流进行实时处理)实时处理后的播放。 + 2. 接收到的音频片段文件的实时播放,比如:WebSocket接收到的录音片段文件播放、WebRTC remote流(Recorder支持对这种流进行实时处理)实时处理后的播放; + 3. 单个音频文件的实时播放处理,比如:播放一段音频,并同时进行可视化绘制(其实自己解码+播放绘制比直接调用这个更有趣,但这个省事、配套功能多点)。 调用示例: var stream=Recorder.BufferStreamPlayer(set) //创建好后第一件事就是start打开流,打开后就会开始播放input输入的音频 stream.start(()=>{ //如果不要默认的播放,可以设置set.play为false,这种情况下只拿到MediaStream来用 - stream.getMediaStream() //通过getMediaStream方法得到MediaStream流,此流可以作为WebRTC的local流发送到对方,或者自己拿来作为audio.srcObject来播放(有提供更简单的getAudioSrc方法);未start时调用此方法将会抛异常 + stream.getMediaStream() //通过getMediaStream方法得到MediaStream流,此流可以作为WebRTC的local流发送到对方,或者直接拿来赋值给audio.srcObject来播放(和赋值audio.src作用一致);未start时调用此方法将会抛异常 - stream.getAudioSrc() //得到MediaStream流的字符串播放地址,可赋值给audio标签的src,直接播放音频;未start时调用此方法将会抛异常 + stream.getAudioSrc() //【已过时】超低版本浏览器中得到MediaStream流的字符串播放地址,可赋值给audio标签的src,直接播放音频;未start时调用此方法将会抛异常;新版本浏览器已停止支持将MediaStream转换成url字符串,调用本方法新浏览器会抛异常,因此在不需要兼容不支持srcObject的超低版本浏览器时,请直接使用getMediaStream然后赋值给auido.srcObject来播放 },(errMsg)=>{ //start失败,无法播放 }); @@ -75,9 +76,11 @@ var fn=function(set){ } }; fn.prototype=BufferStreamPlayer.prototype={ - /**获取MediaStream的audio播放地址,未start将会抛异常**/ + /**【已过时】获取MediaStream的audio播放地址,新版浏览器、未start将会抛异常**/ getAudioSrc:function(){ + console.warn("getAudioSrc方法已过时:请直接使用getMediaStream然后赋值给audio.srcObject,仅允许在不支持srcObject的浏览器中调用本方法赋值给audio.src以做兼容"); if(!this._src){ + //新版chrome调用createObjectURL会直接抛异常了 https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL#using_object_urls_for_media_streams this._src=(window.URL||webkitURL).createObjectURL(this.getMediaStream()); } return this._src; diff --git a/src/package-build.js b/src/package-build.js index 058329e..dd6bd99 100644 --- a/src/package-build.js +++ b/src/package-build.js @@ -123,7 +123,19 @@ function deleteFolder(path,deep){ - +function MDAbsImg(txt,baseUrl){//简单的图片地址 相对路径改成绝对路径 + return txt.replace(/\!\[\]\((.+?)\)/g,function(a,url){ + var folder=baseUrl; + if(!/^https?:/i.test(url)){ + while(/^\.\.\/(.*)$/.test(url)){ + url=RegExp.$1; + folder=folder.replace(/\/[^\/]+\/$/,"/"); + } + url=folder+url; + } + return '![]('+url+')'; + }); +}; function Run_npm(){ console.log("\x1B[33m%s\x1B[0m","制作作者需要上传的npm包文件..."); @@ -138,6 +150,10 @@ function Run_npm(){ var rootREADME=fs.readFileSync("../README.md","utf-8"); var appREADME=fs.readFileSync("../app-support-sample/README.md","utf-8"); var npmREADME=fs.readFileSync(npmHome+"/README.md","utf-8"); + rootREADME=MDAbsImg(rootREADME,"https://xiangyuecn.gitee.io/recorder/"); + appREADME=MDAbsImg(appREADME,"https://xiangyuecn.gitee.io/recorder/app-support-sample/"); + npmREADME=MDAbsImg(npmREADME,"https://xiangyuecn.gitee.io/recorder/"); + var npmPackage=fs.readFileSync(npmHome+"/package.json","utf-8"); var hashHistory=fs.readFileSync(npmHome+"/hash-history.txt","utf-8"); var versionPatch=fs.existsSync(npmHome+"/version.patch.txt")&&fs.readFileSync(npmHome+"/version.patch.txt","utf-8")||""; diff --git a/src/recorder-core.js b/src/recorder-core.js index 1c9c4e8..ed96f38 100644 --- a/src/recorder-core.js +++ b/src/recorder-core.js @@ -341,8 +341,12 @@ Recorder.SampleData=function(pcmDatas,pcmSampleRate,newSampleRate,prevChunkInfo, frameSize=option.frameType=="mp3"?1152:1; }; + var nLen=pcmDatas.length; + if(index>nLen+1){ + CLog("SampleData似乎传入了未重置chunk "+index+">"+nLen,3); + }; var size=0; - for(var i=index;i30){ + This.CLog(procTxt+"低性能,耗时"+slowT+"ms",3); + }; if(asyncBegin===true){ //开启了异步模式,onProcess已接管buffers新数据,立即清空,避免出现未处理的数据