Table of Contents
最近有个需求,微信小程序录音并播放。
录音
- 首先,获取全局录音管理器。
- 然后 onLoad 里面配置各种事件监听。
- 调用录音/停止 api,处理录音事件。
// 录音管理器
const recordManager = wx.getRecorderManager()
Page({
data: {
voiceReportInfo: '', // 工单详情语音 url
voiceSeconds: 0, // 语音时间
recordStatus: '', // ready, recording
recordConfig: {
// 录音配置
duration: 600000,
sampleRate: 44100,
numberOfChannels: 1,
encodeBitRate: 192000,
frameSize: 50,
format: 'aac',
},
},
onLoad: function (options) {
recordManager.onStart((e) => this.handleRecordStart(e))
recordManager.onStop((e) => this.handleRecordStop(e))
recordManager.onError((e) => this.handleRecordError(e))
},
/**
* 开始录音
*/
startRecord() {
console.log('touchStart')
const { recordStatus } = this.data
if (recordStatus === 'recording') return
if (!recordStatus) {
const _self = this
wx.getSetting({
success(res) {
if (!res.authSetting['scope.record']) {
wx.authorize({
scope: 'scope.record',
success() {
_self.setData({
recordStatus: 'ready',
})
console.log('ready')
recordManager.start(_self.data.recordConfig)
},
fail() {
wx.showToast({
title: '未授权',
icon: 'none',
})
},
})
} else {
_self.setData({
recordStatus: 'ready',
})
console.log('ready')
recordManager.start(_self.data.recordConfig)
}
},
fail() {
wx.showToast({
title: '抱歉,目前无法录音',
icon: 'none',
})
},
})
} else {
this.setData({
recordStatus: 'ready',
})
console.log('ready')
recordManager.start(this.data.recordConfig)
}
},
/**
* 结束录音
*/
endRecord() {
console.log('touchEnd')
const { recordStatus } = this.data
if (recordStatus === 'ready' || !recordStatus) return
recordManager.stop()
},
/**
* 开始录音事件
*/
handleRecordStart() {
console.log('start')
this.setData({
recordStatus: 'recording',
})
},
/**
* 结束录音事件
*/
handleRecordStop(e) {
const { tempFilePath, duration } = e
if (tempFilePath) {
// 把音频上传到云服务器
uploadFile({
url: config.uploadUrl,
filePath: tempFilePath,
})
.then((res) => {
if (res[0].success && res[0].result) {
this.setData({
voiceReportInfo: res[0].result,
voiceSeconds: Math.round(duration / 1000),
})
} else {
wx.showToast({
title: '上传失败',
icon: 'none',
})
}
this.setData({
recordStatus: 'ready',
})
})
.catch((e) => {
wx.showToast({
title: e.message || '上传失败',
icon: 'none',
})
this.setData({
recordStatus: 'ready',
})
})
}
},
/**
* 录音出错
*/
handleRecordError(e) {
console.log(e)
},
})
播放音频
为了方便复用,播放音频封装成了组件。内部处理和在页面里写差不多。
- 创建音频上下文。
- 监听音频地址,监听相关事件。
- 播放/暂停处理。
// components/audio-player/index.js
// 音频上下文
const innerAudioContext = wx.createInnerAudioContext()
Component({
/**
* 组件的属性列表
*/
properties: {
src: String,
duration: Number,
},
/**
* 组件的初始数据
*/
data: {
isPlaying: false,
},
observers: {
src: function (value) {
if (typeof value === 'string' && value) {
innerAudioContext.src = value
// innerAudioContext.onCanplay((e) => this.handleAudioCanplay(e))
innerAudioContext.onPlay((e) => this.handleAudioPlay(e))
innerAudioContext.onPause((e) => this.handleAudioPause(e))
innerAudioContext.onStop((e) => this.handleAudioPause(e))
innerAudioContext.onEnded((e) => this.handleAudioPause(e))
innerAudioContext.onError((e) => this.handleAudioError(e))
} else {
innerAudioContext.src = ''
}
},
},
/**
* 组件的方法列表
*/
methods: {
/**
* 播放音频
*/
playAudio() {
const { isPlaying } = this.data
if (isPlaying) {
innerAudioContext.pause()
} else {
innerAudioContext.play()
}
},
/**
* 音频播放成功
*/
handleAudioPlay() {
console.log('play: ', innerAudioContext)
this.setData({
audioPlay: true,
})
},
/**
* 音频播放暂停
*/
handleAudioPause() {
console.log('pause')
this.setData({
audioPlay: false,
})
},
/**
* 音频播放失败
*/
handleAudioError(e) {
console.log(e)
wx.showToast({
title: '播放失败',
icon: 'none',
})
},
},
})
本来是准备在 onCanplay 事件里获取音频时长的,但获取到的都是 0。所以还是用的录音时记录的时长。
小程序的摸索总是比 web 坎坷。