ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

利用Recorder.js在客服中启用语音通话!

2021-08-11 12:00:53  阅读:232  来源: 互联网

标签:function __ log js 通话 window var Recorder audio


  1 <!DOCTYPE html>
  2 
  3 <html>
  4 <head>
  5     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6     <title>Live input record and playback</title>
  7   <style type='text/css'>
  8     ul { list-style: none; }
  9     #recordingslist audio { display: block; margin-bottom: 10px; }
 10   </style>
 11 </head>
 12 <body>
 13 
 14   <h1>Recorder.js simple WAV export example</h1>
 15 
 16   <p>Make sure you are using a recent version of Google Chrome.</p>
 17   <p>Also before you enable microphone input either plug in headphones or turn the volume down if you want to avoid ear splitting feedback!</p>
 18 
 19   <button onclick="startRecording(this);">开始录音</button>
 20   <button onclick="stopRecording(this);" disabled>停止</button>
 21   
 22   <h2>Recordings</h2>
 23   <ul id="recordingslist"></ul>
 24   
 25   <h2>Log</h2>
 26   <pre id="log"></pre>
 27 
 28   <script>
 29   function __log(e, data) {
 30     log.innerHTML += "\n" + e + " " + (data || '');
 31   }
 32 
 33   var audio_context;
 34   var recorder;
 35 
 36   function startUserMedia(stream) {
 37     var input = audio_context.createMediaStreamSource(stream);
 38     __log('Media stream created.');
 39 
 40     // Uncomment if you want the audio to feedback directly
 41     //input.connect(audio_context.destination);
 42     //__log('Input connected to audio context destination.');
 43     
 44     recorder = new Recorder(input);
 45     __log('Recorder initialised.');
 46   }
 47 
 48   function startRecording(button) {
 49     recorder && recorder.record();
 50     button.disabled = true;
 51     button.nextElementSibling.disabled = false;
 52     __log('Recording...');
 53   }
 54 
 55   function stopRecording(button) {
 56     recorder && recorder.stop();
 57     button.disabled = true;
 58     button.previousElementSibling.disabled = false;
 59     __log('Stopped recording.');
 60     
 61     // create WAV download link using audio data blob
 62     createDownloadLink();
 63     
 64     recorder.clear();
 65   }
 66 
 67   function createDownloadLink() {
 68     recorder && recorder.exportWAV(function(blob) {
 69       var url = URL.createObjectURL(blob);
 70       var li = document.createElement('li');
 71       var au = document.createElement('audio');
 72       var hf = document.createElement('a');
 73       
 74       au.controls = true;
 75       au.src = url;
 76       hf.href = url;
 77       hf.download = new Date().toISOString() + '.wav';
 78       hf.innerHTML = hf.download;
 79       li.appendChild(au);
 80       li.appendChild(hf);
 81       recordingslist.appendChild(li);
 82     });
 83   }
 84 
 85   window.onload = function init() {
 86     try {
 87       // webkit shim
 88       window.AudioContext = window.AudioContext || window.webkitAudioContext;
 89       navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
 90       window.URL = window.URL || window.webkitURL;
 91       
 92       audio_context = new AudioContext;
 93       __log('Audio context set up.');
 94       __log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
 95     } catch (e) {
 96       alert('No web audio support in this browser!');
 97     }
 98     
 99     navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
100       __log('No live audio input: ' + e);
101     });
102   };
103   </script>
104 
105   <script src="./dist/recorder.js"></script>
106 </body>
107 </html>

这是HTML代码部份,

  1 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Recorder = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2 "use strict";
  3 
  4 module.exports = require("./recorder").Recorder;
  5 
  6 },{"./recorder":2}],2:[function(require,module,exports){
  7 'use strict';
  8 
  9 var _createClass = (function () {
 10     function defineProperties(target, props) {
 11         for (var i = 0; i < props.length; i++) {
 12             var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);
 13         }
 14     }return function (Constructor, protoProps, staticProps) {
 15         if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
 16     };
 17 })();
 18 
 19 Object.defineProperty(exports, "__esModule", {
 20     value: true
 21 });
 22 exports.Recorder = undefined;
 23 
 24 var _inlineWorker = require('inline-worker');
 25 
 26 var _inlineWorker2 = _interopRequireDefault(_inlineWorker);
 27 
 28 function _interopRequireDefault(obj) {
 29     return obj && obj.__esModule ? obj : { default: obj };
 30 }
 31 
 32 function _classCallCheck(instance, Constructor) {
 33     if (!(instance instanceof Constructor)) {
 34         throw new TypeError("Cannot call a class as a function");
 35     }
 36 }
 37 
 38 var Recorder = exports.Recorder = (function () {
 39     function Recorder(source, cfg) {
 40         var _this = this;
 41 
 42         _classCallCheck(this, Recorder);
 43 
 44         this.config = {
 45             bufferLen: 4096,
 46             numChannels: 2,
 47             mimeType: 'audio/wav'
 48         };
 49         this.recording = false;
 50         this.callbacks = {
 51             getBuffer: [],
 52             exportWAV: []
 53         };
 54 
 55         Object.assign(this.config, cfg);
 56         this.context = source.context;
 57         this.node = (this.context.createScriptProcessor || this.context.createJavaScriptNode).call(this.context, this.config.bufferLen, this.config.numChannels, this.config.numChannels);
 58 
 59         this.node.onaudioprocess = function (e) {
 60             if (!_this.recording) return;
 61 
 62             var buffer = [];
 63             for (var channel = 0; channel < _this.config.numChannels; channel++) {
 64                 buffer.push(e.inputBuffer.getChannelData(channel));
 65             }
 66             _this.worker.postMessage({
 67                 command: 'record',
 68                 buffer: buffer
 69             });
 70         };
 71 
 72         source.connect(this.node);
 73         this.node.connect(this.context.destination); //this should not be necessary
 74 
 75         var self = {};
 76         this.worker = new _inlineWorker2.default(function () {
 77             var recLength = 0,
 78                 recBuffers = [],
 79                 sampleRate = undefined,
 80                 numChannels = undefined;
 81 
 82             self.onmessage = function (e) {
 83                 switch (e.data.command) {
 84                     case 'init':
 85                         init(e.data.config);
 86                         break;
 87                     case 'record':
 88                         record(e.data.buffer);
 89                         break;
 90                     case 'exportWAV':
 91                         exportWAV(e.data.type);
 92                         break;
 93                     case 'getBuffer':
 94                         getBuffer();
 95                         break;
 96                     case 'clear':
 97                         clear();
 98                         break;
 99                 }
100             };
101 
102             function init(config) {
103                 sampleRate = config.sampleRate;
104                 numChannels = config.numChannels;
105                 initBuffers();
106             }
107 
108             function record(inputBuffer) {
109                 for (var channel = 0; channel < numChannels; channel++) {
110                     recBuffers[channel].push(inputBuffer[channel]);
111                 }
112                 recLength += inputBuffer[0].length;
113             }
114 
115             function exportWAV(type) {
116                 var buffers = [];
117                 for (var channel = 0; channel < numChannels; channel++) {
118                     buffers.push(mergeBuffers(recBuffers[channel], recLength));
119                 }
120                 var interleaved = undefined;
121                 if (numChannels === 2) {
122                     interleaved = interleave(buffers[0], buffers[1]);
123                 } else {
124                     interleaved = buffers[0];
125                 }
126                 var dataview = encodeWAV(interleaved);
127                 var audioBlob = new Blob([dataview], { type: type });
128 
129                 self.postMessage({ command: 'exportWAV', data: audioBlob });
130             }
131 
132             function getBuffer() {
133                 var buffers = [];
134                 for (var channel = 0; channel < numChannels; channel++) {
135                     buffers.push(mergeBuffers(recBuffers[channel], recLength));
136                 }
137                 self.postMessage({ command: 'getBuffer', data: buffers });
138             }
139 
140             function clear() {
141                 recLength = 0;
142                 recBuffers = [];
143                 initBuffers();
144             }
145 
146             function initBuffers() {
147                 for (var channel = 0; channel < numChannels; channel++) {
148                     recBuffers[channel] = [];
149                 }
150             }
151 
152             function mergeBuffers(recBuffers, recLength) {
153                 var result = new Float32Array(recLength);
154                 var offset = 0;
155                 for (var i = 0; i < recBuffers.length; i++) {
156                     result.set(recBuffers[i], offset);
157                     offset += recBuffers[i].length;
158                 }
159                 return result;
160             }
161 
162             function interleave(inputL, inputR) {
163                 var length = inputL.length + inputR.length;
164                 var result = new Float32Array(length);
165 
166                 var index = 0,
167                     inputIndex = 0;
168 
169                 while (index < length) {
170                     result[index++] = inputL[inputIndex];
171                     result[index++] = inputR[inputIndex];
172                     inputIndex++;
173                 }
174                 return result;
175             }
176 
177             function floatTo16BitPCM(output, offset, input) {
178                 for (var i = 0; i < input.length; i++, offset += 2) {
179                     var s = Math.max(-1, Math.min(1, input[i]));
180                     output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
181                 }
182             }
183 
184             function writeString(view, offset, string) {
185                 for (var i = 0; i < string.length; i++) {
186                     view.setUint8(offset + i, string.charCodeAt(i));
187                 }
188             }
189 
190             function encodeWAV(samples) {
191                 var buffer = new ArrayBuffer(44 + samples.length * 2);
192                 var view = new DataView(buffer);
193 
194                 /* RIFF identifier */
195                 writeString(view, 0, 'RIFF');
196                 /* RIFF chunk length */
197                 view.setUint32(4, 36 + samples.length * 2, true);
198                 /* RIFF type */
199                 writeString(view, 8, 'WAVE');
200                 /* format chunk identifier */
201                 writeString(view, 12, 'fmt ');
202                 /* format chunk length */
203                 view.setUint32(16, 16, true);
204                 /* sample format (raw) */
205                 view.setUint16(20, 1, true);
206                 /* channel count */
207                 view.setUint16(22, numChannels, true);
208                 /* sample rate */
209                 view.setUint32(24, sampleRate, true);
210                 /* byte rate (sample rate * block align) */
211                 view.setUint32(28, sampleRate * 4, true);
212                 /* block align (channel count * bytes per sample) */
213                 view.setUint16(32, numChannels * 2, true);
214                 /* bits per sample */
215                 view.setUint16(34, 16, true);
216                 /* data chunk identifier */
217                 writeString(view, 36, 'data');
218                 /* data chunk length */
219                 view.setUint32(40, samples.length * 2, true);
220 
221                 floatTo16BitPCM(view, 44, samples);
222 
223                 return view;
224             }
225         }, self);
226 
227         this.worker.postMessage({
228             command: 'init',
229             config: {
230                 sampleRate: this.context.sampleRate,
231                 numChannels: this.config.numChannels
232             }
233         });
234 
235         this.worker.onmessage = function (e) {
236             var cb = _this.callbacks[e.data.command].pop();
237             if (typeof cb == 'function') {
238                 cb(e.data.data);
239             }
240         };
241     }
242 
243     _createClass(Recorder, [{
244         key: 'record',
245         value: function record() {
246             this.recording = true;
247         }
248     }, {
249         key: 'stop',
250         value: function stop() {
251             this.recording = false;
252         }
253     }, {
254         key: 'clear',
255         value: function clear() {
256             this.worker.postMessage({ command: 'clear' });
257         }
258     }, {
259         key: 'getBuffer',
260         value: function getBuffer(cb) {
261             cb = cb || this.config.callback;
262             if (!cb) throw new Error('Callback not set');
263 
264             this.callbacks.getBuffer.push(cb);
265 
266             this.worker.postMessage({ command: 'getBuffer' });
267         }
268     }, {
269         key: 'exportWAV',
270         value: function exportWAV(cb, mimeType) {
271             mimeType = mimeType || this.config.mimeType;
272             cb = cb || this.config.callback;
273             if (!cb) throw new Error('Callback not set');
274 
275             this.callbacks.exportWAV.push(cb);
276 
277             this.worker.postMessage({
278                 command: 'exportWAV',
279                 type: mimeType
280             });
281         }
282     }], [{
283         key: 'forceDownload',
284         value: function forceDownload(blob, filename) {
285             var url = (window.URL || window.webkitURL).createObjectURL(blob);
286             var link = window.document.createElement('a');
287             link.href = url;
288             link.download = filename || 'output.wav';
289             var click = document.createEvent("Event");
290             click.initEvent("click", true, true);
291             link.dispatchEvent(click);
292         }
293     }]);
294 
295     return Recorder;
296 })();
297 
298 exports.default = Recorder;
299 
300 },{"inline-worker":3}],3:[function(require,module,exports){
301 "use strict";
302 
303 module.exports = require("./inline-worker");
304 },{"./inline-worker":4}],4:[function(require,module,exports){
305 (function (global){
306 "use strict";
307 
308 var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
309 
310 var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
311 
312 var WORKER_ENABLED = !!(global === global.window && global.URL && global.Blob && global.Worker);
313 
314 var InlineWorker = (function () {
315   function InlineWorker(func, self) {
316     var _this = this;
317 
318     _classCallCheck(this, InlineWorker);
319 
320     if (WORKER_ENABLED) {
321       var functionBody = func.toString().trim().match(/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/)[1];
322       var url = global.URL.createObjectURL(new global.Blob([functionBody], { type: "text/javascript" }));
323 
324       return new global.Worker(url);
325     }
326 
327     this.self = self;
328     this.self.postMessage = function (data) {
329       setTimeout(function () {
330         _this.onmessage({ data: data });
331       }, 0);
332     };
333 
334     setTimeout(function () {
335       func.call(self);
336     }, 0);
337   }
338 
339   _createClass(InlineWorker, {
340     postMessage: {
341       value: function postMessage(data) {
342         var _this = this;
343 
344         setTimeout(function () {
345           _this.self.onmessage({ data: data });
346         }, 0);
347       }
348     }
349   });
350 
351   return InlineWorker;
352 })();
353 
354 module.exports = InlineWorker;
355 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
356 },{}]},{},[1])(1)
357 });

本文来自https://www.fengzhiyun.top/detail/servicecode/54.html

标签:function,__,log,js,通话,window,var,Recorder,audio
来源: https://www.cnblogs.com/changliaokf-com/p/15127610.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有