资讯专栏INFORMATION COLUMN

浏览器HTML5录音功能

TerryCai / 1565人阅读

摘要:一浏览器录音功能二业务代码录音停止播放提交取消上传成功上传失败上传被取消三录音文件兼容获取计算机的设备摄像头或者录音设备采样数位采样率创建一个音频环境对象第二个和第三个参数指的是输入和输出都是单声道是双声道。

一、浏览器HTML5录音功能 二、业务代码

三、录音文件

</>code

  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...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93125.html

相关文章

  • 览器HTML5录音功能

    摘要:一浏览器录音功能二业务代码录音停止播放提交取消上传成功上传失败上传被取消三录音文件兼容获取计算机的设备摄像头或者录音设备采样数位采样率创建一个音频环境对象第二个和第三个参数指的是输入和输出都是单声道是双声道。 一、浏览器HTML5录音功能 二、业务代码 ...

    nanfeiyan 评论0 收藏0
  • 使用Html5多媒体实现微信语音功能

    摘要:随着微信等社交的兴起,语音聊天成为很多必备功能,大到将语音聊天作为主要功能的社交,小到电商的语音客服店小二功能,语音聊天成为了必不可少的方式。 随着微信等社交App的兴起,语音聊天成为很多App必备功能,大到将语音聊天作为主要功能的社交App,小到电商App的语音客服、店小二功能,语音聊天成为了必不可少的方式。 但是很多人感觉网页端语音离我们很遥远,这些更多是本地应用的工作,其实不然,...

    Render 评论0 收藏0
  • 使用Html5多媒体实现微信语音功能

    摘要:随着微信等社交的兴起,语音聊天成为很多必备功能,大到将语音聊天作为主要功能的社交,小到电商的语音客服店小二功能,语音聊天成为了必不可少的方式。 随着微信等社交App的兴起,语音聊天成为很多App必备功能,大到将语音聊天作为主要功能的社交App,小到电商App的语音客服、店小二功能,语音聊天成为了必不可少的方式。 但是很多人感觉网页端语音离我们很遥远,这些更多是本地应用的工作,其实不然,...

    venmos 评论0 收藏0

发表评论

0条评论

TerryCai

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<