微信小程序-录音功能分享

5,235 阅读4分钟

前言

自从前段时间开发一个小程序项目和录音这个功能邂逅之后,到今日仍久久不能忘怀。总感觉应该记录点神马,来描述我们之间的故事。说着,那就走起!

或许应该先展示下效果比较合适,嗯,没毛病!

因为为了让录音到播放以及播放暂停等各个环节效果清晰呈现,我用此替代掉了微信播放语音的那种展现形式,其实原理是一样的。那下面就对实现的过程展开轻描淡写。

API准备

  • 初始化音频管理器
    wx.getRecorderManager()
    返回 RecorderManager对象
  • 创建内部 audio 上下文对象
    wx.createInnerAudioContext()
  • 开始录音
    RecorderManager.start(Object object)
  • 停止录音
    RecorderManager.stop()
  • 监听录音结束事件
    RecorderManager.onStop(function callback)
  • 播放录音
    InnerAudioContext.play()
  • 停止播放录音(停止后的音频再播放会从头开始播放)
    InnerAudioContext.stop()
  • 监听音频自然播放至结束的事件
    InnerAudioContext.onEnded(function callback)
  • 销毁当前音频上下文实例
    innerAudioContext.destroy()
  • 其他
    获取录音权限 wx.getSetting()
    上传七牛云 qiniuUploader.upload

实现步骤

上面罗列的api都是需要用到的,顺序也基本是按照实现一个录音功能的全流程来排列的,那下面就采用贴代码的方式(最熟悉的方式)来阐述吧,对了,我用的是mpvue(vue语法)为了避免篇幅较长,核心代码片段只贴出js实现,demo完整代码请 猛戳这里 获取。

<!--recoder.vue-->
<template>
   ...
</template>
<script>
import { Base64 } from 'js-base64'; //引入安装的Base64依赖包,不是必须,如果用到七牛云上传则是必须的,因为token会过期,它可以检测token有效期
const qiniuUploader = require("../../utils/qiniuUploader");//引入七牛云上传源码
export default {
    props: {},
    components: {},
    data() {
        return {
            audioValue: "", //录音内容
            duration: 0, //录音时长
            recodeStatus: 0, //录音状态 0:未录音,1:正在录音2:录音完成
            playStatus: 0, //播放状态 0:未播放,1:正在播放
            recoderAuthStatus: false //录音授权状态
        };
    },
    methods: {
        //调用recorderManager.start开始录音
        recorderManagerStart() {
            this.recorderManager.start({
                format: "mp3",
                duration: 60000
            });
            this.recodeStatus = 1;
        },
        //开始录音
        startRecorder(index) {
            let that = this;
            if (this.recoderAuthStatus) {
                this.recorderManagerStart();
            } else {
                wx.openSetting({
                    success(res) {
                        if (res.authSetting["scope.record"]) {
                            that.recoderAuthStatus = true;
                            that.recorderManagerStart();
                        }
                    }
                });
            }
        },

        //结束录音
        stopRecorder(index) {
            this.recodeStatus = 2;
            this.recorderManager.stop();
        },
        //播放录音
        playVoice(index) {
            if (this.playStatus == 0) {
                //未播放状态则点击播放
                if (!this.audioValue) {
                    this.tip("请先录音!");
                    return;
                }
                this.playStatus = 1;
                this.innerAudioContext.src = this.audioValue;
                this.innerAudioContext.play();
            } else {
                //正在播放状态,则点击暂停
                this.playStatus = 0;
                this.innerAudioContext.stop();
            }
        },
        //删除录音,各属性,状态值init
        removeRecoder(index) {
            this.audioValue = "";
            this.recodeStatus = 0;
            this.playStatus = 0;
            this.duration = 0;
        },
        //获取权限设置
        getAuthSetting() {
            let that = this;
            wx.getSetting({
                success(res) {
                    if (!res.authSetting["scope.record"]) {
                        wx.authorize({
                            scope: "scope.record",
                            success() {
                                that.recoderAuthStatus = true;
                            },
                            fail() {
                                that.recoderAuthStatus = false;
                            }
                        });
                    } else {
                        that.recoderAuthStatus = true;
                    }
                }
            });
        },

        //格式化录音时间
        fmtRecoderTime(duration = 0) {
            duration = duration / 1000;
            const seconds = duration.toString().split(".")[0]; //取秒
            return seconds;
        },

        //提示弹窗
        tip(msg) {
            wx.showModal({
                title: "提示",
                content: msg,
                showCancel: false
            });
        },
        //上传音频
        uploadAudio(filePath, success) {
            // 交给七牛上传
            qiniuUploader.upload(
                filePath,
                res => {
                    let audioUrl = res.domain + res.truekey; //上传返回的url链接
                    return (
                        typeof success === "function" &&
                        success({ audio: audioUrl })
                    );
                },
                error => {
                    console.log("error: " + error);
                },
                {
                    region: "ECN", // 华东区
                    uptokenURL: "https://xxx/qiniu/uploadToken", //上传地址,需要后台配置
                    shouldUseQiniuFileName: false
                }
                // Base64 //一般token都是有时效的,Base64可以解析当前token的到期时间,判断是否过期从而更新令牌
            );
        },
        //初始化音频管理器
        initRecorderManager() {
            const recorderManager = wx.getRecorderManager();
            recorderManager.onError(() => {});
            //结束播放语音
            recorderManager.onStop(res => {
                const duration = this.fmtRecoderTime(res.duration); //获取录音时长
                //小程序录音最长1分钟(60秒)
                if (duration > 60) {
                    this.tip('录音时间不能超过60"');
                    this.recodeStatus = 2; //结束
                    return;
                } else if (duration < 1) {
                    this.duration = 1; //不计,未开始
                    return;
                }
                this.duration = duration;
             //  this.audioValue = res.tempFilePath;(这里是录音本地文件,如果需要在其他地方播放,则需要上传转换成网络链接)

                //上传本地音频
                 this.uploadAudio(res.tempFilePath, src => {
                     this.audioValue = src.audio;
                 });
            });
            this.recorderManager = recorderManager;

            //创建内部 audio 上下文 InnerAudioContext 对象。
            const innerAudioContext = wx.createInnerAudioContext();
            //监听音频自然播放至结束的事件
            innerAudioContext.onEnded(() => {
                //音频自然播放至结束的事件的回调函数
                this.playStatus = 0; //播放状态重置为未开始
            });
            innerAudioContext.onError(res => {});
            this.innerAudioContext = innerAudioContext;
        },
        //销毁当前组件音频实例
        destoryInnerAudioContext() {
            this.innerAudioContext.destroy();
            console.log("音频实例销毁啦");
        }
    },
    computed: {},
    watch: {},
    onLoad() {
        //判断是否已授权录音权限
        this.getAuthSetting();
        //初始化音频管理器
        this.initRecorderManager();
    },
    onUnload() {
        this.destoryInnerAudioContext();//销毁当前音频上下文实例
    }
};
</script>
  • 以上基本就是实现一个录音->播放的全过程了,基本注释在代码中都有体现,因此也没有像以往那样进行逐步分析。其实本身小程序基本帮我们把需求实现需要用到的功能都封装成了相应的api,应该说使用起来还是很方便和简单的,唯一可能就是api众多,可能在使用的时候不知所措该用哪一个最合适,所以,以上实现的api也不一定是最合适的,因此,各位大佬如有更好的实现方式,请不吝赐教,互相分享,共同进步!

后记

其实,这个世界哪有什么岁月静好,只不过有人替你负重前行罢了,加油,骚年!