webscoket+webrtc实现语音通话
1.项目方案
前端采用webrtc创建音频上下文,后创建音频源输入和音频处理器,连接音频输入与处理器,处理器再连接到音频输出(扬声器),再通过事件获取音频数据,把音频数据转换成字节数据通过webscoket发送给后端。
注意
1.前端使用的创建音频源api createScriptProcessor onaudioprocess 已经开始废弃使用,但是浏览器依然适配。
2.因为前端使用websocket实时传输录音数据,后端开发需要多线程接受处理数据,给每个数据包提供index坐标,然后处理后保存,再通过单线程发送,可以降低延迟
2.前端代码
// AudioManager.js
export default class AudioManager {/*** 构造函数* @param {string} url - WebSocket服务器的地址* @param {function} onMessageCallback - 当WebSocket接收到消息时的回调函数*/constructor(url, onMessageCallback) {this.url = url; // WebSocket服务器的完整URLthis.websocket = null; // WebSocket连接实例this.audioContext = null; // 音频上下文this.audioStream = null; // 流媒体对象this.audioProcessor = null; // 音频处理器this.onMessageCallback = onMessageCallback; // WebSocket消息的回调函数}/*** 初始化WebSocket连接并设置消息监听器*/initWs() {console.log(this.url,';this.url');// 创建WebSocket实例this.websocket = new WebSocket(this.url);// 设置WebSocket接收消息时的回调函数this.websocket.onmessage = (e) => {if (this.onMessageCallback) {// 调用通过构造函数传入的回调函数处理接收到的消息this.onMessageCallback(e.data);}};// 请求用户的麦克风权限并开始处理音频流this.queryHttp();}/*** 停止录音并关闭所有资源*/stopRecording() {// 关闭所有音频轨道if (this.audioStream) {this.audioStream.getTracks().forEach((track) => track.stop());}// 断开音频处理器的连接if (this.audioProcessor) {this.audioProcessor.disconnect();}// 关闭音频上下文if (this.audioContext) {this.audioContext.close();}// 关闭WebSocket连接if (this.websocket) {this.websocket.close();}}/*** 请求麦克风资源,并在成功后处理音频流*/queryHttp() {navigator.mediaDevices.getUserMedia({audio: {echoCancellation: true, // 开启回声消除noiseSuppression: true, // 开启噪声抑制autoGainControl: true, // 开启自动增益控制},}).then((stream) => {// 处理成功获取的音频流this.handleStream(stream);}).catch((error) => {// 处理获取音频流失败的情况console.error("Error accessing microphone:", error);});}/*** 处理音频流,连接音频输入和处理器,并设置音频处理事件* @param {MediaStream} stream - 从麦克风获取的音频流*/handleStream(stream) {this.audioContext = new AudioContext({sampleRate: 16000, // 设置采样率latencyHint: "interactive", // 延迟模式为交互式channels: 1, // 单声道frameRate: 60, // 帧率sampleType: "int16", // 采样类型numberOfOutputs: 1, // 输出数量});// 创建音频源输入let audioInput = this.audioContext.createMediaStreamSource(stream);// 创建音频处理器this.audioProcessor = this.audioContext.createScriptProcessor(4096, 1, 1);// 设置音频处理事件this.audioProcessor.onaudioprocess = (event) => {// 获取音频数据const inputData = event.inputBuffer.getChannelData(0);// 转换音频数据为字节数据const byteData = this.convertToByteData(inputData);// 通过WebSocket发送字节数据this.websocket.send(byteData);};// 连接音频输入与处理器,处理器再连接到音频输出(扬声器)audioInput.connect(this.audioProcessor);this.audioProcessor.connect(this.audioContext.destination);// 保存音频流引用this.audioStream = stream;}/*** 将浮点数组的音频数据转换为字节数据* @param {Float32Array} inputData - 浮点数组格式的原始音频数据* @return {Uint8Array} 字节数据*/convertToByteData(inputData) {// 创建Int16Array,由于原始的音频数据是Float32Array类型,需要转换const intData = new Int16Array(inputData.map((item) => item * 32767));// 创建Uint8Array来保存字节数据const byteData = new Uint8Array(intData.length * 2);// 将Int16Array的数据转换为字节数据并填充到Uint8ArrayintData.forEach((value, index) => {byteData[index * 2] = value & 0xff; // 存储低位字节byteData[index * 2 + 1] = (value >> 8) & 0xff; // 存储高位字节});return byteData;}
}/*使用方法
<template><audio style="display: none" ref="audio" controls="controls" autoplay><source :src="audioUrl" type="audio/wav" /></audio>
</template><script>
import AudioManager from './AudioManager.js';export default {data() {return {audioManager: null,};},methods: {handleWsMessage(data) {let message = JSON.parse(data);this.$refs.audio.src = message.url; },startRecording() {this.audioManager = new AudioManager('your-server-url',this.handleWsMessage // 回调函数用于接受通话后获取的信息这里我用于播放接受的音频);this.audioManager.initWs();},},
};
</script> */
相关文章:
webscoket+webrtc实现语音通话
1.项目方案 前端采用webrtc创建音频上下文,后创建音频源输入和音频处理器,连接音频输入与处理器,处理器再连接到音频输出(扬声器),再通过事件获取音频数据,把音频数据转换成字节数据通过webscok…...

PHP源码_众筹商城
众筹商城源码 众筹商品平台 商城加共识元富之路 网上商城众筹 前端是编译后的,后端PHP,带商城 运行截图 源码贡献 https://githubs.xyz/boot?app39 部分数据库表 CREATE TABLE ti_shopro_store (id int(11) NOT NULL AUTO_INCREMENT COMMENT ID,nam…...
智能小程序 Ray 开发——表单组件 Button 和 Checkbox 实操讲解
Button 多端按钮基础组件,可用于进行强交互的操作。 导入 import { Button } from ray-js/ray; 属性说明 属性类型默认值必填说明支持平台sizekeyof Sizedefault否按钮的大小涂鸦、微信typekeyof Typedefault否按钮的样式类型涂鸦、微信plainbooleanfalse否按钮…...

渗透之sql注入联合查询的注入
sql注入产生的原因: 由于程序过滤不严谨,导致用户有一些异常输入,最终触发数据库的查询。所以会出现sql注入这个问题。有些恶意的人就会利用这些信息导致数据库泄露。 注意:一般我们存在注入点我们会查询管理员的账号和密码&#…...

NLP transformers - 文本分类
Text classification 文章目录 Text classification加载 IMDb 数据集Preprocess 预处理EvaluateTrainInference 本文翻译自:Text classification https://huggingface.co/docs/transformers/tasks/sequence_classification notebook : https://colab.research.googl…...

QT 开发COM(ActiveX)组件基础介绍和方案验证
一、COM简介 1.1 COM是什么? COM,Component Object Model,即组件对象模型,是一种以组件为发布单元的对象模型,这种模型使各软件组件可以用一种统一的方式进行交互。COM 既提供了组件之间进行交互的规范,也…...

[1673]jsp在线考试管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 JSP 在线考试管理系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0&…...
每日一算法
问题 等待登机的你看着眼前有老有小长长的队伍十分无聊,你突然 想要知道,是否存在两个年龄相仿的乘客。每个乘客的年龄用 1个0 到 36500 的整数表示,两个乘客的年龄相差 365 以内 就认为是相仿的。 具体来说,你有一个长度为 n 的…...
Spring Cloud Gateway直接管理Vue.js的静态资源
1. 构建Vue.js应用 像之前一样,构建你的Vue.js应用,并将生成的静态资源(位于dist目录)复制到Spring Boot项目的某个目录,比如src/main/resources/static。 2. 配置Spring Boot静态资源处理 Spring Boot默认会处理sr…...

14.集合、常见的数据结构
集合 概念 Java中的集合就是一个容器,用来存放Java对象。 集合在存放对象的时候,不同的容器,存放的方法实现是不一样的, Java中将这些不同实现的容器,往上抽取就形成了Java的集合体系。 Java集合中的根接口&#x…...
NLP从入门到实战——命名实体识别
1. 命名实体识别 1.1 概念 中文命名实体识别(Named Entity Recognition,NER是指识别中文文本中实体的边界和类别。命名实体识别是文本处理中的基础技术,广泛应用在自然语言处理、推荐系统、知识图谱等领域,比如推荐系统中的基于…...
接口测试工具-postman介绍
一、介绍 Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。 作用:常用于进行接口测试。 它可以模拟浏览器发起任何形式的HTTP请求...
日志中看到来自User Agent go-http-client / 1.1的大量请求(go-http-client 1.1)服务器爆了
在日志中看到来自User Agent go-http-client / 1.1的大量请求 The go-http-client/1.1 User Agent 是Google的Bot / Crawler 这不是真的。这可能是指Go库(根据您提到的来源,由Google开发,但是我找不到可靠的信息)。 之前写过“G…...

yolov8 区域声光报警+计数
yolov8 区域报警计数 1. 基础2. 报警功能2. 1声音报警代码2. 2画面显示报警代码 3. 完整代码4. 源码 1. 基础 本项目是在 yolov8 区域多类别计数 的基础上实现的,具体区域计数原理可见上边文章 2. 报警功能 设置一个区域region_points,当行人这一类别…...

《QT实用小工具·五十五》带有标签、下划线的Material Design风格输入框
1、概述 源码放在文章末尾 该项目实现了一个带有标签动画、焦点动画、正确提示、错误警告的单行输入框控件。下面是demo演示: 项目部分代码如下所示: #ifndef LABELEDEDIT_H #define LABELEDEDIT_H#include <QObject> #include <QWidget>…...

用Go实现一个无界资源池
写在文章开头 我们希望通过go语言实现一个简单的资源池,而这个资源池的资源包括但不限于: 数据库连接池线程池协程池网络连接池 只要这些资源实现我们指定的关闭方法,则都可以通过我们封装的资源池进行统一管理,需要简单说明一下这个资源池…...

Apache Seata基于改良版雪花算法的分布式UUID生成器分析2
title: 关于新版雪花算法的答疑 author: selfishlover keywords: [Seata, snowflake, UUID, page split] date: 2021/06/21 本文来自 Apache Seata官方文档,欢迎访问官网,查看更多深度文章。 关于新版雪花算法的答疑 在上一篇关于新版雪花算法的解析中…...

13、揭秘JVM垃圾回收器:面试必备知识,你掌握了吗?
13.1、前文回顾 在上一篇文章中,我们详细分析了触发Minor GC的时机,以及对象何时会从新生代迁移到老年代。我们还讨论了为了确保新生代向老年代的内存迁移安全,需要在Minor GC之前如何检查老年代的内存空间,以及在什么情况下会触发老年代的Full GC,以及老年代的垃圾回收算…...

治疗耳鸣患者案例分享第二期
“患者耳鸣20年了,目前耳朵没有堵或者胀的感觉,但是偶尔有点痒,平时会有头晕头胀这种情况,然后头晕是稍微晕炫一下。然后头疼是经常有的,头胀不经常。” 患者耳鸣持续20年,虽然耳朵没有堵或胀的感觉&#x…...
数据加密的方法
这些方法可以单独或结合使用,以提高数据的安全性和保护隐私。 对称加密:使用相同的密钥对数据进行加密和解密。常见的对称加密算法包括DES、AES和RC4。 非对称加密:使用一对密钥(公钥和私钥)对数据进行加密和解密。发…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...