一、浏览器HTML5录音功能

二、业务代码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title></title>
  6. </head>
  7. <body>
  8. <div>
  9. <audio controls autoplay></audio>
  10. <input onclick="startRecording()" type="button" value="录音" />
  11. <input onclick="stopRecording()" type="button" value="停止" />
  12. <input onclick="playRecording()" type="button" value="播放" />
  13. <input onclick="uploadAudio()" type="button" value="提交" />
  14. <input onclick="cancelAudio()" type="button" value="取消" />
  15. </div>
  16. <script type="text/javascript" src="record.js"></script>
  17. <script>
  18. var recorder;
  19. var audio = document.querySelector('audio');
  20. function startRecording() {
  21. HZRecorder.get(function (rec) {
  22. recorder = rec;
  23. recorder.start();
  24. });
  25. }
  26. function stopRecording() {
  27. recorder.stop();
  28. }
  29. function playRecording() {
  30. recorder.play(audio);
  31. }
  32. function cancelAudio(){
  33. recorder.stop();
  34. recorder.clear();
  35. }
  36. function uploadAudio() {
  37. recorder.upload("/upload", function (state, e) {
  38. switch (state) {
  39. case 'uploading':
  40. //var percentComplete = Math.round(e.loaded * 100 / e.total) + '%';
  41. break;
  42. case 'ok':
  43. //alert(e.target.responseText);
  44. alert("上传成功");
  45. break;
  46. case 'error':
  47. alert("上传失败");
  48. break;
  49. case 'cancel':
  50. alert("上传被取消");
  51. break;
  52. }
  53. });
  54. }
  55. </script>
  56. </body>
  57. </html>

三、录音文件


  1. //兼容
  2. window.URL = window.URL || window.webkitURL;
  3. //获取计算机的设备:摄像头或者录音设备
  4. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  5. var HZRecorder = function (stream, config) {
  6. config = config || {};
  7. config.sampleBits = config.sampleBits || 8; //采样数位 8, 16
  8. config.sampleRate = config.sampleRate || (44100 / 6); //采样率(1/6 44100)
  9. //创建一个音频环境对象
  10. var audioContext = window.AudioContext || window.webkitAudioContext;
  11. var context = new audioContext();
  12. var audioInput = context.createMediaStreamSource(stream);
  13. // 第二个和第三个参数指的是输入和输出都是单声道,2是双声道。
  14. var recorder = context.createScriptProcessor(4096, 1, 1);
  15. var audioData = {
  16. size: 0 //录音文件长度
  17. , buffer: [] //录音缓存
  18. , inputSampleRate: context.sampleRate //输入采样率
  19. , inputSampleBits: 16 //输入采样数位 8, 16
  20. , outputSampleRate: config.sampleRate //输出采样率
  21. , outputSampleBits: config.sampleBits //输出采样数位 8, 16
  22. , input: function (data) {
  23. this.buffer.push(new Float32Array(data));
  24. this.size += data.length;
  25. }
  26. , compress: function () { //合并压缩
  27. //合并
  28. var data = new Float32Array(this.size);
  29. var offset = 0;
  30. for (var i = 0; i < this.buffer.length; i++) {
  31. data.set(this.buffer[i], offset);
  32. offset += this.buffer[i].length;
  33. }
  34. //压缩
  35. var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
  36. var length = data.length / compression;
  37. var result = new Float32Array(length);
  38. var index = 0, j = 0;
  39. while (index < length) {
  40. result[index] = data[j];
  41. j += compression;
  42. index++;
  43. }
  44. return result;
  45. }
  46. , encodeWAV: function () {
  47. var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
  48. var sampleBits = Math.min(this.inputSampleBits, this.outputSampleBits);
  49. var bytes = this.compress();
  50. var dataLength = bytes.length * (sampleBits / 8);
  51. var buffer = new ArrayBuffer(44 + dataLength);
  52. var data = new DataView(buffer);
  53. var channelCount = 1;//单声道
  54. var offset = 0;
  55. var writeString = function (str) {
  56. for (var i = 0; i < str.length; i++) {
  57. data.setUint8(offset + i, str.charCodeAt(i));
  58. }
  59. }
  60. // 资源交换文件标识符
  61. writeString('RIFF'); offset += 4;
  62. // 下个地址开始到文件尾总字节数,即文件大小-8
  63. data.setUint32(offset, 36 + dataLength, true); offset += 4;
  64. // WAV文件标志
  65. writeString('WAVE'); offset += 4;
  66. // 波形格式标志
  67. writeString('fmt '); offset += 4;
  68. // 过滤字节,一般为 0x10 = 16
  69. data.setUint32(offset, 16, true); offset += 4;
  70. // 格式类别 (PCM形式采样数据)
  71. data.setUint16(offset, 1, true); offset += 2;
  72. // 通道数
  73. data.setUint16(offset, channelCount, true); offset += 2;
  74. // 采样率,每秒样本数,表示每个通道的播放速度
  75. data.setUint32(offset, sampleRate, true); offset += 4;
  76. // 波形数据传输率 (每秒平均字节数) 单声道×每秒数据位数×每样本数据位/8
  77. data.setUint32(offset, channelCount * sampleRate * (sampleBits / 8), true); offset += 4;
  78. // 快数据调整数 采样一次占用字节数 单声道×每样本的数据位数/8
  79. data.setUint16(offset, channelCount * (sampleBits / 8), true); offset += 2;
  80. // 每样本数据位数
  81. data.setUint16(offset, sampleBits, true); offset += 2;
  82. // 数据标识符
  83. writeString('data'); offset += 4;
  84. // 采样数据总数,即数据总大小-44
  85. data.setUint32(offset, dataLength, true); offset += 4;
  86. // 写入采样数据
  87. if (sampleBits === 8) {
  88. for (var i = 0; i < bytes.length; i++, offset++) {
  89. var s = Math.max(-1, Math.min(1, bytes[i]));
  90. var val = s < 0 ? s * 0x8000 : s * 0x7FFF;
  91. val = parseInt(255 / (65535 / (val + 32768)));
  92. data.setInt8(offset, val, true);
  93. }
  94. } else {
  95. for (var i = 0; i < bytes.length; i++, offset += 2) {
  96. var s = Math.max(-1, Math.min(1, bytes[i]));
  97. data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
  98. }
  99. }
  100. return new Blob([data], { type: 'audio/mp3' });
  101. }
  102. };
  103. //开始录音
  104. this.start = function () {
  105. audioInput.connect(recorder);
  106. recorder.connect(context.destination);
  107. }
  108. //停止
  109. this.stop = function () {
  110. recorder.disconnect();
  111. }
  112. //获取音频文件
  113. this.getBlob = function () {
  114. this.stop();
  115. return audioData.encodeWAV();
  116. }
  117. //回放
  118. this.play = function (audio) {
  119. audio.src = window.URL.createObjectURL(this.getBlob());
  120. }
  121. //清除
  122. this.clear = function(){
  123. audioData.buffer=[];
  124. audioData.size=0;
  125. }
  126. //上传
  127. this.upload = function (url, callback) {
  128. var fd = new FormData();
  129. fd.append("audioData", this.getBlob());
  130. var xhr = new XMLHttpRequest();
  131. if (callback) {
  132. xhr.upload.addEventListener("progress", function (e) {
  133. callback('uploading', e);
  134. }, false);
  135. xhr.addEventListener("load", function (e) {
  136. callback('ok', e);
  137. }, false);
  138. xhr.addEventListener("error", function (e) {
  139. callback('error', e);
  140. }, false);
  141. xhr.addEventListener("abort", function (e) {
  142. callback('cancel', e);
  143. }, false);
  144. }
  145. xhr.open("POST", url);
  146. xhr.send(fd);
  147. }
  148. //音频采集
  149. recorder.onaudioprocess = function (e) {
  150. audioData.input(e.inputBuffer.getChannelData(0));
  151. //record(e.inputBuffer.getChannelData(0));
  152. }
  153. };
  154. //抛出异常
  155. HZRecorder.throwError = function (message) {
  156. alert(message);
  157. throw new function () { this.toString = function () { return message; } }
  158. }
  159. //是否支持录音
  160. HZRecorder.canRecording = (navigator.getUserMedia != null);
  161. //获取录音机
  162. HZRecorder.get = function (callback, config) {
  163. if (callback) {
  164. if (navigator.getUserMedia) {
  165. navigator.getUserMedia(
  166. { audio: true } //只启用音频
  167. , function (stream) {
  168. var rec = new HZRecorder(stream, config);
  169. callback(rec);
  170. }
  171. , function (error) {
  172. switch (error.code || error.name) {
  173. case 'PERMISSION_DENIED':
  174. case 'PermissionDeniedError':
  175. HZRecorder.throwError('用户拒绝提供信息。');
  176. break;
  177. case 'NOT_SUPPORTED_ERROR':
  178. case 'NotSupportedError':
  179. HZRecorder.throwError('浏览器不支持硬件设备。');
  180. break;
  181. case 'MANDATORY_UNSATISFIED_ERROR':
  182. case 'MandatoryUnsatisfiedError':
  183. HZRecorder.throwError('无法发现指定的硬件设备。');
  184. break;
  185. default:
  186. HZRecorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name));
  187. break;
  188. }
  189. });
  190. } else {
  191. HZRecorder.throwErr('当前浏览器不支持录音功能。'); return;
  192. }
  193. }
  194. };

参考地址

https://github.com/silenceboy...

浏览器HTML5录音功能的更多相关文章

  1. 浏览器HTML5支持程度测试

    /********************************************************************* * 浏览器HTML5支持程度测试 * 说明: * 想知道对 ...

  2. 2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼

    2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼   转眼又已过去了一年,在这一年里,Firefox 和 Chrome 在拼升级,版本号不断飙升:IE10 随着 Windows 8 在 ...

  3. 2013年五大主流浏览器 HTML5 和 CSS3 兼容性大比拼【转】

    摘要: 这篇文章给大家带来<五大主流浏览器 HTML5 和 CSS3 兼容性大比拼>,让我们一起来看看2013年的浏览器现状.浏览器厂商之间的竞争促使各大浏览器对 HTML5 和 CSS3 ...

  4. 主流浏览器HTML5视频格式差异

    因最近在研究video.js,现在遇到的问题是在js中设置了swf,但是在ie8下只是显示黑屏并没有播放视频,在网上进行搜索时查到了有关各个浏览器支持哪些视频格式的文章,现在此记录下,方便以后查阅. ...

  5. 实现跨浏览器html5表单验证

    div:nth-of-type(odd){ float: left; clear: left; } .origin-effect > div:nth-of-type(even){ float: ...

  6. 内地视频网站对各种浏览器HTML5的支持情况

    实在闲得蛋疼 2017/10/1

  7. Chrome浏览器 HTML5看视频卡顿

    定位问题 起初以为是flash的问题,但是在B站看视频,由html播放改为flash播放后,卡顿现象消失 将相同的B站视频,用edge播放,也无卡顿现象 可以确定,问题出在chrome身上 解决方法 ...

  8. 兼容各个浏览器的H.264播放: H.264+HTML5+FLOWPLAYER+WOWZA+RMTP

    一.方案确定 计划做视频播放,要求可以播放H264编码的mp4文件,各个浏览器,各种终端都能播放. 首先查找可行性方案, http://www.cnblogs.com/sink_cup/archive ...

  9. html5手机浏览器启动微信客户端支付实例

    html5手机浏览器启动微信客户端支付实例,外部浏览器html5微信支付技术,如何在手机浏览器微信支付,在微信客户端外的移动端网页使用微信支付 首先在微信支付官网https://pay.weixin. ...

随机推荐

  1. 利用pcl数据结构,实现RegionGrowing的复现

    这篇博客是pcl中区域增长的算法进行简介以实现重写,并添加了一些判断条件. 起初原因是在使用pcl封装的regionGrowing时,效果不太好. 于是想自己重新写一下,通过改变其中种子点的生成策略和 ...

  2. ubuntu18下lamp虚拟路劲配置

    一.配置二级域名 修改hosts文件,模拟dns解析. 位置:/etc/hosts 添加 127.0.0.1  myweb.service.com 二.创建项目目录 apache默认目录是/var m ...

  3. input搜索框实时检索功能实现(超简单,核心原理请看思路即可)

    问题:实现input搜索框实时检索的功能,类似哔哩哔哩首页搜索功能(壮哉我大b站!).公司要求,emmmm没办法,果然懒人是要被赶着走才会进步的说,诶嘿O(∩_∩)O. 解决方法: 1.参考资料:ht ...

  4. ES使用text类型字段排序报错

    elasticsearch text字段排序报错解决使用elasticsearch 进行排序的时候,我们一般都会排序数字.日期.但是在排序text类型的时候就会出现错误. GET xytest/sut ...

  5. java 正则表达式 复习

    正则表达式在日常开发中会经常的接触到,学会了正则可以更有效的对字符进行验证.拆分.替换.判断字符串是否合法等操作... 常用语法: 字符的取值范围 1.[abc] : 表示可能是a,可能是b,也可能是 ...

  6. httpClient4.5.2工具类总结

    使用背景: 因项目使用非结构化存储,http相关jar包统一升级到httpClient4.5.2,查阅相关文档总结如下,以咨分享,望不吝指教. 依赖jar包 httpclient-4.5.2.jar. ...

  7. vue点击出现蒙版

      需求: 1.点击一个事件时弹出一个蒙版: 2.蒙版上有取消,删除事件:(点击取消时候蒙版消失,点击删除时,删除蒙版并消失): 3.点击空白地方,蒙版也消失:   <template> ...

  8. php打开csv

    <?php $fh=fopen("a.csv","r");//这里我们只是读取数据,所以采用只读打开文件流 $arr=fgetcsv($fh);//这个函 ...

  9. python 四舍五入进位不准

    python中四舍五入进位不准,自己写了个方法结果: def new_round(_float, _len): ''' 四舍五入保留小数位,如果想实现 0.2 显示为 0.20,可使用 '%.2f' ...

  10. Celery多队列配置

    Celery多队列配置 Celery官方文档 项目结构 /proj -__init__ -app.py #实例化celery对象 -celeryconfig.py #celery的配置文件 -task ...