【electron6】浏览器实时播放PCM数据
pcm介绍:PCM(Puls Code Modulation)全称脉码调制录音,PCM录音就是将声音的模拟信号表示成0,1标识的数字信号,未经任何编码和压缩处理,所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信息,播放器无法知道采样率,声道数,采样位数,音频数据大小等信息,导致无法播放。
需求:我需要在websoket中接收实时的pcm音频流原始数据:16位,16k,单通道(意思就是:pcm 的参数采样率16000,采样位数16,声道数1)
重要!:千万不要去运用什么所谓的插件,因为它会使你绕很大一圈的弯路,实时播放的pcm浏览器是支持的,使用插件很可能还会被迫读什么源码,也很容易将你带偏,再多的播放插件底层大部分也是基于AudioContext去开发的。
首先是拿音频文件试,但是却不了解mp3和wav的区别,就首选拿了mp3这是我的第一个深坑,因为mp3经过多层的处理压缩,已经距离原始的文件很远了,通过ajax拿回来的arraybuffer是可以直接塞进去CreateBufferSource.buffer中就能直接播放,原因就是decodeAdioData就直接能处理接口返回的arraybuffer数据
mp3示例:
useEffect(() => {axios.request({url: require('@/assets/wholeWorld.mp3'), // 假如这是我们从后端请求回来的音乐文件responseType: 'arraybuffer', // 必须需要这个method: 'get'}).then(res => {// 创建AudioBufferSourceNodeconst arrayBuffer = res.dataconst context = new AudioContext()const source = context.createBufferSource();context.decodeAudioData(arrayBuffer).then(audioBuffer => {// 设置buffer属性source.buffer = audioBuffer;// 连接到音频上下文并播放source.connect(context.destination);})source.start(0);})}, [])
我处理wav的音频去播放,也是可以的使用decodeAudioData去进行播放
wav音频播放示例:
useEffect(() => {axios.request({url: require('@/assets/sample.wav'), // 假如这是我们从后端请求回来的音乐文件responseType: 'arraybuffer', // 必须需要这个method: 'get'}).then(res => {// 创建AudioBufferSourceNodeconst arrayBuffer = res.dataconst context = new AudioContext()const source = context.createBufferSource();context.decodeAudioData(arrayBuffer).then(audioBuffer => {// 设置buffer属性source.buffer = audioBuffer;// 连接到音频上下文并播放source.connect(context.destination);})source.start(0);})}, [])
但是都不支持pcm文件,所以我最开始的思路是通过获取到的pcm去处理成wav的文件一样,去搜了很多资料,都说wav的文件比pcm只是多了44字节文件头,我没从深度验证,但是我通过加字节文件头去进行pcm的播放,因为decodeAudioData可以运行其他处理过的音频文件,尽管加了字节文件头是不能解决根本问题的,这段路我绕了很大一个圈。
mp3文件和wav文件的区别示例:

mp3和wav的区别说明:

其实浏览器是可以直接播放pcm数据的,无论是文件,还是socket返回来的原始数据,这过程涉及了Uint8转换Uint16,Uint16转成Float32,了解decodeAudioData和getChannelData究竟处理什么问题等知识。
首先,找一个pcm文件,进行播放调试,pcm的文件能播放成功,那socket就不是问题!
PCM播放代码示例:
(仅播放出声音的调试,自行调整代码规范)
// 解析PCM数据到AudioBuffer
function decodePCM(arrayBuffer: ArrayBufferLike,sampleBits: number, channelCount: number, sampleRate: number,audioContext: any) {return new Promise((resolve, reject) => {const dataView = new DataView(arrayBuffer);const length = (arrayBuffer.byteLength / (sampleBits / 8) / channelCount);const buffer = audioContext.createBuffer(channelCount, length, sampleRate);let offset = 0;for (let channel = 0; channel < channelCount; channel++) {const channelBuffer = buffer.getChannelData(channel);for (let i = 0; i < length; i++) {const sample = dataView.getInt16(offset, true); // 假设PCM数据是16位有符号整数channelBuffer[i] = sample / 32768; // 标准化到-1到1的范围offset += 2; // 16位 = 2字节}}resolve(buffer);});
}
let sourceNode: any = null;useEffect(() => {// 加载音频文件axios.request({method: 'get',url: require('@/assets/recorder.pcm'),responseType: "arraybuffer",}).then(res => {const arraybuffer = res.dataconst audioContext = new window.AudioContext();decodePCM(arraybuffer, 16, 1, 16000, audioContext).then(buffer => {sourceNode = audioContext.createBufferSource();sourceNode.buffer = buffer;sourceNode.connect(audioContext.destination);sourceNode.start(); // 开始播放}).catch(error => {console.error('Error decoding PCM:', error);});})}, [])
注:
当声音有杂音,一直是一个杂音就说明,数据错了
当声音没有声音,数据很可能都是0
当声音隐隐有正常,但是杂音很重,一定是需要它:getChannelData和DataView
后端从TCP给我实时的pcm是压缩Uint8Array,前端将Uint8Array的数据解码为Uint16Array,然后合并Uint16Array的所有音频数据,还需要将Uint16Array通过DataView处理成AudioContext可播放的Float32Array,所以不了解AudioCotext API是很难解决这些问题的,更何况仅仅是播放的功能,我后面还要处理更多复杂的应用场景,持续更新实时播放pcm的处理应用场景。
最终在和蔼可亲的同事帮助和自己不辞辛苦的研究下搞出来了,感谢我的同事。
值得参考:
张鑫旭:https://www.zhangxinxu.com/wordpress/2023/10/js-audio-audiobuffer-concat-merge/
MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/BaseAudioContext/createBuffer
推荐工具:
MEIDAINFO:https://mediaarea.net/MediaInfoOnline
相关文章:
【electron6】浏览器实时播放PCM数据
pcm介绍:PCM(Puls Code Modulation)全称脉码调制录音,PCM录音就是将声音的模拟信号表示成0,1标识的数字信号,未经任何编码和压缩处理,所以可以认为PCM是未经压缩的音频原始格式。PCM格式文件中不包含头部信…...
嵌入式C/C++、FreeRTOS、STM32F407VGT6和TCP:智能家居安防系统的全流程介绍(代码示例)
1. 项目概述 随着物联网技术的快速发展,智能家居安防系统越来越受到人们的重视。本文介绍了一种基于STM32单片机的嵌入式安防中控系统的设计与实现方案。该系统集成了多种传感器,实现了实时监控、报警和远程控制等功能,为用户提供了一个安全、可靠的家居安防解决方案。 1.1 系…...
【Django】django自带后台管理系统样式错乱,uwsgi启动css格式消失的问题
正常情况: ERROR:(css、js文件加载失败) 问题:CSS加载的样式没有了,原因:使用了django自带的admin,在使用 python manage.py runserver启动 的时候,可以加载到admin的文…...
解决npm install(‘proxy‘ config is set properly. See: ‘npm help config‘)失败问题
摘要 重装电脑系统后,使用npm install初始化项目依赖失败了,错误提示:‘proxy’ config is set properly…,具体的错误提示如下图所示: 解决方案 经过报错信息查询解决办法,最终找到了两个比较好的方案&a…...
汽车及零部件研发项目管理系统:一汽东机工选择奥博思 PowerProject 提升研发项目管理效率
在汽车行业中,汽车零部件的研发和生产是一个关键的环节。随着汽车市场的不断扩大和消费者需求的不断增加,汽车零部件项目管理的重要性日益凸显。通过有效的项目管理方法及利用先进的数字项目管理系统,可以大幅提高项目的成功率和顺利度&#…...
Keil开发IDE
Keil开发IDE 简述Keil C51Keil ARMMDK DFP安装 简述 Keil公司是一家业界领先的微控制器(MCU)软件开发工具的独立供应商。Keil公司由两家私人公司联合运营,分别是德国慕尼黑的Keil Elektronik GmbH和美国德克萨斯的Keil Software Inc。Keil公…...
数据结构与算法05堆|建堆|Top-k问题
一、堆 1、堆的介绍 堆(heap)是一种满足特定的条件的完全二叉树,主要可以分为大根堆和小根堆。 大根堆(max heap):任意节点的值大于等于其子节点的值。小根堆(min heap)࿱…...
【精简版】jQuery 中的 Ajax 详解
目录 一、概念 二、jQuery 发送 GET 请求 三、jQuery 发送 POST 请求 四、$.ajax() 方法 1、含义 2、settings 选项 ① type 属性 ② async 属性 ③ headers 属性 ④ contentType 属性 ⑤ processData 属性 ⑥ data 属性 ⑦ timeout 属性 ⑧ beforeSend(jqXHR) 方…...
win10删除鼠标右键选项
鼠标右键菜单时,发现里面的选项特别多,找一下属性,半天找不到。删除一些不常用的选项,让右键菜单变得干净整洁。 1、按下键盘上的“winR”组合按键,调出“运行”对话框,输入“regedit”命令,点击…...
分层评估的艺术:sklearn中的策略与实践
分层评估的艺术:sklearn中的策略与实践 在机器学习中,评估模型性能是一个至关重要的步骤。然而,对于不平衡的数据集,传统的评估方法可能会产生误导性的结果。分层评估(Stratified Evaluation)是一种确保评…...
排序系列 之 快速排序
!!!排序仅针对于数组哦本次排序是按照升序来的哦代码后边有图解哦 介绍 快速排序英文名为Quick Sort 基本思路 快速排序采用的是分治思想,即在一个无序的序列中选取一个任意的基准元素base,利用base将待排序的序列分…...
【银河麒麟服务器操作系统】java进程oom现象分析及处理建议
了解银河麒麟操作系统更多全新产品,请点击访问麒麟软件产品专区:https://product.kylinos.cn 现象描述 某服务器系统升级内核至4.19.90-25.22.v2101版本后仍会触发oom导致java进程被kill。 现象分析 oom现象分析 系统messages日志分析,故…...
Redis的AOF持久化策略(AOF的工作流程、AOF的重写流程,操作演示、注意事项等)
文章目录 缓冲AOF 策略(append only file)AOF 的工作流程AOF 缓冲区策略AOF 的重写机制重写完的AOF文件为什么可以变小?AOF 重写流程 缓冲AOF 策略(append only file) AOF 的核心思路是 “实时备份“,只要我添加了新的数据或者更新了新的数据࿰…...
共享模型之无锁
一、问题提出 1.1 需求描述 有如下的需求,需要保证 account.withdraw() 取款方法的线程安全,代码如下: interface Account {// 获取余额Integer getBalance();// 取款void withdraw(Integer amount);/*** 方法内会启动 1000 个线程…...
下载安装VSCode并添加插件作为仓颉编程入门编辑器
VSCode下载地址:下载 Visual Studio Code - Mac、Linux、Windows 插件下载:GitCode - 全球开发者的开源社区,开源代码托管平台 仓颉社区中下载解压 cangjie.vsix 插件 打开VSCode 按 Ctrl Shift X 弹出下图 按照上图步骤依次点击选中我们下…...
解决:Linux上SVN 1.12版本以上无法直接存储明文密码
问题:今天在Linux机器上安装了SVN,作为客户端使用,首次执行SVN相关操作,输入账号密码信息后,后面再执行SVN相关操作(比如"svn update")还是每次都需要输入密码。 回想以前在首次输入…...
Mongodb多键索引中索引边界的混合
学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第93篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关…...
如何利用windows本机调用Linux服务器,以及如何调用jupyter界面远程操控
其实这篇文章没必要存在,教程太多了 参考博客(1 2 3),如侵删 奈何网上的大神总是会漏掉一些凡人遇到的小问题 (1) 建议下载PuTTy for windows,从而建立与远程服务器的SSH连接 需要确认目标服…...
如何定位Milvus性能瓶颈并优化
假设您拥有一台强大的计算机系统或一个应用,用于快速执行各种任务。但是,系统中有一个组件的速度跟不上其他部分,这个性能不佳的组件拉低了系统的整体性能,成为了整个系统的瓶颈。在软件领域中,瓶颈是指整个路径中吞吐…...
阿里云服务器 篇三:提交搜索引擎收录
文章目录 系列文章推荐:为网站注册域名判断网站是否已被搜索引擎收录主动提交搜索引擎收录未查询到收录结果时,根据提示进行提交网站提交网站时一般需要登录账号主动提交网站可缩短爬虫发现网站链接时间,但不保证一定能够收录所提交的网站百度提交地址360搜索提交地址搜狗提…...
Qwen3-ASR-1.7B功能体验:实时录音识别与批量文件处理,实用功能全解析
Qwen3-ASR-1.7B功能体验:实时录音识别与批量文件处理,实用功能全解析 1. 引言:当语音识别真正变得“好用”时,会发生什么? 想象一下这个场景:你刚结束一场重要的客户会议,手机里录下了整整45分…...
weixin258基于微信小程序的课堂点名系统springboot(文档+源码)_kaic
第5章 系统实现进入到这个环节,也就可以及时检查出前面设计的需求是否可靠了。一个设计良好的方案在运用于系统实现中,是会帮助系统编制人员节省时间,并提升开发效率的。所以在系统的编程阶段,也就是系统实现阶段,对于…...
解决 chattts.core 的 invalid characters 警告:高效字符处理方案
最近在折腾一个文本转语音的项目,用到了 chattts 这个库。功能很强大,但时不时就会在日志里看到一行刺眼的警告:chattts.core:invalid characters found! : {:}。这个警告虽然不会直接让程序崩溃,但就像鞋里的一粒沙子,…...
Android密钥认证踩坑实录:GtsGoogleAttestationHostTestCases模块fail排查指南
Android密钥认证深度排错指南:从GtsGoogleAttestationHostTestCases失败到系统级修复 当你深夜盯着CI系统里那片刺眼的红色——GtsGoogleAttestationHostTestCases模块测试失败时,作为Android系统工程师的你是否感到一阵窒息?这不仅仅是又一个…...
ABAQUS三维多孔材料建模:自定义与多软件导出
ABAQUS三维多孔材料,可生成实体多孔材料空隙连接或六面体网格映射模型。 可自定义参数包括基体长宽高,骨料半径范围,体积比以及网格的尺寸。 可导出到comsol ansys cad等。最近在研究ABAQUS三维多孔材料建模,发现了一些超有趣的功…...
FLUX.小红书极致真实V2实战应用:为小红书笔记自动生成封面+内页配图
FLUX.小红书极致真实V2实战应用:为小红书笔记自动生成封面内页配图 重要提示:本文介绍的FLUX.小红书极致真实V2工具为本地部署方案,无需网络连接,所有图像生成均在本地完成,确保数据隐私和安全。 1. 工具简介ÿ…...
PowerShell自动化批量修改注册表路径:解决用户文件夹重命名后的遗留问题
1. 为什么需要批量修改注册表路径 最近帮同事处理了一个典型的Windows系统问题:他的用户文件夹最初使用了中文命名,导致各种开发工具和环境频繁报错。这个问题其实很常见,特别是当我们需要重命名用户文件夹时,虽然修改了系统路径&…...
Python实战:用PuLP库解决整数规划问题(附完整代码)
Python实战:用PuLP库解决整数规划问题(附完整代码) 整数规划是运筹优化中常见的一类问题,广泛应用于生产调度、资源分配、路径规划等实际场景。与线性规划不同,整数规划要求决策变量取整数值,这使得问题求解…...
解决Unity与3DMax模型单位与中心点偏差的完整指南
1. 为什么Unity和3DMax会出现单位偏差? 这个问题困扰过几乎所有3D美术和Unity开发者。我第一次遇到时,明明在3DMax里建了个1米高的角色,导入Unity后却变成了100米高的巨人,场景直接崩了。后来发现,这其实是两个软件默认…...
Dify异步任务接入全链路拆解(含WebSocket重连+状态回溯+超时熔断)
第一章:Dify自定义节点异步处理如何实现快速接入 Dify 的自定义节点(Custom Node)机制支持通过 Python 函数扩展工作流逻辑,而异步处理能力是提升高延迟任务(如外部 API 调用、大模型推理、文件下载等)执行…...
