最近公司需要用到web录音的功能
讲的都差不多
问题1:怎么上传
下载来的栗子也比较简单,可以直接运行
问题1:怎么上传
栗子中最后返回的是Blob数据
return new Blob([dataview], { type: type })
因为对html5不熟,所以又查了一些数据
原来HTML5中使用FormData这个对象好方便
var fd = new FormData(); fd.append("audioData", blob);var xhr = new XMLHttpRequest(); xhr.open("POST", url); xhr.send(fd);
在C#服务器端 如下代码就可以接收了
public void ProcessRequest(HttpContext context) { if (context.Request.Files.Count > 0) { context.Request.Files[0].SaveAs("d:\\1.wav"); } }
问题2:文件体积太大
是的,使用上面的栗子,直接录音保存后基本上2秒就需要400K,一段20秒的录音就达到了的4M
这样的数据根本无法使用,必须想办法压缩数据
我开始尝试读每一段代码
function encodeWAV(samples){ var buffer = new ArrayBuffer(44 + samples.length * 2); var view = new DataView(buffer); /* RIFF identifier */ writeString(view, 0, 'RIFF'); /* file length */ view.setUint32(4, 32 + samples.length * 2, true); /* RIFF type */ writeString(view, 8, 'WAVE'); /* format chunk identifier */ writeString(view, 12, 'fmt '); /* format chunk length */ view.setUint32(16, 16, true); /* sample format (raw) */ view.setUint16(20, 1, true); /* channel count */ view.setUint16(22, 2, true); /* sample rate */ view.setUint32(24, sampleRate, true); /* byte rate (sample rate * block align) */ view.setUint32(28, sampleRate * 4, true); /* block align (channel count * bytes per sample) */ view.setUint16(32, 4, true); /* bits per sample */ view.setUint16(34, 16, true); /* data chunk identifier */ writeString(view, 36, 'data'); /* data chunk length */ view.setUint32(40, samples.length * 2, true); floatTo16BitPCM(view, 44, samples); return view; }
上面的代码,就是把字节数据格式化成wav的格式的过程
所以我又去查了wav的头文件
要压缩,就要从上面三个红圈的地方入手
最简单的就是把双声道改成单声道的,
在录音的时候只需要记录一个声道就可以了
// 创建声音的缓存节点,createJavaScriptNode方法的 // 第二个和第三个参数指的是输入和输出都是双声道。 //recorder = context.createJavaScriptNode(bufferSize, 2, 2); recorder = context.createJavaScriptNode(bufferSize, 1, 1);//这里改成1 this.node.onaudioprocess = function(e){ if (!recording) return; worker.postMessage({ command: 'record', buffer: [ e.inputBuffer.getChannelData(0)//, //e.inputBuffer.getChannelData(1)// 这里只需要保存一个 ] }); } function exportWAV(type){ var bufferL = mergeBuffers(recBuffersL, recLength); //var bufferR = mergeBuffers(recBuffersR, recLength); var interleaved = interleave(bufferL);//, bufferR); //合并数据的时候去到对右声道的处理 var dataview = encodeWAV(interleaved); var audioBlob = new Blob([dataview], { type: type }); this.postMessage(audioBlob); } function interleave(inputL){//, inputR){//混合声道的时候去掉对右声道的处理 var length = inputL.length ;//+ inputR.length; var result = new Float32Array(length); var index = 0, inputIndex = 0; while (index < length){ result[index++] = inputL[inputIndex]; //result[index++] = inputR[inputIndex]; inputIndex++; } return result; }
然后修改一下注释,我不喜欢英文的....
function encodeWAV(samples) { var dataLength = samples.length * 2; var buffer = new ArrayBuffer(44 + dataLength); var view = new DataView(buffer); var sampleRateTmp = sampleRate; var sampleBits = 16; var channelCount = 1; 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; /* 采样数据 */ floatTo16BitPCM(view, 44, samples); return view; }
一旦把双声道变为单声道,数据直接缩小一半了
但是还不够
继续缩小体积
除了声道以外,还有一个可以缩减的地方就是采样位数 默认是16位的,我们改成8位 又可以减少一半了
function encodeWAV(samples) { var sampleBits = 8;//16;//这里改成8位 var dataLength = samples.length * (sampleBits / 8); var buffer = new ArrayBuffer(44 + dataLength); var view = new DataView(buffer); var sampleRateTmp = sampleRate; var channelCount = 1; 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; /* 采样数据 */ //floatTo16BitPCM(view, 44, samples); floatTo8BitPCM(view, 44, samples);//这里改为写入8位的数据 return view; }
8和16的取值范围不一样
对比一下To8和To16的方法
这里方法是我自己猜的,如果不对还望指出~~~
function floatTo16BitPCM(output, offset, input) { for (var i = 0; i < input.length; i++, offset += 2) { //因为是int16所以占2个字节,所以偏移量是+2 var s = Math.max(-1, Math.min(1, input[i])); output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true); } } function floatTo8BitPCM(output, offset, input) { for (var i = 0; i < input.length; i++, offset++) { //这里只能加1了 var s = Math.max(-1, Math.min(1, input[i])); var val = s < 0 ? s * 0x8000 : s * 0x7FFF; val = parseInt(255 / (65535 / (val + 32768))); //这里有一个转换的代码,这个是我个人猜测的,就是按比例转换 output.setInt8(offset, val, true); } }
怀着忐忑的心情,启动网页...居然听的到声音~居然成功了!!!
经过这样之后又减少了一半大小
最后就是这个采样率了
网页中录音组件的采样率是44100 不知道在哪里改,查询了一些资料,未果...
所以又自己猜测了,是不是我把已经缓存的时候按照比例抛弃一些就可以模拟减少采样率的操作呢?
比如现在已经缓存的数据大小是40960 是不是我直接间隔一位抛弃一次数据,将数据大小变成20480 就可以算是采样率变成22050了呢?
同理,要编程11025只要再抛弃一半的数据?
所以我又做了如下修改
function interleave(inputL, inputR) { var compression = 44100 / 11025; //计算压缩率 var length = inputL.length / compression; var result = new Float32Array(length); var index = 0, inputIndex = 0; while (index < length) { result[index] = inputL[inputIndex]; inputIndex += compression;//每次都跳过3个数据 index++; } return result; } function encodeWAV(samples) { var dataLength = samples.length; var buffer = new ArrayBuffer(44 + dataLength); var view = new DataView(buffer); var sampleRateTmp = 11025 ;//sampleRate;//写入新的采样率 var sampleBits = 8; var channelCount = 1; 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; /* 采样数据 */ floatTo16BitPCM(view, 44, samples); return view; }
再次怀着忐忑的心情,启动网页...居然听的到声音~居然又成功了
最后把之前的代码整理封装一下
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <div> <audio controls autoplay></audio> <input onclick="startRecording()" type="button" value="录音" /> <input onclick="stopRecording()" type="button" value="停止" /> <input onclick="playRecording()" type="button" value="播放" /> <input onclick="uploadAudio()" type="button" value="提交" /> </div> <script type="text/javascript" src="HZRecorder.js"></script> <script> var recorder; var audio = document.querySelector('audio'); function startRecording() { HZRecorder.get(function (rec) { recorder = rec; recorder.start(); }); } function stopRecording() { recorder.stop(); } function playRecording() { recorder.play(audio); } function uploadAudio() { recorder.upload("Handler1.ashx", function (state, e) { switch (state) { case 'uploading': //var percentComplete = Math.round(e.loaded * 100 / e.total) + '%'; break; case 'ok': //alert(e.target.responseText); alert("上传成功"); break; case 'error': alert("上传失败"); break; case 'cancel': alert("上传被取消"); break; } }); } </script> </body> </html>
以上是详解HTML5网页录音和压缩的示例代码的详细内容。更多信息请关注PHP中文网其他相关文章!

H5referstoHTML5,apivotaltechnologyinwebdevelopment.1)HTML5introducesnewelementsandAPIsforrich,dynamicwebapplications.2)Itsupportsmultimediawithoutplugins,enhancinguserexperienceacrossdevices.3)SemanticelementsimprovecontentstructureandSEO.4)H5'srespo

H5开发需要掌握的工具和框架包括Vue.js、React和Webpack。1.Vue.js适用于构建用户界面,支持组件化开发。2.React通过虚拟DOM优化页面渲染,适合复杂应用。3.Webpack用于模块打包,优化资源加载。

HTML5hassignificantlytransformedwebdevelopmentbyintroducingsemanticelements,enhancingmultimediasupport,andimprovingperformance.1)ItmadewebsitesmoreaccessibleandSEO-friendlywithsemanticelementslike,,and.2)HTML5introducednativeandtags,eliminatingthenee

H5通过语义化元素和ARIA属性提升网页的可访问性和SEO效果。1.使用、、等元素组织内容结构,提高SEO。2.ARIA属性如aria-label增强可访问性,辅助技术用户可顺利使用网页。

"h5"和"HTML5"在大多数情况下是相同的,但它们在某些特定场景下可能有不同的含义。1."HTML5"是W3C定义的标准,包含新标签和API。2."h5"通常是HTML5的简称,但在移动开发中可能指基于HTML5的框架。理解这些区别有助于在项目中准确使用这些术语。

H5,即HTML5,是HTML的第五个版本,它为开发者提供了更强大的工具集,使得创建复杂的网页应用变得更加简单。H5的核心功能包括:1)元素允许在网页上绘制图形和动画;2)语义化标签如、等,使网页结构清晰,利于SEO优化;3)新API如GeolocationAPI,支持基于位置的服务;4)跨浏览器兼容性需要通过兼容性测试和Polyfill库来确保。

如何创建 H5 链接?确定链接目标:获取 H5 页面或应用程序的 URL。创建 HTML 锚点:使用 <a> 标记创建锚点并指定链接目标URL。设置链接属性(可选):根据需要设置 target、title 和 onclick 属性。添加到网页:将 HTML 锚点代码添加到希望链接出现的网页中。

解决 H5 兼容问题的方法包括:使用响应式设计,允许网页根据屏幕尺寸调整布局。采用跨浏览器测试工具,在发布前测试兼容性。使用 Polyfill,为旧浏览器提供对新 API 的支持。遵循 Web 标准,使用有效的代码和最佳实践。使用 CSS 预处理器,简化 CSS 代码并提高可读性。优化图像,减小网页大小并加快加载速度。启用 HTTPS,确保网站的安全性。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

SublimeText3汉化版
中文版,非常好用

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能