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

您所在的位置:网站首页 下载录音功能到手机 微信小程序实现语音录制,上传,播放

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

2023-07-23 16:04| 来源: 网络整理| 查看: 265

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

框架选用

开发微信小程序,使用的是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(); } }); } }); } }); 复制代码

官方api链接

接口调整链接

长按录音 / 滑动区域 / 停止长按 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); }); }); }, 复制代码

此处容易出错的地方

音频监听事件要和取消事件同时存在 改变语音播放状态的时候,必须要等到上一条停止,才可以进行后续工作 总结 模拟器和真机的差别还是挺大的,真机上各个事件比模拟器会慢一点。 学海无涯,持之以恒。

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3