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

  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

上一篇:MySQL之senior(八)——约束


下一篇:查询作业1