PCM格式

通过websocket发送音频数据。

<html>
<head><meta charset="utf-8"><title>test</title>
</head>
<body>
<div><button id="intercomBegin">开始对讲</button><button id="intercomEnd">关闭对讲</button>
</div>
</body>
<script>var begin = document.getElementById('intercomBegin');var end = document.getElementById('intercomEnd');navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;var ws = null;//实现WebSocketvar record=null;//多媒体对象,用来处理音频var timeInte = null;//定义一个定时器begin.onclick = function() {console.log('开始对讲')}end.onclick = function() {console.log('关闭对讲')if(ws) {ws.close();record.stop();clearInterval(timeInte);}}function init(rec){record = rec;}if (!navigator.getUserMedia) {alert('浏览器不支持音频输入');}else{navigator.getUserMedia({ audio: true },function (mediaStream) {init(new Recorder(mediaStream));},function(error){console.log(error)})}//录音对象var Recorder = function(stream) {var sampleBits = 16;//输出采样数位 8, 16var sampleRate = 8000;//输出采样率var context = new AudioContext();var audioInput = context.createMediaStreamSource(stream);var recorder = context.createScriptProcessor(4096, 1, 1);var audioData = {size: 0          //录音文件长度, buffer: []    //录音缓存, inputSampleRate: sampleRate    //输入采样率, inputSampleBits: 16      //输入采样数位 8, 16, outputSampleRate: sampleRate, oututSampleBits: sampleBits, clear: function() {this.buffer = [];this.size = 0;}, input: function (data) {this.buffer.push(new Float32Array(data));this.size += data.length;}, compress: function () { //合并压缩//合并var data = new Float32Array(this.size);var offset = 0;for (var i = 0; i < this.buffer.length; i++) {data.set(this.buffer[i], offset);offset += this.buffer[i].length;}//压缩var compression = parseInt(this.inputSampleRate / this.outputSampleRate);var length = data.length / compression;var result = new Float32Array(length);var index = 0, j = 0;while (index < length) {result[index] = data[j];j += compression;index++;}return result;}, encodePCM: function(){//这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);var bytes = this.compress();var dataLength = bytes.length * (sampleBits / 8);var buffer = new ArrayBuffer(dataLength);var data = new DataView(buffer);var offset = 0;for (var i = 0; i < bytes.length; i++, offset += 2) {var s = Math.max(-1, Math.min(1, bytes[i]));data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);}return new Blob([data]);}};this.start = function () {audioInput.connect(recorder);recorder.connect(context.destination);}this.stop = function () {recorder.disconnect();}this.getBlob = function () {return audioData.encodePCM();}this.clear = function() {audioData.clear();}recorder.onaudioprocess = function (e) {audioData.input(e.inputBuffer.getChannelData(0));}};function receive(data) {if( typeof e == 'string' && JSON.parse(e).message=='OK'){console.log('OK');}else{var buffer = (new Response(data)).arrayBuffer();buffer.then(function(buf){console.log("################recv start ####################################");var audioContext = new ( window.AudioContext || window.webkitAudioContext )();var fileResult =addWavHeader(buf, '8000', '16', '1');//解析数据转码wavaudioContext.decodeAudioData(fileResult, function(buffer) {_visualize(audioContext,buffer);//播放});console.log("################recv end ####################################");});}}//处理音频流,转码wavvar addWavHeader = function(samples,sampleRateTmp,sampleBits,channelCount){var dataLength = samples.byteLength;var buffer = new ArrayBuffer(44 + dataLength);var view = new DataView(buffer);function writeString(view, offset, string){for (var i = 0; i < string.length; i++){view.setUint8(offset + i, string.charCodeAt(i));}}var offset = 0;/* 资源交换文件标识符 */writeString(view, offset, 'RIFF'); offset += 4;/* 下个地址开始到文件尾总字节数,即文件大小-8 */view.setUint32(offset, /*32*/ 36 + dataLength, true); offset += 4;/* WAV文件标志 */writeString(view, offset, 'WAVE'); offset += 4;/* 波形格式标志 */writeString(view, offset, 'fmt '); offset += 4;/* 过滤字节,一般为 0x10 = 16 */view.setUint32(offset, 16, true); offset += 4;/* 格式类别 (PCM形式采样数据) */view.setUint16(offset, 1, true); offset += 2;/* 通道数 */view.setUint16(offset, channelCount, true); offset += 2;/* 采样率,每秒样本数,表示每个通道的播放速度 */view.setUint32(offset, sampleRateTmp, true); offset += 4;/* 波形数据传输率 (每秒平均字节数) 通道数×每秒数据位数×每样本数据位/8 */view.setUint32(offset, sampleRateTmp * channelCount * (sampleBits / 8), true); offset +=4;/* 快数据调整数 采样一次占用字节数 通道数×每样本的数据位数/8 */view.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;/* 每样本数据位数 */view.setUint16(offset, sampleBits, true); offset += 2;/* 数据标识符 */writeString(view, offset, 'data'); offset += 4;/* 采样数据总数,即数据总大小-44 */view.setUint32(offset, dataLength, true); offset += 4;function floatTo32BitPCM(output, offset, input){input = new Int32Array(input);for (var i = 0; i < input.length; i++, offset+=4){output.setInt32(offset,input[i],true);}}function floatTo16BitPCM(output, offset, input){input = new Int16Array(input);for (var i = 0; i < input.length; i++, offset+=2){output.setInt16(offset,input[i],true);}}function floatTo8BitPCM(output, offset, input){input = new Int8Array(input);for (var i = 0; i < input.length; i++, offset++){output.setInt8(offset,input[i],true);}}if(sampleBits == 16){floatTo16BitPCM(view, 44, samples);}else if(sampleBits == 8){floatTo8BitPCM(view, 44, samples);}else{floatTo32BitPCM(view, 44, samples);}return view.buffer;}//播放音频var _visualize = function(audioContext, buffer) {var audioBufferSouceNode = audioContext.createBufferSource(),analyser = audioContext.createAnalyser(),that = this;//将信号源连接到分析仪audioBufferSouceNode.connect(analyser);//将分析仪连接到目的地(扬声器),否则我们将听不到声音analyser.connect(audioContext.destination);//然后将缓冲区分配给缓冲区源节点audioBufferSouceNode.buffer = buffer;//发挥作用if (!audioBufferSouceNode.start) {audioBufferSouceNode.start = audioBufferSouceNode.noteOn //在旧浏览器中使用noteOn方法audioBufferSouceNode.stop = audioBufferSouceNode.noteOff //在旧浏览器中使用noteOff方法};//如果有的话,停止前一个声音if (this.animationId !== null) {cancelAnimationFrame(this.animationId);}audioBufferSouceNode.start(0);audo.source = audioBufferSouceNode;audo.audioContext = audioContext;}begin.onclick = function() {var ws = new WebSocket("ws://127.0.0.1:6200");ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据ws.onopen = function(event) {console.log('握手成功');//业务命令构建var data = {"cmd": "jtv",//发送命令"id": "018665897939",//发送设备id"type": 1,//对讲类型"channel": 0//语音通道}//ws.send(JSON.stringify(data));   //这里是发送消息。不包括音频数据,先注掉};timeInte=setInterval(function(){if(ws.readyState==1){//ws进入连接状态,则每隔500毫秒发送一包数据record.start();console.log("#######################send Blob start ##############################");console.log(record.getBlob());ws.send(record.getBlob());    //发送音频数据console.log("#######################send Blob end ##############################");record.clear(); //每次发送完成则清理掉旧数据}},500);  //每隔500ms发送一次,定时器///ws.onmessage = function (evt){console.log( "Received Message: " + evt.data);receive(evt.data);}///}</script>
</html>

通过服务器来接收音频数据。这个时间可以以文件形式保存下来为.pcm就可以了。这里就使用工具来接收

最后生成pcm文件

保存好用.用Audacity工具来播放,看是不是正常的音频文件

播放正常。证明是个pcm的音频文件。得到了pcm(裸数据),我们可以做一个把pcm转成wav文件

#include <stdio.h>
#include <string.h>/*** Convert PCM16LE raw data to WAVE format* @param pcmpath       Input PCM file.* @param channels      Channel number of PCM file.* @param sample_rate   Sample rate of PCM file.* @param wavepath      Output WAVE file.*/
int simplest_pcm16le_to_wave(const char *pcmpath, int channels, int sample_rate, const char *wavepath)
{printf("#########################1111#############################\n");typedef struct WAVE_HEADER{char    fccID[4];       //内容为""RIFFunsigned long dwSize;   //最后填写,WAVE格式音频的大小char    fccType[4];     //内容为"WAVE"}WAVE_HEADER;typedef struct WAVE_FMT{char    fccID[4];          //内容为"fmt "unsigned long  dwSize;     //内容为WAVE_FMT占的字节数,为16unsigned short wFormatTag; //如果为PCM,改值为 1unsigned short wChannels;  //通道数,单通道=1,双通道=2unsigned long  dwSamplesPerSec;//采用频率unsigned long  dwAvgBytesPerSec;/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */unsigned short wBlockAlign;//==wChannels*uiBitsPerSample/8unsigned short uiBitsPerSample;//每个采样点的bit数,8bits=8, 16bits=16}WAVE_FMT;typedef struct WAVE_DATA{char    fccID[4];       //内容为"data"unsigned long dwSize;   //==NumSamples*wChannels*uiBitsPerSample/8}WAVE_DATA;if(channels==2 || sample_rate==0){channels = 2;sample_rate = 44100;}int bits = 16;WAVE_HEADER pcmHEADER;WAVE_FMT    pcmFMT;WAVE_DATA   pcmDATA;unsigned short m_pcmData;FILE *fp, *fpout;printf("#########################2222#############################\n");fp = fopen(pcmpath, "rb+");if(fp==NULL){printf("Open pcm file error.\n");return -1;}fpout = fopen(wavepath, "wb+");if(fpout==NULL){printf("Create wav file error.\n");return -1;}printf("########################3333##############################\n");/* WAVE_HEADER */memcpy(pcmHEADER.fccID, "RIFF", strlen("RIFF"));memcpy(pcmHEADER.fccType, "WAVE", strlen("WAVE"));fseek(fpout, sizeof(WAVE_HEADER), 1);   //1=SEEK_CUR/* WAVE_FMT */memcpy(pcmFMT.fccID, "fmt ", strlen("fmt "));pcmFMT.dwSize = 16;pcmFMT.wFormatTag = 1;pcmFMT.wChannels = 2;pcmFMT.dwSamplesPerSec = sample_rate;pcmFMT.uiBitsPerSample = bits;/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */pcmFMT.dwAvgBytesPerSec = pcmFMT.dwSamplesPerSec*pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;/* ==wChannels*uiBitsPerSample/8 */pcmFMT.wBlockAlign = pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;printf("##################4444####################################\n");fwrite(&pcmFMT, sizeof(WAVE_FMT), 1, fpout);/* WAVE_DATA */memcpy(pcmDATA.fccID, "data", strlen("data"));pcmDATA.dwSize = 0;fseek(fpout, sizeof(WAVE_DATA), SEEK_CUR);printf("##################5555####################################\n");fread(&m_pcmData, sizeof(unsigned short), 1, fp);while(!feof(fp)){pcmDATA.dwSize += 2;fwrite(&m_pcmData, sizeof(unsigned short), 1, fpout);fread(&m_pcmData, sizeof(unsigned short), 1, fp);}printf("##################4444####################################\n");/*pcmHEADER.dwSize = 44 + pcmDATA.dwSize;*///修改时间:2018年1月5日pcmHEADER.dwSize = 36 + pcmDATA.dwSize;rewind(fpout);fwrite(&pcmHEADER, sizeof(WAVE_HEADER), 1, fpout);fseek(fpout, sizeof(WAVE_FMT), SEEK_CUR);fwrite(&pcmDATA, sizeof(WAVE_DATA), 1, fpout);fclose(fp);fclose(fpout);printf("##################6666####################################\n");return 0;
}int main()
{simplest_pcm16le_to_wave("E:\\project\\audio\\in.pcm", 2, 44100, "E:\\project\\audio\\out.wav");return 0;
}

再用Audacity播放out.wav文件,可正常播放。

涉及到音频领域。后面文章,再继讲如何把pcm转在g711a或是aac音频。

html5使用websocket发送(PCM)音频数据到服务器,再转在wav文件相关推荐

  1. Android录音,PCM音频数据打包成AAC

    之前做TUTK音视频流的拉流APP时踩了很多坑,曾经因为编解码问题熬了好几次夜,网上的资料也很有限,自己一点点拼凑来的,在这里Mark一下曾经走过的路. android的音频采集,我用的是androi ...

  2. Java Mp3转化WAV/PCM音频数据,解码详细解析,提取每一帧数据集合/比特流/播放,一行代码!

    导言 大家好!我是原子君 1.因为Java本身只支持,wav,缺少mp3的解码器,所以Java自带的无法对mp3进行处理,这种MPEG-*音频有损压缩标准编码,更不要说使用Java的音频格式和音频流就 ...

  3. Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据

    一.实现说明 OpenSL ES的录音要比播放简单一些,在创建好引擎后,再创建好录音接口基本就可以录音了.在这里我们做的是流式录音,所以需要用至少2个buffer来缓存录制好的PCM数据,这里我们可以 ...

  4. PCM音频数据音量大小调节

    转载:http://blog.csdn.net/timsley/article/details/50683084 PCM音频数据增大或减小的原理主要是,将采样的数据乘上一个数字或者是除以一个数字,但要 ...

  5. 基于C的PCM音频数据的读取、处理与写入(一)

    PCM音频数据,是模拟音频信号经过数模转换后直接形成的二进制序列,是一种罕见的音频文件格式,因此在对pcm文件进行读写的时候,要选用以二进制的形式打开. 此次读写的PCM文件,单声道,采样率是16KH ...

  6. PCM音频数据、DSD音频数据,spdif,以及DOP格式说明

    了解PCM音频数据.DSD音频数据,spdif看下面连接 https://blog.csdn.net/LINZAI508/article/details/111413061#commentBox DO ...

  7. SDL播放PCM音频数据

    SDL播放PCM音频数据 1.PCM简介    PCM(Pulse CodeModulation,脉冲编码调制)音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样.量化.编码转换成的标准数字 ...

  8. AudioTrack 播放PCM音频数据

    AudioTrack 可以用来播放PCM数据,上一篇博客我讲了AudioRecord可以录制PCM数据 AudioTrack实例可以在两种模式下运行:静态或流式传输. 在Streaming模式下,应用 ...

  9. 【C++】基于OpenGL的音乐可视化(一):PCM音频数据的解析

    PCM的数据解析出音量信息首先要知道的一些基础常识: 采样频率,指每秒钟取得声音样本的次数,采样频率越高,包含的声音信息自然就越多,声音也就越好,频率越高,保存需要的空间也会高. 采样位宽,即采样值, ...

最新文章

  1. 谈谈被大家过于在乎的性能
  2. yota3墨水屏设置_【YotaPhoneYOTA3评测】外观:没有全面屏但有墨水屏_YotaPhone YOTA 3_手机评测-中关村在线...
  3. 《Linux内核设计与实现》读书笔记(十一)- 定时器和时间管理
  4. C++很难学?这个ACM金牌大佬可不这么认为!
  5. java父包引用_父类引用指向子类对象(java)
  6. opensource项目_最佳Opensource.com:访谈
  7. java 抽象类的匿名类_Java匿名内部类(通过继承抽象类来实现)
  8. Hibernate3的jar包
  9. Black Salt Audio All Plug-Ins Mac 实用音频压缩插件套装
  10. unity获取麦克风音量_Unity获取麦克风实现吹气球效果
  11. 细丝菲涅尔衍射MATLAB,任意孔型菲涅尔衍射matlab仿真.docx
  12. Linux USB 鼠标驱动程序详解
  13. 关于力学环境中振动试验的知识
  14. 小甲鱼 OllyDbg 教程系列 (十四) : 模态对话框 和 非模态对话框 之 URlegal 和 movgear...
  15. SCC flex布局
  16. CTF题库实验吧 py的交易
  17. 解决Macbook Pro蓝牙不可用问题
  18. 猎豹移动推出直播产品Live.me风靡美国
  19. Ubuntu下使用NTP同步对时
  20. 人工智能知识全面讲解:特征工程

热门文章

  1. 构建 Darknet 分类器 (Tiny Darknet) 训练数据集 (color recognition 颜色识别/color classification 颜色分类)
  2. 使用 easyExcel 生成多个 excel 并打包成zip压缩包
  3. 【知识兔】Excel教程小技巧之常用快捷键汇总
  4. i.MX6ULL系统移植 | 移植NXP官方linux4.1.15内核
  5. IMX6 LCD 参数匹配过程分析
  6. Unity3D 多种播放音效的方式
  7. No qualifying bean of type [com.service.UserService] found for dependency: 解决方案
  8. 练习打字速度效果很好的网站(本人亲测)
  9. Qt 实现libVLC视频显示
  10. 【人工智能】5.不确定性推理