文章目录

  • 录音、上传、播放音频微信小程序实践
    • 实践分析
      • 依赖接口
      • 录音
      • 上传
      • 播放
      • Page 事件
    • 参考

录音、上传、播放音频微信小程序实践

最近上线了一款智能外呼机器人产品,需要开发一款录音、上传、播放音频功能的
微信小程序给录音师配置外呼话术真人录音。

代码已开源,数据均已本地化处理。适合新手参考学习的完整原生微信小程序小项目。

实践分析

依赖接口

主要使用以下 api

  1. wx.getRecorderManager :获取全局唯一的录音管理器 RecorderManager
  2. wx.createInnerAudioContext : 创建内部 audio 上下文 InnerAudioContext 对象

PS.

  1. 默认 audio 组件样式不符合需求,目前只需播放进度条,InnerAudioContext 配合 process 组件实现
  2. InnerAudioContext 退出小程序自动停止播放,需要退出小程序依然可播放请使用背景音频 BackgroundAudioManager 代替

为什么要声明全局变量:

  1. 录音本身就是唯一全局
  2. 语音播放,如果每次离开、进入页面动态生成、销毁(好像有 bug),会有多条音频同时播放,为避免这个问题,使用全局唯一对象管理
const recorderManager: WechatMiniprogram.RecorderManager = wx.getRecorderManager();
const innerAudioContext: WechatMiniprogram.InnerAudioContext = wx.createInnerAudioContext();

录音

  • 录音开始配置
const recordOptions = {duration: 10 * 60 * 1000, // 最多录音时长 10 分钟sampleRate: 8000, // 采样率numberOfChannels: 1, // 1 个录音通道即可format: 'wav', // 服务端指定格式
};
recorderManager.start(recordOptions)
  • 初始状态

  • 录音检测是否收到声音,本想利用 RecorderManager.onFrameRecorded 来感知是否收到声音,
    展示波形图,但该事件不支持 wav 格式文件。目前监听到开始事件即显示录音计时。
// 监听已录制完指定帧大小的文件事件。如果设置了 frameSize,则会回调此事件。
recorderManager.onFrameRecorded(({ frameBuffer, isLastFrame }) => {console.log('frameBuffer.byteLength: ', frameBuffer.byteLength)console.log('isLastFrame: ', isLastFrame);
});
  • 监听录音开始事件,设置录音进行中状态,并展示录音计时器
recorderManager.onStart(() => {console.log('recorder start');this.startClock();this.setData({...recordingData,});
});

  • 停止录音事件,可以接收到本地录音文件地址、录音时长信息。一般上传文件至 CDN ,然后把地址存储到业务服务器,接着试听播放。
recorderManager.stop();
// 停止录音事件
recorderManager.onStop(async (res) => {console.log('recorder stop', res)// 停止后立即更新状态,以免异常this.stopClock();this.setData({...initRData,});if (isError) {isError = false;return;}const { tempFilePath, duration } = res;console.log('tempFilePath', tempFilePath);const url = await uploadFile({ filePath: tempFilePath });// 快速开始时,获取的都是未录音,会冲掉当前上传试听,这里手动设置一下if (innerAudioContext.currentTime) {innerAudioContext.stop();}innerAudioContext.src = url;this.setData({...initPlayData,...initRData,detail: {...this.data.detail,url,duration: Math.ceil(duration / 1000),},duration: formatClock(duration, true),});// await this.getDetail('CUR');
});
  • 监听录音异常、中断,录音异常千奇百怪,且无文档具体说明。
    比如电话会打断录音,触发暂停事件。拒绝授权会出发错误事件。这里都设置异常变量为 true,在 onStop 事件中不进行上传逻辑,而是恢复到录音初始状态。
// 监听录音错误事件
recorderManager.onError((err) => {this.noEffectStopRecorder();showErrMsg(msgMap[err.errMsg] || err.errMsg || '小程序错误');console.log('recorderManager.onError', err);
});// 监听录音暂停事件
recorderManager.onPause(() => {console.log('recorder pause');// 立马停止,重新开始,没有恢复机制this.noEffectStopRecorder();
});
  • 记录异常不进行业务处理并调用终止录音。这里注意录音不像播放调用 stop 是无副作用的。未开始或暂停录音调用 stop 会抛出异常。小心导致死循环。
noEffectStopRecorder() {if (this.data.isRecording) {isError = true;recorderManager.stop();}
}

上传

  • 需小程序后台配置相关业务域名
export function uploadFile({ fileName, filePath }: {fileName?: string;filePath: string;
}) {return new Promise<string>((resolve) => {wx.showLoading({title: '上传中...',});const name = fileName || filePath;// 获取 CDN tokengetNosToken({ fileName: name }).then((data) => {console.log('uploadToken: ', data);wx.uploadFile({url: 'https://nos.com/',name: 'file', // 服务器获取流的参数名filePath,formData: {Object: data.objectName,'x-nos-token': data.token,},success(res) {console.log('上传成功回调', res);wx.hideLoading();const url = `https://cdn.com/${data.objectName}`console.log(url);resolve(url);},fail(err) {wx.hideLoading();wx.showToast({title: err.errMsg,icon: 'none',});reject(err);},})});});
}

播放

  • 未播放状态

  • 监听播放开始事件,设置播放状态,且展示播放进度条
// 监听音频播放事件
innerAudioContext.onPlay(() => {console.log('开始播放');this.setData({...playingData,});
});
  • 监听音频播放进度更新事件,更新 process 百分比
// 监听音频播放进度更新事件
innerAudioContext.onTimeUpdate(() => {console.log('监听音频播放进度更新事件');let playPercent = 0;const duration = this.data.detail.duration || innerAudioContext.duration;try {playPercent = Math.ceil(((innerAudioContext.currentTime * 1000) / (duration * 1000)) * 100) || 0;} catch (e) {playPercent = 0;}playPercent = playPercent && playPercent > 100 ? 100 : playPercent;const currentTime = formatClock(innerAudioContext.currentTime * 1000, true);console.log('当前播放时间:', currentTime);console.log('微信暴露时间:', innerAudioContext.duration);console.log('后端返回时间:', duration);console.log('当前播放进度:', playPercent);this.setData({currentTime,playPercent,});
});

  • 需求不需要暂停或拖拽进度条。监听音频正常、异常停止或暂停时,都恢复到初始状态。需要恢复或拖拽进度能力,可自行相应事件中处理
// 监听音频自然播放至结束的事件
innerAudioContext.onEnded(() => {console.log('监听音频自然播放至结束的事件');this.setData({...initPlayData});
});// 监听音频播放错误事件
innerAudioContext.onError((res) => {/*** 10001  系统错误* 10002 网络错误* 10003 文件错误* 10004 格式错误* -1        未知错误*/console.log(res.errCode, res.errMsg);this.setData({...initPlayData});
});// 监听音频暂停事件
innerAudioContext.onPause(() => {console.log('监听音频暂停事件');this.setData({...initPlayData});
});// 监听音频停止事件
innerAudioContext.onStop(() => {console.log('监听音频停止事件');this.setData({...initPlayData,});
});

Page 事件

  1. 页面初次渲染完成,初始化音频录音、播放事件
  2. 页面每次重新进入加载最新业务数据
  3. 页面离开当前页面或退出小程序,停止录音、播放
/*** 生命周期函数--监听页面初次渲染完成*/
onReady() {this.initRecorder();this.initAudioPlayer();
},/*** 生命周期函数--监听页面显示*/
onShow() {this.getDetail('CUR');
},/*** 生命周期函数--监听页面卸载*/
onUnload() {console.log('切换页面停止录音或播放');innerAudioContext.stop();this.noEffectStopRecorder();
},

参考

  1. 原文地址
  2. Github 地址

录音、上传、播放音频微信小程序实践相关推荐

  1. php微信小程序多图上传,tp5实现微信小程序多图片上传到服务器功能

    最近在做一个教育类的小商城的微信小程序,用到了上传多个图片文件到服务器端,这里做一个讲解,希望对大家有所帮助. 1,小程序端: 在wxml文件中: 删除 点击上传作业 在js文件中: Page({ / ...

  2. 小程序 图片上传php后台,微信小程序图片选择、上传到服务器、预览(PHP)实现实例...

    微信小程序图片选择.上传到服务器.预览(php)实现实例 小程序实现选择图片.预览图片.上传到开发者服务器上 后台使用的tp3.2 图片上传 请求时候的header参考时可以去掉(个人后台验证权限使用 ...

  3. 微信小程序上传接口php,微信小程序API 上传、下载

    微信小程序API 上传.下载 wx.uploadFile(OBJECT) 将本地资源上传到开发者服务器.如页面通过 wx.chooseImage 等接口获取到一个本地资源的临时文件路径后,可通过此接口 ...

  4. 上传照片视频的小程序

    作为活动组织者,经常组织活动需要收集照片.收集视频,原来通过邮箱.公众号后台征集,但是很多年龄大的参与者吐糟:邮箱.公众号参与难度大,不会操作,导致参与度比较低: [Fotoo征集一下]是一个方便参与 ...

  5. 标星 2.7w+ 堪称史上最全的微信小程序开发资源汇总

    [公众号回复 "1024",免费领取程序员赚钱实操经验] 2017 年 1 月,微信小程序一夜成名. 微信小程序成名后,各大厂开始效仿,相继出现了支付宝.百度.今日头条.QQ.抖音 ...

  6. 微信小程序html5音频,微信小程序 audio音频播放详解及实例

    loop:是否循环播放 id:标注唯一组件以this.audioCtx = wx.createAudioContext('myAudio')获取控制组件的对象. bindplay:播放时触发该事件 b ...

  7. 微信小程序html5音频,微信小程序音频怎么开发?10分钟看懂(官方教程)

    想安静听歌,即使退出小程序也不会被中断: 最好还能在系统播放面板上控制小程序音频: 电话/闹钟响起时,小程序音频最好"识时务"自动暂停-- 面对用户对小程序音频能力的种种需求,开发 ...

  8. 微信小程序录音 第一篇 (基于微信小程序及百度AI的 人员语音识别转文字显示小程序)

    基于微信小程序及百度AI的 人员语音识别转文字显示小程序 基于微信小程序及百度AI的 人员语音识别转文字显示小程序主要分3篇 1.微信小程序录音篇(小程序基于wx.startRecord()微信语音录 ...

  9. 微信小程序之目前为止史上最全的微信小程序项目实例, 微信小程序实战学习

    wx-gesture-lock  微信小程序的手势密码 WXCustomSwitch 微信小程序自定义 Switch 组件模板 WeixinAppBdNovel 微信小程序demo:百度小说搜索 sh ...

最新文章

  1. 12月第三周安全要闻回顾:浏览器安全不容忽视,SSL弱点影响网站安全
  2. VDI序曲二 RemotoAPP晋级篇
  3. bps计算机,bps指的是计算机的什么
  4. TCP/IP详解--第二十章
  5. 将serversocket 写在按钮事件中连接不上_Java服务器的模型—TCP连接/流量优化
  6. ROS中阶笔记(九):Movelt!机械臂控制
  7. Pytorch 编译cpp、cuda扩展时卡在import
  8. 荣耀10 原版android,荣耀V10新内置壁纸
  9. HIVE 命令行操作和参数指引
  10. 老板口中的一区二区是什么意思?
  11. 一次成功编译Bilibili安卓播放器
  12. Internet时间自动同步后,计算机系统时间比北京时间不能同步一致
  13. python脚本迁移数据库_Django 数据库迁移脚本
  14. [易飞]付款条件-账期之理解
  15. 我们经常看到的”缺省“是什么意思
  16. 聊聊前端开发日常的协作工具(全)
  17. 【创新²】SERO超零协议项目进展双月报
  18. 工具_本地安装chatgpt,openai
  19. 如何利用MATLAB对多项式进行计算?
  20. C语言:L1-057 PTA使我精神焕发 (5 分)

热门文章

  1. ccf-csp 2015春季真题题解
  2. C语言编程入门之--第一章初识程序
  3. 暴力破解无线密码最详细教程
  4. 客运售票员_见过这样的客运售票员吗
  5. 零基础C语言入门001——编译器下载
  6. 斐波纳契数列(Fibonacci Sequence)
  7. 全面理解 Unity UI 系统
  8. java三个技术平台_java三大技术平台是什么
  9. Javascript中引用数据类型
  10. web数据库管理和运维软件 - webcat