前言
微信小程序中可以实现录音的主要有wx.startRecord()和wx.getRecorderManager(),其中wx.startRecord()从微信开发者工具基础库1.6后停止维护,开始启用更加强大的wx.getRecorderManager()。
一、关于wx.startRecord()的坑
wx.startRecord()使用还是相当容易的,微信官方示例便是使用wx.startRecord()。
1 wx.startRecord({ 2 success(res) { 3 const tempFilePath = res.tempFilePath 4 console.log(res) 5 } 6 }) 7 setTimeout(function () { 8 wx.stopRecord() // 结束录音 9 }, 3000)
成功录音的返回值为一个含有音频临时路径的对象
1 errMsg: "startRecord:ok" 2 tempFilePath: "http://tmp/wx88e053d45b28e2cf.o6zAJs-nrru-YZpqRQeb-X8EzBfk.JVhmiR78K4oY2e7522995230f041a81c5967a4e1598c.silk"
这个silk格式为加密格式,在真机上可以播放,上传到服务器以后,其它用户无法播放,只有上传者可以播放。
如果要分享给别人,得先解密,再转换为其它格式,网上的教程很多,但是比较麻烦
二、关于wx.getRecorderManager()的实战解析
有一个项目,需要使用录音,上传到云存储后,分享给其它人。
1 const recorderManager = wx.getRecorderManager() 2 const backgroundAudio = wx.getBackgroundAudioManager() 3 var util = require(\'../../utils/util.js\'); 4 Page({ 5 data: { 6 openRecordingdis: "block", //显示录机图标 7 shutRecordingdis: "none", //隐藏停止图标 8 recordingTimeqwe: 0, //录音计时 9 setInter: "", //录音名称 10 soundUrl: "" 11 }, 12 13 //录音计时器 14 recordingTimer: function() { 15 var that = this; 16 //将计时器赋值给setInter 17 that.data.setInter = setInterval( 18 function() { 19 var time = that.data.recordingTimeqwe + 1; 20 that.setData({ 21 recordingTimeqwe: time 22 }) 23 }, 1000); 24 }, 25 26 27 //开始录音 28 openRecording: function() { 29 var that = this; 30 wx.getSystemInfo({ 31 success: function(res) { 32 that.setData({ 33 shutRecordingdis: "block", 34 openRecordingdis: "none" 35 }) 36 } 37 }) 38 const options = { 39 duration: 60000, //指定录音的时长,单位 ms,最大为10分钟(600000),默认为1分钟(60000) 40 sampleRate: 16000, //采样率 41 numberOfChannels: 1, //录音通道数 42 encodeBitRate: 96000, //编码码率 43 format: \'mp3\', //音频格式,有效值 aac/mp3 44 frameSize: 50, //指定帧大小,单位 KB 45 } 46 //开始录音计时 47 that.recordingTimer(); 48 //开始录音 49 recorderManager.start(options); 50 recorderManager.onStart(() => { 51 console.log(\'。。。开始录音。。。\') 52 }); 53 //错误回调 54 recorderManager.onError((res) => { 55 console.log(res); 56 }) 57 }, 58 59 //结束录音 60 shutRecording: function() { 61 var that = this; 62 wx.getSystemInfo({ 63 success: function(res) { 64 that.setData({ 65 shutRecordingdis: "none", 66 openRecordingdis: "block" 67 }) 68 } 69 }) 70 recorderManager.stop(); 71 recorderManager.onStop((res) => { 72 const that = this 73 let timestamp = util.formatTime2(new Date()); 74 console.log(\'。。停止录音。。\', res.tempFilePath) 75 const { 76 tempFilePath 77 } = res; 78 //结束录音计时 79 clearInterval(that.data.setInter); 80 wx.cloud.uploadFile({ 81 cloudPath: "sounds/"+timestamp + \'-\' + this.randomNum(10000, 99999) + \'.mp3\', 82 filePath: tempFilePath, 83 // 成功回调 84 success: res => { 85 console.log(\'上传成功\', res) 86 that.setData({ 87 soundUrl: res.fileID, 88 // time: util.formatTime1(new Date()) 89 }) 90 }, 91 }) 92 93 }) 94 }, 95 96 //录音播放 97 recordingAndPlaying: function(eve) { 98 99 // console.log(eve) 100 var tempsound = eve.currentTarget.dataset.soundid 101 tempsound = "https://6e65-newdj-d79af2-1257790921.tcb.qcloud.la/sounds"+this.midstr(tempsound) 102 // console.log(tempsound) 103 wx.playBackgroundAudio({ 104 //播放地址 105 dataUrl: tempsound 106 }) 107 }, 108 109 //生成从minNum到maxNum的随机数 110 randomNum(minNum, maxNum) { 111 switch (arguments.length) { 112 case 1: 113 return parseInt(Math.random() * minNum + 1, 10); 114 break; 115 case 2: 116 return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10); 117 break; 118 default: 119 return 0; 120 break; 121 } 122 }, 123 midstr(str) { 124 var strnum = str.lastIndexOf(\'/\') 125 var ministr = str.substr(strnum) 126 return ministr 127 }, 128 })
1.首先声明录音组件
const recorderManager = wx.getRecorderManager()
2. 开始录音的实现
1 //开始录音 2 openRecording: function() { 3 var that = this; 4 wx.getSystemInfo({ 5 success: function(res) { 6 that.setData({ 7 shutRecordingdis: "block", 8 openRecordingdis: "none" 9 }) 10 } 11 }) 12 const options = { 13 duration: 60000, //指定录音的时长,单位 ms,最大为10分钟(600000),默认为1分钟(60000) 14 sampleRate: 16000, //采样率 15 numberOfChannels: 1, //录音通道数 16 encodeBitRate: 96000, //编码码率 17 format: \'mp3\', //音频格式,有效值 aac/mp3 18 frameSize: 50, //指定帧大小,单位 KB 19 } 20 //开始录音计时 21 that.recordingTimer(); 22 //开始录音 23 recorderManager.start(options); 24 recorderManager.onStart(() => { 25 console.log(\'。。。开始录音。。。\') 26 }); 27 //错误回调 28 recorderManager.onError((res) => { 29 console.log(res); 30 }) 31 },
3. 结束录音的实现
1 //结束录音 2 shutRecording: function() { 3 var that = this; 4 wx.getSystemInfo({ 5 success: function(res) { 6 that.setData({ 7 shutRecordingdis: "none", 8 openRecordingdis: "block" 9 }) 10 } 11 }) 12 recorderManager.stop(); 13 recorderManager.onStop((res) => { 14 const that = this 15 let timestamp = util.formatTime2(new Date()); 16 console.log(\'。。停止录音。。\', res.tempFilePath) 17 const { 18 tempFilePath 19 } = res; 20 //结束录音计时 21 clearInterval(that.data.setInter); 22 wx.cloud.uploadFile({ 23 cloudPath: "sounds/"+timestamp + \'-\' + this.randomNum(10000, 99999) + \'.mp3\', 24 filePath: tempFilePath, 25 // 成功回调 26 success: res => { 27 console.log(\'上传成功\', res) 28 that.setData({ 29 soundUrl: res.fileID, 30 // time: util.formatTime1(new Date()) 31 }) 32 }, 33 }) 34 }) 35 },
第13行,录音停止后,生成mp3格式的临时文件,以jason格式提示,包含时长,文件大小和临时文件名
1 { 2 duration: 2532 3 fileSize: 42268 4 tempFilePath: "http://tmp/wx88e053d45b28e2cf.o6zAJs-nrru-YZpqRQeb-X8EzBfk.73z3a3qIwC7yc13f32e3d179133ac77ca7851ec7d25b.durationTime=2532.mp3" 5 }
第15行,生成一个时间戳,用来生成文件名,
第22行,上传至云存储,为了避免出现同时有多个进程上传的极端情况,加了一个5位数的随机数,
第29行,上传成功后,将生成的云文件ID返给data变量soundUrl
1 { 2 errMsg: "cloud.uploadFile:ok" 3 fileID: "cloud://newdj-d79af2.6e65-newdj-d79af2-1257790921/sounds/20190731162324-40454.mp3" 4 }
4.播放云存储里的录音
1 //录音播放 2 recordingAndPlaying: function(eve) { 3 // console.log(eve) 4 var tempsound = eve.currentTarget.dataset.soundid 5 tempsound = "https://6e65-newdj-d79af2-1257790921.tcb.qcloud.la/sounds" + this.midstr(tempsound) 6 // console.log(tempsound) 7 wx.playBackgroundAudio({ 8 //播放地址 9 dataUrl: tempsound 10 }) 11 },
点击播放按钮时,把录音的云文件名传递到JS
1 <view bindtap=\'recordingAndPlaying\' data-soundid="{{soundUrl}}"> 2 <image class="progress_img" src=\'/images/play.png\'></image> 3 </view>
data-soundid--->eve.currentTarget.dataset.soundid
然后第5行,将云文件名,转换为可供真机使用的https文件,midstr(tempsound)函数是取"/"之后的文件名,
"https://6e65-newdj-d79af2-1257790921.tcb.qcloud.la/sounds",为本项目所使用云开发环境所对应的路径
将"cloud://newdj-d79af2.6e65-newdj-d79af2-1257790921/sounds"替换后即可使用。 注意标黑部分,通过对两个路径的比对,可以找到cloud://转https://的规律:
"cloud://云环境ID."===>"https://",之后再加上".tcb.qcloud.la"即可
5.生成随机数的通用函数
1 //生成从minNum到maxNum的随机数 2 randomNum(minNum, maxNum) { 3 switch (arguments.length) { 4 case 1: 5 return parseInt(Math.random() * minNum + 1, 10); 6 break; 7 case 2: 8 return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10); 9 break; 10 default: 11 return 0; 12 break; 13 } 14 },
6.取"/"右侧的字符串
midstr(str) { var strnum = str.lastIndexOf(\'/\') var ministr = str.substr(strnum) return ministr },
三、WXML的实现
1 <view class=\'progress_box\' bindtap=\'openRecording\' style="display:{{openRecordingdis}}"> 2 <view class="progress_bgs"> 3 <view class="progress_bg"> 4 <image class="progress_img" src=\'/images/record.png\'></image> 5 </view> 6 </view> 7 </view> 8 <view class=\'progress_box\' bindtap=\'shutRecording\' style="display:{{shutRecordingdis}}"> 9 <view class="progress_bgs"> 10 <view class="progress_bg"> 11 <image class="progress_img" src=\'/images/stop.png\'></image> 12 </view> 13 </view> 14 </view> 15 <view bindtap=\'recordingAndPlaying\' data-soundid="{{soundUrl}}"> 16 <image class="progress_img" src=\'/images/play.png\'></image> 17 </view>
里面的图片换成自己的,仅实现功能,没有调播放按钮的位置。
四、WXSS的实现
1 .topicRecording { 2 float: left; 3 width: 40%; 4 height: 100%; 5 position: relative; 6 } 7 8 9 .progress_box { 10 width: 130rpx; 11 height: 130rpx; 12 margin-left: -65rpx; 13 position: absolute; 14 bottom: 0; 15 left: 50%; 16 display: flex; 17 align-items: center; 18 justify-content: center; 19 background: #ccc; 20 border-radius: 50%; 21 } 22 23 .progress_bgs { 24 width: 114rpx; 25 height: 114rpx; 26 background: #fff; 27 border-radius: 50%; 28 margin: 9rpx; 29 } 30 31 .progress_bg { 32 width: 106rpx; 33 height: 106rpx; 34 margin: 5rpx; 35 position: absolute; 36 background: #444; 37 border-radius: 50%; 38 } 39 40 .progress_img { 41 width: 82rpx; 42 height: 82rpx; 43 border-radius: 50%; 44 margin: 12rpx; 45 }
样式借鉴下就好了。