最近公司安排一个任务,对接IP网络广播,web版的,需要在浏览器直接获取麦克风音频,然后发送给服务端,IP网络广播和服务器是在同一个网段,然后调用第三方进行广播发声。

后端是java,前端是Ant Design Vue,浏览器用的是chrome。

浏览器端是在网上找的采集音频数据的代码,支持16K采样率,16位/样。直播发声肯定要跟服务器及时通信,采用的是websocket,

websocket每次发送数据给服务器有大小限制,具体怎么解除限制我查了不少文档,还是没能解决,暂时就设定150毫秒传输一次,这样可以做到数据不超上限。

Recorder.js是在网上找的,自己改了下数据处理的,这里用的recorder.js。

var time;
import axios from '@/utils/request'
export default class Recorder {constructor(stream, config) {//兼容window.URL = window.URL || window.webkitURL;navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;config = config || {};config.sampleBits = config.sampleBits || 16;   //采样数位 8, 16config.sampleRate = config.sampleRate || 8000; //采样率(1/6 44100)this.context = new (window.webkitAudioContext || window.AudioContext)();this.audioInput = this.context.createMediaStreamSource(stream);this.createScript = this.context.createScriptProcessor || this.context.createJavaScriptNode;this.recorder = this.createScript.apply(this.context, [4096, 1, 1]);this.audioData = {size: 0,          //录音文件长度buffer: [],    //录音缓存inputSampleRate: this.context.sampleRate,   //输入采样率inputSampleBits: 16,     //输入采样数位 8, 16outputSampleRate: config.sampleRate,   //输出采样率oututSampleBits: config.sampleBits,       //输出采样数位 8, 16input: function (data) {this.buffer.push(new Float32Array(data));this.size += data.length;},compress: function () { //合并压缩//合并let data = new Float32Array(this.size);let offset = 0;for (let i = 0; i < this.buffer.length; i++) {data.set(this.buffer[i], offset);offset += this.buffer[i].length;}this.buffer = [];this.size = 0;//压缩let compression = parseInt(this.inputSampleRate / this.outputSampleRate);let length = data.length / compression;let result = new Float32Array(length);let index = 0, j = 0;while (index < length) {result[index] = data[j];j += compression;index++;}return result;},encodeWAV: function () {let array = new Array();let sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);let sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);let bytes = this.compress();let dataLength = bytes.length * (sampleBits / 8);let buffer = new ArrayBuffer(44 + dataLength);let data = new DataView(buffer);let channelCount = 1;//单声道let offset = 0;let writeString = function (str) {for (let i = 0; i < str.length; i++) {data.setUint8(offset + i, str.charCodeAt(i));}};// 资源交换文件标识符writeString('RIFF');offset += 4;// 下个地址开始到文件尾总字节数,即文件大小-8data.setUint32(offset, 36 + dataLength, true);offset += 4;// WAV文件标志writeString('WAVE');offset += 4;// 波形格式标志writeString('fmt ');offset += 4;// 过滤字节,一般为 0x10 = 16data.setUint32(offset, 16, true);offset += 4;// 格式类别 (PCM形式采样数据)data.setUint16(offset, 1, true);offset += 2;// 通道数data.setUint16(offset, channelCount, true);offset += 2;// 采样率,每秒样本数,表示每个通道的播放速度data.setUint32(offset, sampleRate, true);offset += 4;// 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true);offset += 4;// 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8data.setUint16(offset, channelCount * (sampleBits / 8), true);offset += 2;// 每样本数据位数data.setUint16(offset, sampleBits, true);offset += 2;// 数据标识符writeString('data');offset += 4;// 采样数据总数,即数据总大小-44data.setUint32(offset, dataLength, true);offset += 4;// 写入采样数据if (sampleBits === 8) {for (let i = 0; i < bytes.length; i++, offset++) {let s = Math.max(-1, Math.min(1, bytes[i]));let val = s < 0 ? s * 0x8000 : s * 0x7FFF;val = parseInt(255 / (65535 / (val + 32768)));data.setInt8(offset, val, true);}} else {for (let i = 0; i < bytes.length; i++, offset += 2) {let s = Math.max(-1, Math.min(1, bytes[i]));data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);array.push(parseInt(s < 0 ? s * 0x8000 : s * 0x7FFF));}}return array;//  return new Blob([data], {type: 'audio/wav'});}};}//开始录音start(param) {this.audioInput.connect(this.recorder);this.recorder.connect(this.context.destination);//音频采集let self = this;this.initWebSocket();this.sendMsg(self,param);this.recorder.onaudioprocess = function (e) {self.audioData.input(e.inputBuffer.getChannelData(0));};};initWebSocket () {this.websock = new WebSocket('ws://localhost:8083/dispatch/websocket/sendVoice');this.websock.onopen = this.websocketonopen;this.websock.onerror = this.websocketonerror;this.websock.onmessage = this.websocketonmessage;this.websock.onclose = this.websocketclose;};websocketonopen () {console.log("WebSocket连接成功");};websocketonerror (e) {console.log("WebSocket连接发生错误");};websocketsend(data,self){//数据发送if(self.websock.readyState === self.websock.CLOSED){//     self.restart(self);}else {try {self.websock.send(data);} catch (e) {//       self.restart(self);}}};websocketonmessage (e) {};websocketclose (e) {try {this.websock.close();} catch (e1) {console.log(e1);}console.log("connection closed (" + e + ")");};sendMsg(self,param){time = setInterval(function(){let array = self.audioData.encodeWAV();self.audioData.buffer = [];self.audioData.size = 0;let json = {id:param.id,pcm:array,};try {self.websocketsend(JSON.stringify(json), self);} catch (e) {console.log(e);}},150)}restart(self){clearInterval(time);self.initWebSocket();self.sendMsg(self);}//停止stop() {clearInterval(time);this.websock.close();this.recorder.disconnect();};//获取音频文件getBlob() {this.stop();//   return this.audioData.encodeWAV();//  return this.audioData.compress();};//回放play(audio) {audio.src = window.URL.createObjectURL(this.getBlob());};//清理缓存的录音数据clear() {this.audioData.buffer = [];this.audioData.size = 0;};static throwError(message) {console.log("Error:" + message);throw new function () {this.toString = function () {return message;}};};static canRecording() {return (navigator.getUserMedia != null);}static get(callback, config) {if (callback) {if (Recorder.canRecording()) {navigator.getUserMedia({audio: true}, //只启用音频function (stream) {let rec = new Recorder(stream, config);callback(rec);},function (error) {switch (error.code || error.name) {case 'PERMISSION_DENIED':case 'PermissionDeniedError':Recorder.throwError('用户拒绝提供信息。');break;case 'NOT_SUPPORTED_ERROR':case 'NotSupportedError':Recorder.throwError('浏览器不支持硬件设备。');break;case 'MANDATORY_UNSATISFIED_ERROR':case 'MandatoryUnsatisfiedError':Recorder.throwError('无法发现指定的硬件设备。');break;default:Recorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name));break;}});} else {Recorder.throwError('当前浏览器不支持录音功能。');return;}}};
}

record-sdk.js

import Recorder from "./Recorder";
export default class Record {startRecord(param) {let self = this;try {Recorder.get(rec => {console.log("init recorder component now.");self.recorder = rec;self.recorder.start(param);console.log("start record now.");param.success("record successfully!");});} catch (e) {param.error("record failed!" + e);}}stopRecord() {console.log("stop record now.");let self = this;try {self.recorder.stop();console.log("stop successfully.");} catch (e) {console.log("stop record failed!" + e);}}play() {console.log("start play record now.");let self = this;try {self.recorder.play();console.log("play successfully.");} catch (e) {console.log("play record failed!" + e);}}
}

页面中引入import Record from "@/api/admin/commons/record-sdk";

export default {data () {return {recorder: new Record(),}
methods: {
this.recorder.startRecord({success: res => {this.$message.success("开始喊话");},error: res => {console.log("start record failed.");this.$message.error("当前浏览器暂不支持录音");}
});
}
}

后端websocket每个150毫秒接收一次pcmdata是16K采样率,16位/样的,由于我用的是第三方的IP网络广播,有提供对接demo,按照需求将pcmdata分割,发送给IP广播,就可以发声了。

新手写博,如果有什么好的建议或者意见可以发消息给我。

浏览器获得电脑麦克风音频进行广播发声(非录音播放)相关推荐

  1. 看看电脑麦克风没声音怎么办

    看看 电脑麦克风没声音怎么办 最近,很多用户向贵州电脑网反映说麦克风没声音怎么办,对于电脑麦克风没声音问题可能是多方面原因造成的.先检查麦克风和电脑连接是否正常,麦克风是否插错地方等. 再看看能不能解 ...

  2. ZOOM H1n录音笔怎么连接电脑做音频输入麦克风【教程】

    一.ZOOM 录音笔连接电脑做音频输入麦克风,以H1n为例 以前试过用usb连接,但是发现音质不对.又试过用公对公3.5mm接头连接电脑麦口和录音笔耳机输出口,一顿操作猛如虎,一听音质超级糊. 因为买 ...

  3. vb.net如何查询电脑麦克风收到声音_EMUI 10.1 跨屏协同实测:这一次把你的手机「搬」进电脑...

    智能手机发展到现在,我们越来越需要手机与其他设备进行互联互通.电脑是我们办公最常用的工具,手机则是生活必需设备,这两者的协同需求,自然也就成为了大多数用户的痛点. Apple 用隔空投送.接力.随航等 ...

  4. 电脑常用音频剪辑软件_常用的音频编辑软件

    用电脑来进行音频制作是目前很多人的需求,譬如说小视频,微电影,广播电台片花等等,这需要音频制作处理软件的支持.目前市场上的音频处理软件很多,比较常用和受欢迎的也不少.这里选择了10款常用的音频制作软件 ...

  5. 使用计算机录制声音10,Win10电脑麦克风无法录音怎么解决 win10麦克风声音无法输入的解决方法...

    在使用win10系统的时候很多用户反映说会遇到这样那样的问题,当升级到win10系统之后,有部分用户发现要使用麦克风录音的时候,发现麦克风没有声音无法输入,导致麦克风无法录音,该怎么解决这个问题呢,现 ...

  6. 将手机3.5mm耳机作为电脑麦克风

    众所周知,电脑的耳机和麦克风插口是分开的,与手机3.5mm耳机不兼容,但当我们要与朋友开黑,手边又没有电脑专用的麦克风时,该怎么办呢? 这时我们可以用曲线救国的方式,下载一个软件:WO Mic,将手机 ...

  7. C# 电脑麦克风录音

    C# 电脑麦克风录音 本实例通过Naudio库完成麦克风录音并把PCM脉冲信号保存成wav音频文件.关于音频的采样率.比特率.声道等问题请查阅相关资料,本示例不做解释.Naudio库 请从NuGet搜 ...

  8. 硅麦克风的声学设计指南_电脑麦克风入门指南

    硅麦克风的声学设计指南 With Gmail adding the ability to make free calls within the US and Canada, now is a grea ...

  9. windows录屏html文件,如何直接使用浏览器进行电脑录屏

    正常我们有录制需求的话,都是直接使用第三方软件操作:但是如果下载的地方不对,经常会附带一堆捆绑软件.但是直接使用浏览器在线录屏可以有效避免这个问题. 浏览器在线录屏的优势 ①打开浏览器就能在电脑端录制 ...

最新文章

  1. C++11中std::unique_lock的使用
  2. Anychat视频会议系统企业信息化的完美衔接
  3. 调整weblogic内存的分配和使用
  4. SqlServer还原数据库时提示:异常终止,不能在此版本的SQL Server中启动,因为它包含分区函数
  5. Python scrapy爬取京东,百度百科出现乱码,解决方案
  6. vivado路径最大时钟约束_Vivado使用误区与进阶系列(五)XDC约束技巧之I/O篇(下)...
  7. Oracle高可用概述(HA与RAC的关系解惑)
  8. Struts2源码阅读(一)_Struts2框架流程概述
  9. Gartner:2019年公有云服务六大趋势
  10. Bootstrap CSS 编码规范之Less 和 Sass 中的嵌套
  11. 【例5.2】组合的输出
  12. iOS开发笔记 2、Cocoa简明
  13. 连续两天,8 大技术论坛,微软超 60 个烧脑议题等你来战
  14. 跟着弦哥学人工智能2—HAND-CRAFTED RULES实现的人工智能及其缺陷
  15. ERLANG recon使用示例
  16. 用 Python 给程序加个进度条,让你的程序看起来更炫酷
  17. 欧文工学院计算机,UCI的EECS「加州大学欧文分校电气工程与计算机科学系」
  18. 愤怒大叔-喝酒聚会游戏
  19. 机器学习预测结果评估展示_评估通用社区测试计划的性能并预测结果
  20. c++ std::swap() 函数

热门文章

  1. 【BZOJ1455】罗马游戏
  2. Digital Pixel 杂志 Joomla模板 joomla摄影艺术数码作品博客商业
  3. 瑞波2020年第三季度XRP市场报告节选
  4. RCU前传:从同步到RCU的引入
  5. STM32串口通信的 USART_ClearFlag(USART1,USART_FLAG_TC); 添加后程序出现bug;( USART_ClearFlag(USART_TypeDef* USART)
  6. 计算机开机卡在进入桌面的时候,电脑启动时卡在“正在启动WINDOWS”界面如何处理...
  7. WWX的520(结构体排序)
  8. Vmware ESXi 部署飞塔虚拟机防火墙
  9. siki学院 游戏热更新实战案例(基于xLua) 捕鱼达人 完整素材
  10. 剑指offer-矩阵中的路径