微信小程序录音上传php代码,微信小程序实现语音录制,上传,播放

记录技术,分享技术,做个伟大的搬运工。

框架选用

开发微信小程序,使用的是unapp。 为什么要选用这个,因为他比较成熟,之前用过mpvue,kbone都是特别的不太成熟。后来经过各种选型选定了uniapp。

遇到的问题

录音授权。

长按录音,判断手指是否划出长按的区域

文件上传。

多录制语音播放。

初始化工作

定义全局录音对象和audio对象,并且格式化自己想要的音频格式

const recorderManager = uni.getRecorderManager(); // 创建录音对象

const audioContext = wx.createInnerAudioContext(); // 创建audio对象

const options = {

duration: 600000, //指定录音的时长,单位 ms,最大为10分钟(600000),默认为1分钟(60000)

sampleRate: 16000, //采样率

numberOfChannels: 1, //录音通道数

encodeBitRate: 96000, //编码码率

format: 'mp3', //音频格式,有效值 aac/mp3 等

frameSize: 50 //指定帧大小,单位 KB

};

录音授权

录音收取主要从两个方面考虑

申请授权用户直接同意授权

用户拒绝授权后,打开设置,用户收到授权。

uni.authorize({

scope: 'scope.record',

success() {

// 用户已经同意授权,可以进行录音

},

fail() {

// 此处用户授权失败,需要打开设置,去手动授权。 在某些情况下openSetting无法打开

// 可以通过fail的方式,通过弹窗用户打开设置。

uni.openSetting({

success: res => {

// 没有授权的情况下,弹窗提示

if (!res.authSetting['scope.record']) {

//未设置录音授权

uni.showModal({

title: '提示',

content: '您未授权录音,功能将无法使用',

showCancel: false

});

} else {

// 第二次才成功授权

// 用户已经同意授权,可以进行录音

}

},

fail: function() {

uni.showModal({

title: '提示',

content: '您未授权录音,功能将无法使用',

showCancel: false,

success: function(res) {

uni.openSetting();

}

});

}

});

}

});

长按录音 / 滑动区域 / 停止长按

uniapp中的方法

@longpress 长按(手指触摸超过350ms)

@longtap 长按

@tap 点击

@touchcancel 手指触摸被打断,如来电提醒,弹窗

@touchend 手指触摸动作结束,如松开按钮

@touchmove 手指触摸后移动

@touchstart 手指触摸动作开始

录制操作

获取当前点击元素距离顶部的距离

长按的同时,要开始计时,已经授权的时候要开始录制语音。

// 小程序中获取当前点击元素的距离和其他的有所不同,以下是获取的方法

const query = uni.createSelectorQuery().in(this);

query

.select('.record-button')

.boundingClientRect(data => {

// data 当前元素的各个信息

})

.exec();

通过event获取当前各项信息

滑动超出的时候要进行停止录音,并且要清空计时器。

滑回来的时候要继续录音,继续定时器。

此处需要加个中间状态,通过监听来进行继续录制录音和停止录制语音

let touches = e.touches[0];

// 超出的时候

if (touches.pageY < this.reocrdLocation.top) {

clearInterval(this.timerInfo);

recorderManager.pause();

} else {

recorderManager.resume();

}

停止长按

判断录音时长太短的话,不进行上传,

符合条件的进行上传,并且清空定时器,停止录制

recorderManager.stop();

// 监听停止事件

recorderManager.onStop(res => {

if (this.duration < 1) {

uni.showToast({

title: '录制时间太短',

duration: 1000,

icon: 'none'

});

return;

}

// 符合条件的,推进数组。

this.voiceList.push({

size: res.fileSize, // 本地的进度

progress: -1,//-1 没有上传, -100 上传失败, 100 上传成功, 0 ~ 100上传中

path: res.tempFilePath, // 线上路径

duration: this.duration // 录音时长

});

// 核对上传

this.checkUploadVoice();

});

clearInterval(this.timerInfo);

文件上传

通过设置每个录音的状态,来记录各个状态(-1 没有上传, -100 上传失败, 100 上传成功, 0 ~ 100上传中)。

上传失败可以实现重新上传。所以上传文件前,要进行核对文件(核对各个状态)。

let obj;

for (let i = 0; i < this.voiceList.length; i++) {

let item = this.voiceList[i];

if (item.progress == -1 || item.progress == -100) {

obj = await this.uploadFiles(item, i); // 等待文件上传完成后,获取信息

// 修改语音数组 通过set

this.$set(this.voiceList, i, {

name: item.name,

size: item.size,

progress: obj.progress,

path: obj.path, //

duration: item.duration,

nowPlay: false,

text: '',

translateStatus: false, // 此处记录是否转化为文字

});

this.duration = 0; // 文件上传后,时间记录要清0

}

}

// 上传文件

uploadFiles(item, i) {

return new Promise((resolve, reject) => {

const uploadTask = uni.uploadFile({

url: url, // 上传图片的地址

filePath: item.path, // 录音后拿到的地址

name: 'file',

header: {

'Content-Type': 'multipart/form-data',

accept: 'application/json'

},

success: upRes => {

console.log(upRes);

let dataInfo = JSON.parse(upRes.data);

let { code, data } = dataInfo;

// 成功后要返回成功的信息

resolve({

path: data.fileUrl,

progress: 100

});

},

fail: function(err) {

// 上传失败的时候要记录状态

resolve({

path: '',

progress: -100

});

}

});

uploadTask.onProgressUpdate(res => {

// 此处获取上传的进度,并且实时展示

this.$set(this.voiceList, {

name: item.name,

size: item.size,

progress: res.progress,

path: item.path,

duration: item.duration

});

// console.log('上传进度', res.progress);

// console.log('已经上传的数据长度', res.totalBytesSent);

// console.log(

// '预期需要上传的数据总长度',

// res.totalBytesExpectedToSend

// );

});

});

},

多条录音播放

播放的时候只保持一条正在播放(最主要的问题)

停止其他正在播放的语音

播放当前点击的语音

// 播放语音

async playVoice(item, index) {

uni.showLoading({

title: '录音播放加载中'

});

// 同时点击当前的语音两次,需要先把上一个停止到,再进行播放新的

if (item.nowPlay && this.nowPlayItem.nowPlay) {

this.stopVoice(item);

return;

}

// 两条播放的语音不一样, 停止上一条,改变播放的状态,然后播放当前的

if (!item.nowPlay && this.nowPlayItem.nowPlay) {

let status = await this.stopVoice(item);

let obj = Object.assign({}, this.nowPlayItem.item, {

nowPlay: false

});

/**

// 记录全局播放的音频(停止上次点击的音频,播放新的点击的音频,两次点击的音频不一样)

nowPlayItem: {

index: -1, // index 为当前播放的索引值

nowPlay: false, // 当前是否有正在播放的语音

item: null

},

*/

this.$set(this.voiceList, this.nowPlayItem.index, obj);

}

audioContext.src = item.path; // 播放的录音地址

audioContext.play();

this.nowPlayItem.index = index;

this.nowPlayItem.item = item;

// 开始播放监听

audioContext.onPlay(res => {

uni.hideLoading();

console.log('play');

item.nowPlay = true;

this.nowPlayItem.nowPlay = true;

});

// 停止播放监听(当前的播放是否停止)

audioContext.onPause(res => {

console.log('pause');

item.nowPlay = false;

this.nowPlayItem.nowPlay = false;

// 监听音频,要和取消监听同时存在,

audioContext.offPlay();

audioContext.offPause();

audioContext.offStop();

audioContext.offEnded();

});

// 监听音频自然播放至结束的事件,真机调试会存在问题,微信开发者工具这块不会有问题

audioContext.onEnded(res => {

console.log('ended');

item.nowPlay = false;

this.nowPlayItem.nowPlay = false;

// 监听音频,要和取消监听同时存在,

audioContext.offPlay();

audioContext.offPause();

audioContext.offStop();

audioContext.offEnded();

});

audioContext.onError(res => {

console.log('error');

// 播放音频失败的回调

console.log(res);

});

},

// 只有当前的播放停止时,才进行下一个播放开始

stopVoice(item) {

return new Promise((resolve, reject) => {

audioContext.stop();

audioContext.onStop(res => {

// 播放音频失败的回调

this.nowPlayItem.nowPlay = false;

if (item) {

item.nowPlay = false;

}

audioContext.offPlay();

audioContext.offPause();

audioContext.offStop();

audioContext.offEnded();

resolve(true);

});

});

},

此处容易出错的地方

音频监听事件要和取消事件同时存在

改变语音播放状态的时候,必须要等到上一条停止,才可以进行后续工作

总结

模拟器和真机的差别还是挺大的,真机上各个事件比模拟器会慢一点。

学海无涯,持之以恒。

本篇文章主要记录开发中遇到的问题,遇到什么问题,有什么错误,欢迎留言指正哦。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值