H5 PCM转WAV实时音频直播代码实现细节

2023-11-09

一、前端实现

H5数据采集

web audio的概念和使用详见;接口文档

采集音频数据

var context = new AudioContext();       
var audioInput = context.createMediaStreamSource(stream);  
var recorder = context.createScriptProcessor(4096, 1, 1); 
var context = new AudioContext();      
var audioInput = context.createMediaStreamSource(stream); 
var recorder = context.createScriptProcessor(4096, 1, 1);
recorder.onaudioprocess = function (e) {
      var channelData = e.inputBuffer.getChannelData(0);  // PCM数据   
      audioData.input(channelData);     
      ws.send(gRecorder.getBlob()); //发送pcm转wav音频数据 
      audioData.clear();       
}]

音频PCM转WAV

代码参考 https://www.bbsmax.com/A/rV57M9WzPD/ HZRecorder.js 实现

gRecorder.getBlob(); // 返回blod wav文件

WEBSOCKET推流

实例化websocket

                    ws = new WebSocket("ws://localhost:8084/myHandler");

                    ws.onopen = function () {
                        console.log('握手成功');
                    };


                    
ws.send(gRecorder.getBlob()); // websocket发送音频流

WEBSOCKET接收流

ws.onmessage = function (e) {
                        // 收到的音频二进制wav数据

                        var reader = new FileReader();
                        reader.readAsArrayBuffer(e.data); //转为ArrayBuffer
                        reader.onload = function () {
                            // WAV转PCM
                            context.decodeAudioData(reader.result, function (buffer) {
                                    var float32Array = buffer.getChannelData(0); // PCM数据
                                    audioChuncks.push(float32Array);//保存到播放的音频数组
                                },

                                function (e) {
                                    "Error with decoding audio data" + e.err
                                }
                            );

                        }
                    };

音频WAV转PCM

代码同上

context.decodeAudioData

H5播放音频

        this.play = function () {
            //创建播放音频对象
            let myBuffer = context.createBuffer(1, 4096, context.sampleRate);
            let source = context.createBufferSource();
            let playRecorder = context.createScriptProcessor(4096, 1, 1);
            source.connect(playRecorder);
            playRecorder.connect(context.destination);
            playRecorder.onaudioprocess = function (ev) {
                //播放audioChuncks里面真正的二进制数据;来源websocket.onmessage 
                if (audioChuncks.length > 0) {
                    ev.outputBuffer.copyToChannel(audioChuncks.shift() || new Float32Array(4096), 0, 0);
                }
            };

        }

也可以直接播放PCM,使用开源PCM-PLAYER

二、后端实现

springboot集成websocket;继承BinaryWebSocketHandler

接收音频

消息接收保存到文件

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        super.handleBinaryMessage(session, message);
        final ByteBuffer byteBuffer = message.getPayload();
        byte[] array = byteBuffer.array();
        final String fielName = getFileNameBySession(session);
        final File file = new File(fielName);
        try (FileOutputStream outputStream = new FileOutputStream(file, true)) {
            outputStream.write(array);
            outputStream.flush();
            outputStream.close();
        }
    }

发送音频

建立连接就实时发送音频数据

@Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
      
        //新建线程实时输出音频
        Thread thread = new Thread(new SendFileTask(session));
        thread.start();


    }

    static class SendFileTask implements Runnable {

        WebSocketSession session = null;

        public SendFileTask(WebSocketSession session) {
            this.session = session;
        }

        @Override
        public void run() {
            final String name = getFileNameBySession(session);
            final File file = new File(name);
            int oldFileSize = 0;
            while (session.isOpen()) {
                if (file.exists()) {
                    try (FileInputStream fileInputStream = new FileInputStream(file)) {
                        final int length = 726;
                        byte[] readByte = new byte[length];
                        int read = 0;
                        final long fileSize = file.length();
                        if (fileSize > oldFileSize) {
                            fileInputStream.skip(oldFileSize);
                            int offset = oldFileSize;
                            while ((read = fileInputStream.read(readByte, 0, length)) > 0) {
                                if (session.isOpen()) {
                                    offset = offset + read;
                                    oldFileSize = offset;
                                    session.sendMessage(new BinaryMessage(readByte, readByte.length != length));
                                } else {
           
                                    break;
                                }
                            }
                        }
                        fileInputStream.close();
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(150L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

参考文档:

  1. web音频流转发之音视频直播
  2. web音频流转发之音频源
  3. web音频流转发之AudioNode
  4. wav文件格式分析与详解
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

H5 PCM转WAV实时音频直播代码实现细节 的相关文章

  • 实战: 跨年烟花代码的实现(附源码)

    目录 前言 一 pandas是什么 二 代码结构 1 介绍主html代码 2 js文件介绍 GameCanvas js script js 运行效果 前言 本文章将介绍跨年烟花代码的实现以及源代码 提示 以下是本篇文章正文内容 一 pand
  • JSP通用分页

    通用分页核心思路 将上一次查询请求再发一次 只不过页码变了 实现步骤 1 先查询全部数据 baseDao
  • 前端学习之常见标签的使用(2)

    目录 h标签 p标签 br标签 字符实体 img标签 a标签 mailto链接 base标签 锚点 div span video H5新增 audio H5新增 h标签 h标签 标题标签 在HTML中 一共有六级标题标签 h1 h6 在显示
  • 微信H5如何关闭浏览器(如何监听手机的物理返回键)

    一 背景 背景是这样的 该项目进入h5时会通过 location replace xxx 或 location href xxx 跳转到某个地址 该地址会请求获得微信 openId 获取成功后再重定向到h5首页 那么问题来了 重定向会在微信
  • Vue组件按需引入时v-if和v-show的区别

    普通加载 在父组件中先import子组件 然后在components模块中注册子组件 在进 入页面时 会随着加载当前页面的js文件就加载子组件的内容 子组件的内容和父组件的内容在同一个js文件 按需加载 子组件显示的时候 才会去加载子组件的
  • vue+element-ui el-tabs切换面板el-tab-pane切换

    在vue项目中 el tabs在页面的右侧显示 切换面板 下面的内容是正常显示的 效果如下 代码如下 父组件
  • CSS 浏览器缩小之后页面错乱 块不见问题

    问题1 浏览器正常100 显示的时候 今日推荐是看得见的 浏览器缩小 小于100 之后 今日推荐被挤不见了 今日推荐块的DIV的CSS原配置是 today recommend py container width 1200px margin
  • JavaScript基础Day02:流程控制

    文章目录 1 顺序结构 2 分支结构 1 if语句 2 switch语句 3 循环结构 1 while语句 2 do while语句 3 for循环 1 顺序结构 2 分支结构 1 if语句 if 条件表达式 执行语句 if 条件表达式 成
  • Web前端开发概述

    Web World Wide Web 全球广域网 是指一种基于互联网的信息系统 通过超文本链接将全球各地的文档 图像 视频等资源相互关联起来 并通过Web浏览器进行交互浏览和访问 Web的发展使得人们可以方便地获取和共享各种类型的信息 成为
  • EduCoder_web实训作业--文本层次语义元素

    第一关 A D B B 第二关 strong 重要通知 strong
  • ElementUi常用组件创建前端页面

    elementui 创建前端页面
  • JS有小数保留两位,整数不显示小数

    在很多时候要展示数据 会有各种小数处理 碰到页面的数据要根据不同的情况展示不同格式的数据 比如得到的数据是一个小数 现在要将小数保留两位 而整数则不显示小数点 显示整数格式 使用toFixed n 方法 toFixed 2 里面的2表示保留
  • 58同城 -- 前端一面

    面我的是一个小哥哥 面试体验挺好的 大概进行了35分钟左右 自我介绍 面试内容 为什么向做前端 怎么学习的前端 本人非科班哈 然后问我项目 直接问项目 没问笔试令我有点意外 问我印象最深的项目 印象最深的功能 遇到的难点 前端存储的区别 C
  • HTML头部

    目录 实例 HTML 元素 HTML
  • 【H5】 svg画扇形饼图

    H5 svg画扇形饼图 效果图如下 封装代码如下 代码内有详细注解哦
  • HTML--后台管理系统

    后台管理系统
  • align-content 设置多行下的子元素排列方式 代码和图片展示

    align content 适用于 换行 多行 的情况下 单行无效 可以设置上对齐 居中拉伸和平均分配剩余空间等属性值 属性值 flex start 默认值 在侧轴头部开始排列 flex end 在侧轴尾部开始排列 center 在侧轴中间
  • JavaScript 实现html导出为PDF文件

    相信各位前端工程狮们在一些报表项目 管理系统项目中都会遇到在这样的需求 申请报 表格 简历等等图文信息有导出为PDF文件 下面是记录我在项目中完成该需求的代码dome 发布出来也是希望对大家有些帮助 1 整体思路 将HTML元素打印或导出为
  • 【HTML】HTML5的拖放你用了吗

    HTML HTML5的拖放你用了吗 引言 github HTML HTML5的拖放你用了吗 内容速递 看了本文您能了解到的知识 在 HTML5 中 拖放是标准的一部分 任何元素都能够拖放 拖放的操作 多用在拖拽排序列表 游戏拼图等 下文中出
  • 第8章 多媒体嵌入

    学习目标 了解视频 音频嵌入技术 能够总结HTML5视频 音频嵌入技术的优点 了解常用的视频文件格式和音频文件格式 能够归纳HTML5支持的视频和音频格式 掌握HTML5中视频的嵌入方法 能够在HTML5页面中添加视频文件 掌握HTML5中

随机推荐

  • Vscode 绿色系清新主题

    炎炎夏日 上班上的心浮气躁 敲代码的时候 只觉昏昏沉沉 浑浑噩噩 给vscode换一个一个清新美好的绿色主题 充满活力和希望吧 朋友们 收藏起来 每个季节换一个主题 打工快乐 1 green theme 主打一个绿色温温柔柔的绿色画风 真的
  • Unity3D AssetBundles 动态加载游戏资源

    AssetBundles are files which you can export from Unity to contain assets of your choice These files use a proprietary co
  • ERP的权限管理的操作与设计--开源软件诞生24

    赤龙ERP用户与权限管理讲解 第24篇 用日志记录 开源软件 的诞生 进入地址 点亮星星 祈盼着一个鼓励 博主开源地址 码云 https gitee com redragon redragon erp GitHub https github
  • 设计模式之享元模式

    享元模式是对象池的一种实现 用来尽可能减少内存使用量 它适合用于可能存在大量重复对象的场景 来缓存可共享的对象 达到对象共享 避免创建过多对象的效果 这样依赖就可以提升性能 避免内存移除等 享元对象中的部分状态是可以共享 可以共享的状态称为
  • 使用Microsoft Word2016无法正常对Latex文本转换的踩坑和解决方法

    相信很多人都遇到像我一样的问题 word2016中 有latex的按钮 按ALT 就可以开始写公式 复制粘贴latex公式之后 怎么就转换不了呢 就是如图这样的 左上角转换按钮为灰色 上网找呀找 找了很多资料 大多数都是介绍用法的 但是转换
  • 图像语义分割的前世今生

    1998年以来 人工神经网络识别技术已经引起了广泛的关注 并且应用于图像分割 基于神经网络的分割方法的基本思想是通过训练多层感知机来得到线性决策函数 然后用决策函数对像素进行分类来达到分割的目的 这种方法需要大量的训练数据 神经网络存在巨量
  • GIT基本使用记录

    1 git配置与查看用户名与邮箱命令 git config global user name your name git config global user email your email 163 com git config glob
  • 根据这些超参数构建Transformer模型。

    对不起 您需要提供更多信息 以便构建Transformer模型 您需要提供超参数的详细列表 以便构建模型 您可以提供以下超参数以构建Transformer模型 模型大小 例如 隐藏层的大小 头的数量 编码器和解码器层的数量 门控循环单元 G
  • 左值和右值

    左值引用 也就是 常规引用 不能绑定到要转换的表达式 字面常量 或返回右值的表达式 而右值引用恰好相反 可以绑定到这类表达式 但不能绑定到一个左值上 右值引用就是必须绑定到右值的引用 通过 获得 右值引用只能绑定到一个将要销毁的对象上 因此
  • mybatis-plus复杂条件查询

    针对 mybatisplus 的复杂条件 需要将条件封装到 QueryWrapper 和 UpdateWrapper 对象中 1 QueryWrapper 查询 删除条件封装 QueryWrapper 对象用于封装查询 删除条件 2 Upd
  • oracle数据库时分秒格式_Oracle如何输出指定格式的日期时间数据呢?

    摘要 下文讲述Oracle数据库输出指定的日期时间格式的方法分享 如下所示 实现思路 使用TO CHAR系统函数 指定输出格式为 即可将日期时间转换为指定格式的字符串 如 SELECT TO CHAR SYSDATE YYYY MM DD
  • 学生信息管理系统(C语言)

    高级程序设计 学生管理系统 C语言 本项目可以简单的实现学生信息的增 删 改 查 统计 存储等基本功能 环境是Dev C 创建学生信息文件 根据提示输入学生的各项信息 然后按学号对学生信息进行排序 并将排序后的学生信息存储到文件中 增加学生
  • 网络nan的原因_深度学习网络训练中出现nan的原因分析

    nan Not a Number 错误后果 造成训练准确率的断崖式下跌 两种出现地点 1 在loss函数中出现nan 出现原因 一般是因为tf中的log函数输入了 负数 或 0 值 出现log 0 0的情况 解决方法 使用tf clip b
  • MQTT

    MQTT 菜鸟资料收集 https blog csdn net bangdingshouji article details 52576110 https github com menudoproblema libemqtt https b
  • 使用exceljs导出excel表格

    背景 最近在使用electon写一个桌面程序 需要对数据进行excel导出操作 这里选择使用 exceljs 来完成这个功能 下面是exceljs导出功能的简单实现 功能实现 下载 exceljs yarn add exceljs 引入 e
  • 【Mysql】使用语句插入数据的方法

    mysql中常用的三种插入数据的语句 insert into表示插入数据 数据库会检查主键 如果出现重复会报错 replace into表示插入替换数据 需求表中有PrimaryKey 或者unique索引 如果数据库已经存在数据 则用新数
  • 【故障诊断】基于 KPCA 进行降维、故障检测和故障诊断研究(Matlab代码实现)

    个人主页 研学社的博客 欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 主要特点
  • Mongodb的安装部署

    Mongodb的安装部署 一 环境介绍 二 配置mongodb的yum源 三 安装mongodb 三 启动mongodb 1 mongodb启动 2 查看mongodb的状态 3 查看监听端口 四 进入mongodb 五 查看mongodb
  • 有关html,css的实用知识总结(二)

    1 CSS 选择符有哪些 哪些属性可以继承 优先级算法如何计算 1 id 选择器 myid 2 类选择器 myclassname 3 标签选择器 div h1 p 4 相邻选择器 h1 p 5 子选择器 ul lt li 6 后代选择器 l
  • H5 PCM转WAV实时音频直播代码实现细节

    一 前端实现 H5数据采集 web audio的概念和使用详见 接口文档 采集音频数据 var context new AudioContext var audioInput context createMediaStreamSource