123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- //必须引入的Recorder核心(文件路径是 /src/recorder-core.js 下同),使用import、require都行
- import Recorder from 'recorder-core' //注意如果未引用Recorder变量,可能编译时会被优化删除(如vue3 tree-shaking),请改成 import 'recorder-core',或随便调用一下 Recorder.a=1 保证强引用
- //必须引入的RecordApp核心文件(文件路径是 /src/app-support/app.js)
- import RecordApp from 'recorder-core/src/app-support/app'
- //所有平台必须引入的uni-app支持文件(如果编译出现路径错误,请把@换成 ../../ 这种)
- import '@/uni_modules/Recorder-UniCore/app-uni-support.js'
- import 'recorder-core/src/engine/mp3'
- import 'recorder-core/src/engine/mp3-engine' //如果此格式有额外的编码引擎(*-engine.js)的话,必须要加上
- //可选的插件支持项,把需要的插件按需引入进来即可
- import 'recorder-core/src/extensions/waveview'
- export default {
- data() {
- return {
- longPress: true, // 是否长按
- getRecord: false, // 是否获取权限
- showRecorder: false, // 是否在录音
- // isMounted
- };
- },
- onShow() {
- if (this.isMounted) RecordApp.UniPageOnShow(this);
- },
- created() {
- this.recReq()
- },
- mounted() {
- this.isMounted = true;
- //页面onShow时【必须调用】的函数,传入当前组件this
- RecordApp.UniPageOnShow(this);
- },
- methods: {
- // 长按触发
- longPressEvent() {
- // this.recReq();
- this.longPress = true;
- if (this.getRecord) {
- // 获取录音权限,直接开始录音
- this.recStart();
- } else {
- // 未获取,重新获取,参数未获取权限成功后开启录音
- this.recReq(true);
- }
- },
- // 长按结束
- longPressEnd(e) {
- e.preventDefault();
- this.longPress = false;
- try {
- this.recStop()
- } catch (e) {
- //TODO handle the exception
- }
- },
- //请求录音权限
- recReq(startRecord = false) {
- //编译成App时提供的授权许可(编译成H5、小程序为免费授权可不填写);如果未填写授权许可,将会在App打开后第一次调用请求录音权限时,弹出“未获得商用授权时,App上仅供测试”提示框
- //RecordApp.UniAppUseLicense='我已获得UniAppID=*****的商用授权';
- //RecordApp.RequestPermission_H5OpenSet={ audioTrackSet:{ noiseSuppression:true,echoCancellation:true,autoGainControl:true } }; //这个是Start中的audioTrackSet配置,在h5(H5、App+renderjs)中必须提前配置,因为h5中RequestPermission会直接打开录音
- RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
- RecordApp.RequestPermission(() => {
- // console.log("已获得录音权限,可以开始录音了");
- this.getRecord = true;
- if (startRecord) {
- // 获取之后立即录音
- this.recStart();
- } else {
- // this.recStop()
- }
- }, (msg, isUserNotAllow) => {
- this.getRecord = false;
- if (isUserNotAllow) { //用户拒绝了录音权限
- //这里你应当编写代码进行引导用户给录音权限,不同平台分别进行编写
- }
- console.error("请求录音权限失败:" + msg);
- });
- },
- //开始录音
- recStart() {
- if (!this.longPress) {
- return false
- }
- this.showRecorder = true;
- //录音配置信息
- var set = {
- type: "mp3",
- sampleRate: 16000,
- bitRate: 16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
- /*,audioTrackSet:{ //可选,如果需要同时播放声音(比如语音通话),需要打开回声消除(打开后声音可能会从听筒播放,部分环境下(如小程序、App原生插件)可调用接口切换成扬声器外放)
- //注意:H5、App+renderjs中需要在请求录音权限前进行相同配置RecordApp.RequestPermission_H5OpenSet后此配置才会生效
- echoCancellation:true,noiseSuppression:true,autoGainControl:true} */
- ,
- onProcess: (buffers, powerLevel, duration, sampleRate, newBufferIdx, asyncEnd) => {
- //全平台通用:可实时上传(发送)数据,配合Recorder.SampleData方法,将buffers中的新数据连续的转换成pcm上传,或使用mock方法将新数据连续的转码成其他格式上传,可以参考Recorder文档里面的:Demo片段列表 -> 实时转码并上传-通用版;基于本功能可以做到:实时转发数据、实时保存数据、实时语音识别(ASR)等
- //注意:App里面是在renderjs中进行实际的音频格式编码操作,此处的buffers数据是renderjs实时转发过来的,修改此处的buffers数据不会改变renderjs中buffers,所以不会改变生成的音频文件,可在onProcess_renderjs中进行修改操作就没有此问题了;如需清理buffers内存,此处和onProcess_renderjs中均需要进行清理,H5、小程序中无此限制
- //注意:如果你要用只支持在浏览器中使用的Recorder扩展插件,App里面请在renderjs中引入此扩展插件,然后在onProcess_renderjs中调用这个插件;H5可直接在这里进行调用,小程序不支持这类插件;如果调用插件的逻辑比较复杂,建议封装成js文件,这样逻辑层、renderjs中直接import,不需要重复编写
- //H5、小程序等可视化图形绘制,直接运行在逻辑层;App里面需要在onProcess_renderjs中进行这些操作
- // #ifdef H5 || MP-WEIXIN
- if (this.waveView) this.waveView.input(buffers[buffers.length - 1], powerLevel, sampleRate);
- // #endif
- },
- onProcess_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
- //App中在这里修改buffers会改变生成的音频文件,但注意:buffers会先转发到逻辑层onProcess后才会调用本方法,因此在逻辑层的onProcess中需要重新修改一遍
- //本方法可以返回true,renderjs中的onProcess将开启异步模式,处理完后调用asyncEnd结束异步,注意:这里异步修改的buffers一样的不会在逻辑层的onProcess中生效
- //App中是在renderjs中进行的可视化图形绘制,因此需要写在这里,this是renderjs模块的this(也可以用This变量);如果代码比较复杂,请直接在renderjs的methods里面放个方法xxxFunc,这里直接使用this.xxxFunc(args)进行调用
- if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
- }`,
- onProcessBefore_renderjs: `function(buffers,powerLevel,duration,sampleRate,newBufferIdx){
- //App中本方法会在逻辑层onProcess之前调用,因此修改的buffers会转发给逻辑层onProcess,本方法没有asyncEnd参数不支持异步处理
- //一般无需提供本方法只用onProcess_renderjs就行,renderjs的onProcess内部调用过程:onProcessBefore_renderjs -> 转发给逻辑层onProcess -> onProcess_renderjs
- }`
- ,
- takeoffEncodeChunk: true ? null : (chunkBytes) => {
- //全平台通用:实时接收到编码器编码出来的音频片段数据,chunkBytes是Uint8Array二进制数据,可以实时上传(发送)出去
- //App中如果未配置RecordApp.UniWithoutAppRenderjs时,建议提供此回调,因为录音结束后会将整个录音文件从renderjs传回逻辑层,由于uni-app的逻辑层和renderjs层数据交互性能实在太拉跨了,大点的文件传输会比较慢,提供此回调后可避免Stop时产生超大数据回传
- },
- takeoffEncodeChunk_renderjs: true ? null : `function(chunkBytes){
- //App中这里可以做一些仅在renderjs中才生效的事情,不提供也行,this是renderjs模块的this(也可以用This变量)
- }`
- ,
- start_renderjs: `function(){
- //App中可以放一个函数,在Start成功时renderjs中会先调用这里的代码,this是renderjs模块的this(也可以用This变量)
- //放一些仅在renderjs中才生效的事情,比如初始化,不提供也行
- }`,
- stop_renderjs: `function(arrayBuffer,duration,mime){
- //App中可以放一个函数,在Stop成功时renderjs中会先调用这里的代码,this是renderjs模块的this(也可以用This变量)
- //放一些仅在renderjs中才生效的事情,不提供也行
- }`
- };
- RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
- RecordApp.Start(set, () => {
- this.start()
- //创建音频可视化图形绘制,App环境下是在renderjs中绘制,H5、小程序等是在逻辑层中绘制,因此需要提供两段相同的代码
- //view里面放一个canvas,canvas需要指定宽高(下面style里指定了300*100)
- //<canvas type="2d" class="recwave-WaveView" style="width:300px;height:100px"></canvas>
- const w = uni.upx2px(700);
- const h = uni.upx2px(100);
- // const h = uni.upx2px(70);
- this.$nextTick(() => {
- RecordApp.UniFindCanvas(this, [".recwave-WaveView"], `
- this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:${w}, height:${h}});
- `, (canvas1) => {
- this.waveView = Recorder.WaveView({
- compatibleCanvas: canvas1,
- width: w,
- height: h
- });
- });
- })
- }, (msg) => {
- this.showRecorder = false;
- console.error("开始录音失败:" + msg);
- });
- },
- //暂停录音
- recPause() {
- if (RecordApp.GetCurrentRecOrNull()) {
- RecordApp.Pause();
- console.log("已暂停");
- }
- },
- //继续录音
- recResume() {
- if (RecordApp.GetCurrentRecOrNull()) {
- RecordApp.Resume();
- console.log("继续录音中...");
- }
- },
- //停止录音
- recStop() {
- RecordApp.Stop((arrayBuffer, duration, mime) => {
- //全平台通用:arrayBuffer是音频文件二进制数据,可以保存成文件或者发送给服务器
- //App中如果在Start参数中提供了stop_renderjs,renderjs中的函数会比这个函数先执行
- //注意:当Start时提供了takeoffEncodeChunk后,你需要自行实时保存录音文件数据,因此Stop时返回的arrayBuffer的长度将为0字节
- //如果是H5环境,也可以直接构造成Blob/File文件对象,和Recorder使用一致
- // #ifdef H5
- var blob = new Blob([arrayBuffer], { type: mime });
- const blobUrl = (window.URL || webkitURL).createObjectURL(blob);
- this.end({ tempFilePath: blobUrl })
- // console.log(blob, (window.URL || webkitURL).createObjectURL(blob));
- // var file = new File([arrayBuffer], "recorder.mp3");
- // console.log('recStop ', file);
- // this.audioUrl = (window.URL || webkitURL).createObjectURL(blob)
- //uni.uploadFile({file:file, ...}) //参考demo中的test_upload_saveFile.vue
- // #endif
- //如果是App、小程序环境,可以直接保存到本地文件,然后调用相关网络接口上传
- // // #ifdef APP || MP-WEIXIN
- // RecordApp.UniSaveLocalFile("recorder.mp3", arrayBuffer, (savePath) => {
- // console.log(
- // savePath
- // ); //app保存的文件夹为`plus.io.PUBLIC_DOWNLOADS`,小程序为 `wx.env.USER_DATA_PATH` 路径
- // //uni.uploadFile({filePath:savePath, ...}) //参考demo中的test_upload_saveFile.vue
- // }, (errMsg) => { console.error(errMsg) });
- // // #endif
- this.showRecorder = false;
- }, (msg) => {
- console.error("结束录音失败:" + msg);
- });
- }
- },
- }
|