Vue+ElementUi实现录音播放上传及处理getUserMedia报错问题

发布于:2024-07-05 ⋅ 阅读:(136) ⋅ 点赞:(0)

1.Vue安装插件

npm install --registry=https://registry.npmmirror.com

2.Vue页面使用

<template>
    <div class="app-container">
        <!-- header -->
        <el-header class="procedureHeader" style="height: 20px;">
            <el-divider content-position="left">
                <h3>
                    <el-link type="primary" style="background-color: rgba(255, 255, 255, 0.5);">语音识别</el-link>
                </h3>
            </el-divider>
        </el-header>
        <el-row>
            <!-- 左侧语音录制区域-->
            <el-col :span="12">
                <div class="asr-left">
                    <el-input v-model="asrName" placeholder="请输入内容" size="small"
                        style="width: 192px;margin-left: 20px;margin-top: 20px;"></el-input>
                    <el-input type="textarea" :rows="34" placeholder="请开始录音" v-model="asrData" size="small" :readonly="true" 
                        style="margin-left: 20px;margin-top: 20px;width: 94%;">
                    </el-input>
                    <div style="display: -webkit-box;">
                        <div style="margin-left: 18px;margin-top: 20px;margin-bottom: 10px;width: 82%;">
                        <span style="color: #303133;">时长:</span>
                        <span style="color: #303133;">{{convertSecondsToHMS(recorder.duration.toFixed(4))}}</span>
                        <span title="开始录音" class="asr-btn" style="margin-left: 67%;" v-if="startRecord" @click="handleStartRecord">
                            <i class="el-icon-microphone"></i>
                        </span>
                        <span title="录音中" class="asr-btn" style="color: #1890ff;margin-left: 67%;"  v-if="recordIng" @click="handleRecordIng">
                            <i class="el-icon-mic"></i>
                        </span>
                        <span title="播放录音" class="asr-btn" v-if="playRecord" @click="handlePlayRecord">
                            <i class="el-icon-video-play"></i>
                        </span>
                        <span title="播放中" class="asr-btn" v-if="playRecordIng" @click="handlePlayRecordIng">
                            <i class="el-icon-video-pause"></i>
                        </span>
                        <span title="结束录音" class="asr-btn" style="color: red;" @click="handleStopRecord">
                            <i class="el-icon-switch-button" style="font-weight: 600;"></i>
                        </span>
                    </div>
                    <el-button type="primary" size="mini" style="margin-top: 17px;" @click="handleRecord">开始识别</el-button>
                    </div>

                </div>
            </el-col>
            <!-- 右侧语音识别结果展示区域 -->
            <el-col :span="12" class="asr-right">
                <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px" style="margin-top: 20px;">
                    <el-form-item label="标题" prop="title">
                        <el-input
                        v-model="queryParams.title"
                        placeholder="请输入标题"
                        clearable
                        @keyup.enter.native="handleQuery"
                        />
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
                        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
                    </el-form-item>
                </el-form>
                <el-table v-loading="loading" :data="asrList" height="675">
                <el-table-column label="名称" align="center" prop="title" width="340" />
                <el-table-column label="创建时间" align="center" prop="createTime" />
                <el-table-column label="状态" align="center" width="100" prop="flag" :formatter="flagFormat"/>
                <el-table-column label="操作" align="center" width="100" class-name="small-padding fixed-width">
                    <template slot-scope="scope">
                    <el-button
                        size="mini"
                        type="text"
                        icon="el-icon-edit"
                        v-if="scope.row.flag == 2"
                        @click="handleOpen(scope.row)"
                    >查看</el-button>
                    </template>
                </el-table-column>
                </el-table>
                
                <pagination
                v-show="total>0"
                :total="total"
                :page.sync="queryParams.pageNum"
                :limit.sync="queryParams.pageSize"
                @pagination="getList"
                />
                <!-- 查看语音识别信息弹窗 -->
                <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
                    <el-input type="textarea" :rows="34" placeholder="" v-model="asrCallbackData" size="small" :readonly="true" >
                    </el-input>
                </el-dialog>
            </el-col>
        </el-row>
    </div>
</template>
<script>
import { listAsr,upload,getAsr } from "@/api/mam/asr";
import Recorder from 'js-audio-recorder';
let recorder = new Recorder();

export default {
    name: "asr",
    data() {
        return {
            recorder: new Recorder({
                sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
                sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
                numChannels: 1, // 声道,支持 1 或 2, 默认是1
                compiling: false  //(0.x版本中生效,1.x增加中) 是否边录边转换,默认是false
            }),
            // 语音识别任务名称
            asrName: "",
            // 语音识别结果
            asrData: "",
            // 录音时长
            recordTime: "00:00:00",
            // 开始录音
            startRecord: true,
            // 录音中
            recordIng: false,
            // 播放录音
            playRecord: true,
            // 播放中
            playRecordIng: false,
            // 倒计时播放
            countdownTimer: null,
            // 任务轮询定时器
            taskTimer: null,
            // 总条数
            total: 0,
            // 语音识别表格数据
            asrList: [],
            // 遮罩层
            loading: true,
            // 查询参数
            queryParams: {
                pageNum: 1,
                pageSize: 20,
                taskid: null,
                assetid: null,
                fileid: null,
                title: null,
                content: null,
                createtime: null,
                creator: null,
                flag: null
            },
            // 弹出层标题
             title: "",
            // 是否显示弹出层
            open: false,
            // 弹出层数据
            asrCallbackData: ""
        }
    },
    created() {
        this.asrName= this.getNowTime();      
        this.getList();
    },
    methods: {
        /** 查询语音识别列表 */
        getList() {
            this.loading = true;
            listAsr(this.queryParams).then(response => {
                this.asrList = response.rows;
                this.total = response.total;
                this.loading = false;
            });
        },
        // 表单重置
        reset() {
            this.form = {
                id: null,
                taskid: null,
                assetid: null,
                fileid: null,
                title: null,
                content: null,
                createtime: null,
                creator: null,
                flag: null
            };
            this.resetForm("form");
        },
        /** 搜索按钮操作 */
        handleQuery() {
            this.queryParams.pageNum = 1;
            this.getList();
        },
        /** 重置按钮操作 */
        resetQuery() {
            this.resetForm("queryForm");
            this.handleQuery();
        },
        //任务状态格式化
        flagFormat(row, column){
            if(row.flag == 0){
                return "未开始";
            }else if(row.flag == 1){
                return "进行中";
            }else if(row.flag == 2){
                return "已完成";
            }else if(row.flag == 3){
                return "出错";
            }else{
                return "未知状态";
            }
        },
        // 打开弹出层
        handleOpen(row){
            this.title = row.title;
            this.open = true;
            this.asrCallbackData = row.content;
        },
        // 开始录音 
        handleStartRecord(){
            Recorder.getPermission().then(
                () => {
                    if(this.asrData == "正在转写中..."){
                        this.$message.warning('正在转写中...');
                    }else{
                        //开始录音时关闭录音播放
                        this.playRecordIng = false;
                        this.playRecord = true;
                        this.recorder.pausePlay();
                        this.recorder.start();; // 开始录音

                        this.startRecord = false;
                        this.recordIng = true;
                        this.asrData = "信息采集中..."; 
                    }      
                },
                (error) => {
                this.$message({
                    message: "请先允许该网页使用麦克风",
                    type: "info",
                });
                console.log(`${error.name} : ${error.message}`);
                }
            );
        },

        // 录音中
        handleRecordIng(){
            // this.recordIng = false;
            // this.startRecord = true;
        },
        // 播放录音
        handlePlayRecord(){
            if(this.recordIng ){
                this.$message.warning('信息采集中,请先结束录音后,再播放录音!');
            }else{
                if(this.recorder.size > 0){
                    this.playRecord = false;
                    this.playRecordIng = true;
                    this.recorder.play();
                    this.asrData = "正在播放采集信息...";
                    //倒计时播放自动关闭
                    this.countdown(this.recorder.duration);
                }else{
                    this.$message.warning('请先录制音频!');
                }


            }
        },
        // 播放中
        handlePlayRecordIng(){
            this.playRecordIng = false;
            this.playRecord = true;
            this.recorder.pausePlay();
        },
        // 结束录音
        handleStopRecord(){
            if(this.asrData == "正在转写中..."){
                this.$message.warning('正在转写中...');
            }else{
                this.recordIng = false;
                this.startRecord = true;
                this.asrData = "信息采集结束...";
                this.recorder.stop();
            }
        },
        // 开始识别
        handleRecord(){
            //关闭录音
            this.recordIng = false;
            this.startRecord = true;
            this.recorder.stop();
            //关闭录音播放
            this.playRecordIng = false;
            this.playRecord = true;
            this.recorder.pausePlay();
            //识别
            console.log(this.recorder.size);
            if(this.recorder.size > 0){
                // 获取 WAV 数据(Blob)
                let blob =this.recorder.getWAVBlob()
                console.log(blob);
                let formData = new FormData()
                formData.append('file', blob)
                formData.append("asrTitle",this.asrName)
                upload(formData).then(response => {
                    if(response.code == 200){
                        this.asrData = "正在转写中...";
                        //销毁实例
                        this.recorder.destroy();
                        this.msgSuccess('任务创建成功');
                        this.asrName= this.getNowTime();
                        this.taskPolling(response.msg);

                    }
                });
            }else{
                this.$message.warning('请先录制音频!');
            }    
        },
        // 任务轮询
        taskPolling(id){
            this.taskTimer = setInterval(
                () => {
                    //任务列表
                    listAsr(this.queryParams).then(response => {
                        this.asrList = response.rows;
                        this.total = response.total;
                    });
                    //列表详情
                    getAsr(id).then(response => {
                        if(response.code == 200){
                            if(response.data.flag == 2){
                                this.asrData = response.data.content;
                                clearInterval(this.taskTimer);
                                this.msgSuccess('任务已完成');
                            }
                        }
                    });
                }
                , 1000);
        },
        // 获取当前时间
        getNowTime() {
            const now = new Date();
            const year = now.getFullYear();
            const month = this.padNumber(now.getMonth() + 1);
            const day = this.padNumber(now.getDate());
            const hours = this.padNumber(now.getHours());
            const minutes = this.padNumber(now.getMinutes());
            const seconds = this.padNumber(now.getSeconds());
            return "语音识别-"+`${year}${month}${day}${hours}${minutes}${seconds}`;
        },
        padNumber(num) {
            return num < 10 ? '0' + num : num;
        },
        //秒数转为时分秒
        convertSecondsToHMS(seconds) {
            var date = new Date(null);
            date.setSeconds(seconds);
            var timeString = date.toISOString().substr(11, 8);
            return timeString;
        },
        //倒计时播放
         countdown(currentSeconds) {
            this.countdownTimer = setInterval(() => {
                currentSeconds--; // 每次间隔1秒,将秒数减少1
                if (currentSeconds < 0) {
                    clearInterval(this.countdownTimer); // 当秒数小于等于0时清除定时器
                    // console.log("倒计时结束");
                    this.playRecordIng = false;
                    this.playRecord = true;
                    this.asrData = "采集信息播放结束...";
                } else {
                    // console.log(`还有 ${seconds} 秒`);
                }
            }, 1000); // 设置定时器间隔为1秒(1000毫秒)
        }
    }
}
</script>
<style scoped lang="less">
/* 左侧语音录制区域 */
.asr-left {
    /*border: 1px solid #ebebeb;*/
    margin-left: 20px;
}

/* header */
::v-deep .el-divider__text {
    background-color: unset;
}

/* 右侧语音识别结果展示区域 */
.asr-right {

}
/* 按钮 */
.asr-btn {
    cursor: pointer;
    margin-left: 15px;
    font-size: 20px;
}
</style>

3.效果图

4.注意使用127.0.0.1或者localhost与线上地址用Ip或者域名访问时不一样,因为getUserMedia在高版本的chrome下需要使用https。若仍需要使用,按下面步骤使用。

浏览器地址栏输入:

chrome://flags/#unsafely-treat-insecure-origin-as-secure

5.详细参考博主地址

https://www.cnblogs.com/badaoliumangqizhi/p/16711777.html