微信小程序实现录音格式为mp3,并上传到云开发环境

微信小程序中可以实现录音的主要有wx.startRecord()和wx.getRecorderManager(),其中wx.startRecord()从微信开发者工具基础库1.6后停止维护,开始启用更加强大的wx.getRecorderManager()。

前言

微信小程序中可以实现录音的主要有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-sound>
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\' >
 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\' >
 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-sound>
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 }

样式借鉴下就好了。