JS实现麦克风录音并通过WebSocket实时传递到后台

15 篇文章 0 订阅

https://blog.csdn.net/qiao_1017/article/details/102609243

实现效果:PC端通过麦克风录音,通过 WebSocket实时传递到后台

  • 原始每包数据过于大,后台不能接收,需要分包处理,每包最大1024
  • 原始采样率为48000;通过合并压缩为自己所需采样率,demo中最终采样率为8000
 
  1. <!DOCTYPE html>

  2. <html>

  3. <head>

  4. <meta charset="UTF-8">

  5. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

  6. <meta name="apple-mobile-web-capable" content="yes">

  7. <title>录音并传递给后台</title>

  8. </head>

  9. <body>

  10. <button id="intercomBegin">开始对讲</button>

  11. <button id="intercomEnd">关闭对讲</button>

  12. </body>

  13. <script type="text/javascript">

  14. var begin = document.getElementById('intercomBegin');

  15. var end = document.getElementById('intercomEnd');

  16.  
  17. var ws = null; //实现WebSocket

  18. var record = null; //多媒体对象,用来处理音频

  19.  
  20. function init(rec) {

  21. record = rec;

  22. }

  23.  
  24. //录音对象

  25. var Recorder = function(stream) {

  26. var sampleBits = 16; //输出采样数位 8, 16

  27. var sampleRate = 8000; //输出采样率

  28. var context = new AudioContext();

  29. var audioInput = context.createMediaStreamSource(stream);

  30. var recorder = context.createScriptProcessor(4096, 1, 1);

  31. var audioData = {

  32. size: 0, //录音文件长度

  33. buffer: [], //录音缓存

  34. inputSampleRate: 48000, //输入采样率

  35. inputSampleBits: 16, //输入采样数位 8, 16

  36. outputSampleRate: sampleRate, //输出采样数位

  37. oututSampleBits: sampleBits, //输出采样率

  38. clear: function() {

  39. this.buffer = [];

  40. this.size = 0;

  41. },

  42. input: function(data) {

  43. this.buffer.push(new Float32Array(data));

  44. this.size += data.length;

  45. },

  46. compress: function() { //合并压缩

  47. //合并

  48. var data = new Float32Array(this.size);

  49. var offset = 0;

  50. for (var i = 0; i < this.buffer.length; i++) {

  51. data.set(this.buffer[i], offset);

  52. offset += this.buffer[i].length;

  53. }

  54. //压缩

  55. var compression = parseInt(this.inputSampleRate / this.outputSampleRate);

  56. var length = data.length / compression;

  57. var result = new Float32Array(length);

  58. var index = 0,

  59. j = 0;

  60. while (index < length) {

  61. result[index] = data[j];

  62. j += compression;

  63. index++;

  64. }

  65. return result;

  66. },

  67. encodePCM: function() { //这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。

  68. var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);

  69. var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);

  70. var bytes = this.compress();

  71. var dataLength = bytes.length * (sampleBits / 8);

  72. var buffer = new ArrayBuffer(dataLength);

  73. var data = new DataView(buffer);

  74. var offset = 0;

  75. for (var i = 0; i < bytes.length; i++, offset += 2) {

  76. var s = Math.max(-1, Math.min(1, bytes[i]));

  77. data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);

  78. }

  79. return new Blob([data]);

  80. }

  81. };

  82.  
  83. var sendData = function() { //对以获取的数据进行处理(分包)

  84. var reader = new FileReader();

  85. reader.onload = e => {

  86. var outbuffer = e.target.result;

  87. var arr = new Int8Array(outbuffer);

  88. if (arr.length > 0) {

  89. var tmparr = new Int8Array(1024);

  90. var j = 0;

  91. for (var i = 0; i < arr.byteLength; i++) {

  92. tmparr[j++] = arr[i];

  93. if (((i + 1) % 1024) == 0) {

  94. ws.send(tmparr);

  95. if (arr.byteLength - i - 1 >= 1024) {

  96. tmparr = new Int8Array(1024);

  97. } else {

  98. tmparr = new Int8Array(arr.byteLength - i - 1);

  99. }

  100. j = 0;

  101. }

  102. if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {

  103. ws.send(tmparr);

  104. }

  105. }

  106. }

  107. };

  108. reader.readAsArrayBuffer(audioData.encodePCM());

  109. audioData.clear();//每次发送完成则清理掉旧数据

  110. };

  111.  
  112. this.start = function() {

  113. audioInput.connect(recorder);

  114. recorder.connect(context.destination);

  115. }

  116.  
  117. this.stop = function() {

  118. recorder.disconnect();

  119. }

  120.  
  121. this.getBlob = function() {

  122. return audioData.encodePCM();

  123. }

  124.  
  125. this.clear = function() {

  126. audioData.clear();

  127. }

  128.  
  129. recorder.onaudioprocess = function(e) {

  130. var inputBuffer = e.inputBuffer.getChannelData(0);

  131. audioData.input(inputBuffer);

  132. sendData();

  133. }

  134. }

  135.  
  136.  
  137. /*

  138. * WebSocket

  139. */

  140. function useWebSocket() {

  141. ws = new WebSocket("ws://192.168.2.9:8080/websocket");

  142. ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据

  143. ws.onopen = function() {

  144. console.log('握手成功');

  145. if (ws.readyState == 1) { //ws进入连接状态,则每隔500毫秒发送一包数据

  146. record.start();

  147. }

  148. };

  149.  
  150. ws.onmessage = function(msg) {

  151. console.info(msg)

  152. }

  153.  
  154. ws.onerror = function(err) {

  155. console.info(err)

  156. }

  157. }

  158.  
  159. /*

  160. * 开始对讲

  161. */

  162. begin.onclick = function() {

  163. navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;

  164. if (!navigator.getUserMedia) {

  165. alert('浏览器不支持音频输入');

  166. } else {

  167. navigator.getUserMedia({

  168. audio: true

  169. },

  170. function(mediaStream) {

  171. init(new Recorder(mediaStream));

  172. console.log('开始对讲');

  173. useWebSocket();

  174. },

  175. function(error) {

  176. console.log(error);

  177. switch (error.message || error.name) {

  178. case 'PERMISSION_DENIED':

  179. case 'PermissionDeniedError':

  180. console.info('用户拒绝提供信息。');

  181. break;

  182. case 'NOT_SUPPORTED_ERROR':

  183. case 'NotSupportedError':

  184. console.info('浏览器不支持硬件设备。');

  185. break;

  186. case 'MANDATORY_UNSATISFIED_ERROR':

  187. case 'MandatoryUnsatisfiedError':

  188. console.info('无法发现指定的硬件设备。');

  189. break;

  190. default:

  191. console.info('无法打开麦克风。异常信息:' + (error.code || error.name));

  192. break;

  193. }

  194. }

  195. )

  196. }

  197. }

  198.  
  199. /*

  200. * 关闭对讲

  201. */

  202. end.onclick = function() {

  203. if (ws) {

  204. ws.close();

  205. record.stop();

  206. console.log('关闭对讲以及WebSocket');

  207. }

  208. }

  209. </script>

  210. </html>

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值