【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搜索提交地址搜狗提…...
 
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
 
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
 
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
 
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
 
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
 
认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...
