前言
在开发小程序过程中,有一个实现录音功能并播放录音,将录音上传至服务器的需求。开发过程中使用了Taro框架,录音功能通过Taro.getRecorderManager()接口实现,上传录音至服务器通过Taro.uploadFile接口实现,播放录音使用Taro.createInnerAudioContext()接口实现。下面就详细介绍整个流程是如何实现的。
小程序录音
首先获取录音管理器模块:
- const recorderManager = Taro.getRecorderManager();
在组件挂载完毕时注册录音监听事件:
- useEffect(() => {
- // 监听录音开始
- recorderManager.onStart(() => {
- console.log('开始录音');
- });
- // 监听录音暂停
- recorderManager.onPause(() => {
- console.log('暂停录音');
- });
- // 监听录音继续
- recorderManager.onResume(() => {
- console.log('继续录音');
- });
- // 监听录音停止
- recorderManager.onStop((res) => {
- if (res.duration < 1000) {
- Taro.showToast({
- title: '录音时间太短',
- duration: 1000,
- icon: 'none',
- });
- } else {
- console.log('停止录音');
- fileUpload(res.tempFilePath);
- }
- });
-
- recorderManager.onError(() => {
- Taro.showToast({
- title: '录音失败!',
- duration: 1000,
- icon: 'none',
- });
- });
- }, []);
-
在录音onStop的回调函数中,我们可以获取到录音的临时地址res.tempFilePath,但这个地址是有有效期限的,所以我们需要将这个录音上传至服务器后台,进行保存,后续才能正常使用。
onStop回调函数中我们调用了fileUpload函数实现文件上传,fileUpload函数的实现如下:
- const fileUpload = (tempFilePath) => {
- Taro.uploadFile({
- url: 'http://127.0.0.1:7001/record', // 服务器地址
- filePath: tempFilePath,
- name: 'file', // 这个随便填
- header: {
- 'content-type': 'multipart/form-data', // 格式必须是这个
- Authorization: Taro.getStorageSync('token'),
- },
- // formData用于传输除文件以外的一些信息
- formData: {
- record_name: '朗诵作品',
- poem_id: poemInfo.id,
- category: poemInfo.category,
- },
- success: (res) => {
- console.log(res);
- const url = res.data;
- playAudio(url); // 播放录音
- },
- fail: (error) => {
- console.log('failed!');
- console.error(error);
- },
- });
- };
需要注意的点是:header中的content-type必须是multipart/form-data。
录音事件的处理
第一次点击handleClick就会触发开始录音,之后会通过当前状态判断是暂停录音还是继续录音。handleComplete用于停止录音。
- const handleClick = () => {
- const curPause = pause;
- setPause(!curPause);
-
- if (firstRecord) {
- setfirstRecord(false);
-
- recorderManager.start({
- duration: 60000,
- sampleRate: 44100,
- numberOfChannels: 1,
- encodeBitRate: 192000,
- format: 'mp3',
- frameSize: 50,
- });
-
- Taro.showToast({
- title: '开始录音',
- duration: 1000,
- icon: 'none',
- });
-
- } else {
- if (curPause) {
- recorderManager.pause(); // 暂停录音
- } else {
- recorderManager.resume(); // 继续录音
- }
- }
- };
-
- const handleComplete = () => {
- recorderManager.stop(); // 停止录音
- };
后台实现录音存储并返回录音地址
网上大多数博客都没有涉及这块内容,下面就介绍一下如何实现,后台框架我用的是阿里的egg.js。
文件上传需要配置的东西可见官方文档:egg.js文件上传。我们这里使用它的第一种File模式来实现。
因为egg.js框架内置了Multipart插件,可以解析上传的multipart/form-data类型的数据。
首先,现在配置文件config.default.js中写入multipart配置:
- module.exports = (app) => {
- const config = (exports = {});
-
- ...
-
- config.multipart = {
- mode: 'file',
- fileSize: '50mb',
- }
- ...
-
- return {
- ...config,
- ...userConfig,
- };
- };
-
然后,在router.js中定义路由:
- // 提交录音
- router.post('/record', auth, controller.record.postRecord);
-
- 在controller目录下定义record.js文件写入如下内容:
- const Controller = require('egg').Controller;
-
- class RecordController extends Controller {
- async postRecord() {
- const { ctx } = this;
- const file = ctx.request.files[0];
- const { record_name, poem_id, category } = ctx.request.body;
-
- const res = await ctx.service.record.postRecord(file, record_name, poem_id, category);
-
- ctx.body = res;
- }
- }
-
- module.exports = RecordController;
-
在service目录下定义record.js写入具体实现:
- const Service = require('egg').Service;
- let OSS = require('ali-oss');
-
- let aliInfo = {
- // https://help.aliyun.com/document_detail/31837.html
- region: 'oss-cn-guangzhou',
- bucket: 'poem-mini-program',
- accessKeyId: 'xxx', // 填入阿里云的accessKeyId
- accessKeySecret: 'xxx', // 填入阿里云的accessKeySecret
- };
-
- let client = new OSS(aliInfo);
-
- class RecordService extends Service {
- async postRecord(file, record_name, poem_id, category) {
- const url = await this.uploadOSS(file);
- await this.updateRecord(url, record_name, poem_id, category);
-
- return url;
- }
-
- async uploadOSS(file) {
- const { ctx } = this;
-
- let result;
- try {
- // 处理文件,比如上传到云端
- result = await client.put(file.filename, file.filepath);
- } finally {
- // 需要删除临时文件
- await ctx.cleanupRequestFiles();
- }
- return result.url;
- }
-
- async updateRecord(url, record_name, poem_id, category) {
- const { ctx } = this;
-
- console.log('从ctx.locals中取openid');
- console.log(ctx.locals.openid);
- const openid = ctx.locals.openid;
-
- // 将用户信息记录到数据库中
- const res = await ctx.model.Record.create({
- record_name: record_name,
- record_url: url,
- poem_id: poem_id,
- category: category,
- openid: openid,
- });
- }
- }
- module.exports = RecordService;
这里需要注意的是:
- 需要注册阿里云账号,并在对象存储那里新建一个存储桶用于存放音频,也就是云存储的实现。
- 需要安装ali-ossnpm包,用于连接阿里云对象存储。在后台接收到前端上传的临时文件后,就会将音频上传至阿里云对象存储中(client.put)。
播放录音
细心的小伙伴可以注意到在使用Taro.uploadFile接口上传录音后,在success回调中调用了playAudio函数用于播放音频,接下来讲一下播放音频是如何实现的。
首先,使用Taro.createInnerAudioContext获取audio的上下文对象:
- const innerAudioText = Taro.createInnerAudioContext();
和录音一样,在组件挂载完成时,注册监听事件:
- useEffect(() => {
- innerAudioText.onPlay(() => {
- console.log('开始播放');
- });
-
- innerAudioText.onError((e) => {
- console.log('播放异常');
- console.log(e);
- });
- }, []);
-
在录音文件上传成功后,调用playAudio方法用于播放录音:
- const playAudio = (url) => {
- innerAudioText.autoplay = true;
- innerAudioText.src = url;
- };
在src被赋予值的时候,录音就会开始播放。
总结
到此这篇关于小程序录音功能实现的文章就介绍到这了,更多相关小程序 录音内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!