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

news2024/12/26 23:49:15

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1907617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AJAX快速入门(一) express框架的安装和使用范例

主打一个有用 首先保证安装了nodejs环境 打开终端 初始化npm npm init安装express npm i express测试样例 目录结构 样例代码 express.js //引入express const express require(express);//创建应用对象 const app express();//创建路由规则 //req是请求对象&#x…

C#委托事件的实现

1、事件 在C#中事件是一种特殊的委托类型&#xff0c;用于在对象之间提供一种基于观察者模式的通知机制。 1.1、事件的发送方定义了一个委托&#xff0c;委托类型的声明包含了事件的签名&#xff0c;即事件处理器方法的签名。 1.2、事件的订阅者可以通过运算符来注册事件处理器…

HTTP 请求走私漏洞详解

超详细的HTTP请求走私漏洞教程&#xff0c;看完还不会你来找我。 1. 简介 HTTP请求走私漏洞&#xff08;HTTP Request Smuggling&#xff09;发生在前端服务器&#xff08;也称代理服务器&#xff0c;一般会进行身份验证或访问控制&#xff09;和后端服务器在解析HTTP请求时&…

【GIt】变基(rebase)

目录 变基(rebase)是什么为什么有变基变基后的时间线变基前的时间线 变基原理怎么变基同一个分支变基不同分支变基 参考文章 变基(rebase)是什么 Git 变基&#xff08;rebase&#xff09;是一种用于整合分支的方法&#xff0c;它的工作原理是将一系列提交&#xff08;或分支合…

太实用了吧?手把手教你华为eNSP模拟器桥接真实网络!

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 今天聊聊eNSP桥接正式网络&#xff0c;就是把eNSP桥接进真实的网络&#xff0c;利用我们的物理网卡通过实体路…

MoonBit 周报 Vol.48:默认开启诊断信息渲染、test block 不再返回 Result 类型的结果

weekly 2024-07-08 MoonBit 更新 【重大更新】修改 array slice 的语法&#xff0c;从 arr[start..end] 修改为类似 Python 的 arr[start:end]。这是为了避免和接下来要支持的 cascade method call x..f() 产生语法冲突。旧的语法会在近期删除。 【Wasm后端重大更新】将 fn i…

什么是C#

C#是一种面向对象的语言与c语言不同 C语言是面向过程的编程 C#运行于.NETFramework和.NETCore之上的高级语言 C#是由C和C衍生而来的一种语言 在C#中不建议使用指针 什么叫面向对象 是一种编程范式&#xff0c;它将现实世界中的事物抽象为对象&#xff0c;并通过对象之间的…

田地行走-美团2023笔试(codefun2000)

题目链接 田地行走-美团2023笔试(codefun2000) 题目内容 塔子哥是一个农民&#xff0c;他有一片 nm 大小的田地&#xff0c;共 n 行 m 列&#xff0c;其中行和列都用从 1 开始的整数编号&#xff0c;田地中有 k 个格子中埋有土豆。我们记第 a 行第 b 列的格子为 (a,b) 。塔子哥…

JAVA:常用的队列指南

1、简述 在计算机科学中&#xff0c;队列是一种常见的线性数据结构&#xff0c;它遵循先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;的原则。队列在各种应用中广泛使用&#xff0c;例如任务调度、消息队列和宽度优先搜索等。在 Java 中&#xff0c;队列…

android perfetto使用技巧梳理

1 抓取方法 根据不同的配置参数&#xff0c;会显示不同的功能。 比如有的trace文件就无法显示线程状态信息&#xff0c;有的无法显示锁依赖信息等等&#xff0c;要看你的参数&#xff0c;我这个是很全的&#xff0c;基本够了&#xff0c;如果还想添加&#xff0c;可以命令行看…

我与OceanBase|一位DBA老兵的国产数据库探索之旅

本文作者&#xff1a;尚雷&#xff0c;有超过十年的工作经验&#xff0c;目前就职于南京一家上市互联网企业&#xff0c;担任DBA。Oracle 11g OCM&#xff0c;Oracle及PG的 ACE认证&#xff0c;并有AWS及国产知名数据库等多项认证。他热衷于技术交流与分享&#xff0c;爱交友&a…

Apache AGE 安装部署

AGE概述 概述 我们可以通过源码安装、拉取docker镜像运行、直接使用公有云三种方式中的任意一种来使用Apache AGE 获取 AGE 发布版本 可以在 https://github.com/apache/age/releases 找到发布版本和发布说明。 源代码 源代码可以在 https://github.com/apache/age 找到…

非参数检测5——双输入检测系统

在很多情况下&#xff0c;信号常常存在于两个带有独立噪声的信道中。所以很有必要研究双输入系统。双输入系统广泛应用于无线电天文学、水下声波检测和地球物理学等领域。

【ffmpeg系列一】源码构建,ubuntu22与win10下的过程对比。

文章目录 背景ubuntu22结论 win10过程 对比结论 背景 顺手编译个ffmpeg试试&#xff0c;看看不同平台下谁的配置比较繁琐。 先让gpt给出个教程&#xff1a; ubuntu22 使用elementary-os7.1构建&#xff0c;看看有几个坑要踩。 错误1&#xff1a; 依赖libavresample-dev未…

源码层面学习动态代理

前言 在Java中&#xff0c;动态代理主要分为CGLIB动态代理和JDK动态代理&#xff0c;我们从Hutool的源码也可一窥这两者的使用方式和区别&#xff1b; CGLIB动态代理 JDK动态代理 使用场景 CglibInterceptor和JdkInterceptor都是Hutool提供的代理工具&#xff0c;用于在运行时…

214.贪心算法:K次取反后最大化的数组和(力扣)

class Solution { public:int largestSumAfterKNegations(vector<int>& nums, int k) {int sum 0;// 进行k次取反操作while (k > 0){// 对数组进行排序sort(nums.begin(), nums.end());// 将最小的元素取反nums[0] -nums[0];// 减少k的值k--;}// 计算数组的总和…

12 - matlab m_map地学绘图工具基础函数 - 在地图上绘制矢量场m_vec函数和绘制风羽图的m_windbarb函数

12 - matlab m_map地学绘图工具基础函数 - 在地图上绘制矢量场函数m_vec和绘制风羽图的函数m_windbarb 0. 引言1. 关于m_vec2. 关于m_windbarb3. 总结 0. 引言 本篇介绍下m_map中绘制矢量场的函数&#xff08;m_vec&#xff09;和地图上绘制风羽图的函数m_windbarb。 1. 关于m…

语言模型的进化:从NLP到LLM的跨越之旅

在人工智能的浩瀚宇宙中&#xff0c;自然语言处理&#xff08;NLP&#xff09;一直是一个充满挑战和机遇的领域。随着技术的发展&#xff0c;我们见证了从传统规则到统计机器学习&#xff0c;再到深度学习和预训练模型的演进。如今&#xff0c;我们站在了大型语言模型&#xff…

Unity扩展 Text支持超链接文本

重点提示&#xff1a;当前的文本扩展支持多个超链接&#xff0c;支持修改超链接规则和支持修改超链接颜色。 近期在邮件文本中用到了超链接。最初是在邮件窗口中新加一个按钮用来超链接跳转&#xff0c;之后发现效果表现不如直接在文本中添加&#xff0c;后经过几个小时的资料…

STM32中的DMA:解锁高效数据传输的秘密武器(内附实例)

目录 引言 理解DMA&#xff1a;数据的高效搬运工 DMA的主要特性 多优先级请求 事件标志 数据对齐 多样化的数据传输路径 广泛的数据源与目标 最大数据长度 DMA寄存器详解 增量与循环模式 DMA中断机制 ​编辑 小实验&#xff1a;DMA-ADC串口发送 引言 在现代嵌入…