废话不说,直接上代码吧

  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 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. </div>
  15. <script type="text/javascript" src="HZRecorder.js"></script>
  16. <script>
  17. var recorder;
  18.  
  19. var audio = document.querySelector('audio');
  20.  
  21. function startRecording() {
  22. HZRecorder.get(function (rec) {
  23. recorder = rec;
  24. recorder.start();
  25. });
  26. }
  27.  
  28. function stopRecording() {
  29. recorder.stop();
  30. }
  31.  
  32. function playRecording() {
  33. recorder.play(audio);
  34. }
  35.  
  36. function uploadAudio() {
  37. recorder.upload("Handler1.ashx", 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.  
  56. </script>
  57.  
  58. </body>
  59. </html>

HZRecorder.js

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

H5进行录音,播放,上传的更多相关文章

  1. 微信录音文件上传到服务器以及amr转化成MP3格式

    微信公众号音频接口开发 根据业务需求,我们可能需要将微信录音保存到服务器,而通过微信上传语音接口上传到微信服务器的语音文件的有效期只有3天,所以需要将文件下载到我们自己的服务器. 上传语音接口 wx. ...

  2. 微信录音文件上传到服务器以及amr转化成MP3格式,linux上转换简单方法

    微信公众号音频接口开发 根据业务需求,我们可能需要将微信录音保存到服务器,而通过微信上传语音接口上传到微信服务器的语音文件的有效期只有3天,所以需要将文件下载到我们自己的服务器. 上传语音接口 wx. ...

  3. Java+FlashWavRecorder实现网页录音并上传

    [注意] 最新版本号请看这里:http://uikoo9.com/blog/detail/java-flashwavrecorder [前言] 肯定有需求要网页录音,并且要上传.这奇葩需求. 然后找到 ...

  4. 项目分享五:H5图片压缩与上传

    一.简介 图片的压缩与上传,是APP里一个很常用的功能.我们来年看 ChiTuStore 是怎样做的.相关文件 App/Module/User/UserInfo.html,App/Module/Use ...

  5. H5实现拍照并上传

    <!DOCTYPE HTML><html><head>    <meta charset="UTF-8">    <meta ...

  6. PC端 H5实现拍照并上传

    <!DOCTYPE HTML><html><head> <meta charset="UTF-8"> <meta name=& ...

  7. h5 + nginx + php 视频上传之突破文件大小受限的解决办法

    一.环境: CentOS 6.8 nginx 1.8.0 php 7.0.10 二.背景 基于 nginx + php 的 h5 项目,上传视频的时候,如果视频太大,会上传失败. 三.正文 一份视频传 ...

  8. 移动端h5拍照压缩即时上传后台并预览

    项目经理让迭代一个功能,实时预览并上传到后台的功能,听到这立马想起了几个第三方插件去实现,mui  和api cloude万万没想到的是这个app前面使用ios 和安卓原生写的,然后mui和api c ...

  9. h5属性直接控制上传文件类型

    和公司前端交互的时候发现我在选择上传文件的时候只能选择图片,其他类型,text,doc等等等等全部无法选择 仔细查看了下代码,发现归功于H5新增(??没查到资料,不确定是不是H5的)的input属性 ...

  10. 移动端H5上传图片并压缩上传

    手头上的这个项目主要是在微信内运行的一个网站,需要用户上传手机内的照片,而现在手机照片尺寸越来越大,直接上传的话的确上传进度慢影响用户体验而且也会给服务器增加压力,所以利用H5的新特性压缩后上传不失为 ...

随机推荐

  1. BZOJ 3224 - 普通平衡树 - [Treap][Splay]

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3224 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中 ...

  2. Hive日志(Hive Logging)--hive GettingStarted翻译

    Hive uses log4j for logging. By default logs are not emitted to the console by the CLI. The default ...

  3. 使用hive分析nginx访问日志方法

    以下案例是使用hive分析nginx的访问日志案例,其中字段分隔通过正则表达式匹配,具体步骤如下: 日志格式: 192.168.5.139 - - [08/Jun/2017:17:09:12 +080 ...

  4. mysql表引擎myisam改为innodb

    1.进入数据库 2.SELECT  CONCAT('ALTER TABLE `', table_name, '` ENGINE=InnoDB;') AS sql_statements FROM    ...

  5. 原来的ALL IN ONE架构,快速的演进成为SOA架构

    原来的ALL IN ONE架构,快速的演进成为SOA架构 京东服务市场高并发下SOA服务化演进架构 原创: 张俊卿 京东技术 今天

  6. [centos][ntp][administrator] chrony ntp

    以下内容,适用于 CentOS 7 (systemd 体系) 一. 首先,确认你是否启用了 ntp 服务: [root@nlb2-liantiao ~]# timedatectl Local time ...

  7. AWS学习笔记

    VPC :虚拟局域网 EC2 :虚拟机 RDS :关系型数据库的管理平台 ElasticCache: 缓存系统的管理平台 ELB :可伸缩的负载均衡(私有子网中的web服务通过elb暴露到公网中) A ...

  8. redis有序集合性能 列表、集合、有序集合

    https://www.cnblogs.com/pirlo21/p/7120935.html 1.1 列表 列表(list)类型是用来存储多个字符串,元素从左到右组成一个有序的集合.列表中的每个字符串 ...

  9. 2018/05/02 PHP 之错误与异常处理

    在学习中,越学习越觉得自己基础薄弱. 在平常工作中,对于某些错误处理感觉不知道怎么下手,于是决定重新再整理一下. 强烈推荐这篇文章,真的感觉学习到了很多. 部分引用::再谈PHP错误与异常处理 -- ...

  10. 洛谷P4587 神秘数 [FJOI2016] 主席树

    正解:主席树 解题报告: 先放下传送门QAQ 首先可以先思考如果只有一组询问,怎么解决 可以这么想,最开始一个数也麻油的时候能表示的最大的数是0嘛 然后先排个序,按顺序每次新加入一个数x,设加入这个数 ...