{"version":3,"file":"static/js/vendors-33f59662.782eab10.js","mappings":"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","sources":["../node_modules/recordrtc/RecordRTC.js"],"sourcesContent":["'use strict';\r\n\r\n// Last time updated: 2021-03-09 3:20:22 AM UTC\r\n\r\n// ________________\r\n// RecordRTC v5.6.2\r\n\r\n// Open-Sourced: https://github.com/muaz-khan/RecordRTC\r\n\r\n// --------------------------------------------------\r\n// Muaz Khan - www.MuazKhan.com\r\n// MIT License - www.WebRTC-Experiment.com/licence\r\n// --------------------------------------------------\r\n\r\n// ____________\r\n// RecordRTC.js\r\n\r\n/**\r\n * {@link https://github.com/muaz-khan/RecordRTC|RecordRTC} is a WebRTC JavaScript library for audio/video as well as screen activity recording. It supports Chrome, Firefox, Opera, Android, and Microsoft Edge. Platforms: Linux, Mac and Windows. \r\n * @summary Record audio, video or screen inside the browser.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef RecordRTC\r\n * @class\r\n * @example\r\n * var recorder = RecordRTC(mediaStream or [arrayOfMediaStream], {\r\n * type: 'video', // audio or video or gif or canvas\r\n * recorderType: MediaStreamRecorder || CanvasRecorder || StereoAudioRecorder || Etc\r\n * });\r\n * recorder.startRecording();\r\n * @see For further information:\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc.\r\n * @param {object} config - {type:\"video\", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, desiredSampRate: 16000, video: HTMLVideoElement, etc.}\r\n */\r\n\r\nfunction RecordRTC(mediaStream, config) {\r\n if (!mediaStream) {\r\n throw 'First parameter is required.';\r\n }\r\n\r\n config = config || {\r\n type: 'video'\r\n };\r\n\r\n config = new RecordRTCConfiguration(mediaStream, config);\r\n\r\n // a reference to user's recordRTC object\r\n var self = this;\r\n\r\n function startRecording(config2) {\r\n if (!config.disableLogs) {\r\n console.log('RecordRTC version: ', self.version);\r\n }\r\n\r\n if (!!config2) {\r\n // allow users to set options using startRecording method\r\n // config2 is similar to main \"config\" object (second parameter over RecordRTC constructor)\r\n config = new RecordRTCConfiguration(mediaStream, config2);\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('started recording ' + config.type + ' stream.');\r\n }\r\n\r\n if (mediaRecorder) {\r\n mediaRecorder.clearRecordedData();\r\n mediaRecorder.record();\r\n\r\n setState('recording');\r\n\r\n if (self.recordingDuration) {\r\n handleRecordingDuration();\r\n }\r\n return self;\r\n }\r\n\r\n initRecorder(function() {\r\n if (self.recordingDuration) {\r\n handleRecordingDuration();\r\n }\r\n });\r\n\r\n return self;\r\n }\r\n\r\n function initRecorder(initCallback) {\r\n if (initCallback) {\r\n config.initCallback = function() {\r\n initCallback();\r\n initCallback = config.initCallback = null; // recorder.initRecorder should be call-backed once.\r\n };\r\n }\r\n\r\n var Recorder = new GetRecorderType(mediaStream, config);\r\n\r\n mediaRecorder = new Recorder(mediaStream, config);\r\n mediaRecorder.record();\r\n\r\n setState('recording');\r\n\r\n if (!config.disableLogs) {\r\n console.log('Initialized recorderType:', mediaRecorder.constructor.name, 'for output-type:', config.type);\r\n }\r\n }\r\n\r\n function stopRecording(callback) {\r\n callback = callback || function() {};\r\n\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n if (self.state === 'paused') {\r\n self.resumeRecording();\r\n\r\n setTimeout(function() {\r\n stopRecording(callback);\r\n }, 1);\r\n return;\r\n }\r\n\r\n if (self.state !== 'recording' && !config.disableLogs) {\r\n console.warn('Recording state should be: \"recording\", however current state is: ', self.state);\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('Stopped recording ' + config.type + ' stream.');\r\n }\r\n\r\n if (config.type !== 'gif') {\r\n mediaRecorder.stop(_callback);\r\n } else {\r\n mediaRecorder.stop();\r\n _callback();\r\n }\r\n\r\n setState('stopped');\r\n\r\n function _callback(__blob) {\r\n if (!mediaRecorder) {\r\n if (typeof callback.call === 'function') {\r\n callback.call(self, '');\r\n } else {\r\n callback('');\r\n }\r\n return;\r\n }\r\n\r\n Object.keys(mediaRecorder).forEach(function(key) {\r\n if (typeof mediaRecorder[key] === 'function') {\r\n return;\r\n }\r\n\r\n self[key] = mediaRecorder[key];\r\n });\r\n\r\n var blob = mediaRecorder.blob;\r\n\r\n if (!blob) {\r\n if (__blob) {\r\n mediaRecorder.blob = blob = __blob;\r\n } else {\r\n throw 'Recording failed.';\r\n }\r\n }\r\n\r\n if (blob && !config.disableLogs) {\r\n console.log(blob.type, '->', bytesToSize(blob.size));\r\n }\r\n\r\n if (callback) {\r\n var url;\r\n\r\n try {\r\n url = URL.createObjectURL(blob);\r\n } catch (e) {}\r\n\r\n if (typeof callback.call === 'function') {\r\n callback.call(self, url);\r\n } else {\r\n callback(url);\r\n }\r\n }\r\n\r\n if (!config.autoWriteToDisk) {\r\n return;\r\n }\r\n\r\n getDataURL(function(dataURL) {\r\n var parameter = {};\r\n parameter[config.type + 'Blob'] = dataURL;\r\n DiskStorage.Store(parameter);\r\n });\r\n }\r\n }\r\n\r\n function pauseRecording() {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n if (self.state !== 'recording') {\r\n if (!config.disableLogs) {\r\n console.warn('Unable to pause the recording. Recording state: ', self.state);\r\n }\r\n return;\r\n }\r\n\r\n setState('paused');\r\n\r\n mediaRecorder.pause();\r\n\r\n if (!config.disableLogs) {\r\n console.log('Paused recording.');\r\n }\r\n }\r\n\r\n function resumeRecording() {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n if (self.state !== 'paused') {\r\n if (!config.disableLogs) {\r\n console.warn('Unable to resume the recording. Recording state: ', self.state);\r\n }\r\n return;\r\n }\r\n\r\n setState('recording');\r\n\r\n // not all libs have this method yet\r\n mediaRecorder.resume();\r\n\r\n if (!config.disableLogs) {\r\n console.log('Resumed recording.');\r\n }\r\n }\r\n\r\n function readFile(_blob) {\r\n postMessage(new FileReaderSync().readAsDataURL(_blob));\r\n }\r\n\r\n function getDataURL(callback, _mediaRecorder) {\r\n if (!callback) {\r\n throw 'Pass a callback function over getDataURL.';\r\n }\r\n\r\n var blob = _mediaRecorder ? _mediaRecorder.blob : (mediaRecorder || {}).blob;\r\n\r\n if (!blob) {\r\n if (!config.disableLogs) {\r\n console.warn('Blob encoder did not finish its job yet.');\r\n }\r\n\r\n setTimeout(function() {\r\n getDataURL(callback, _mediaRecorder);\r\n }, 1000);\r\n return;\r\n }\r\n\r\n if (typeof Worker !== 'undefined' && !navigator.mozGetUserMedia) {\r\n var webWorker = processInWebWorker(readFile);\r\n\r\n webWorker.onmessage = function(event) {\r\n callback(event.data);\r\n };\r\n\r\n webWorker.postMessage(blob);\r\n } else {\r\n var reader = new FileReader();\r\n reader.readAsDataURL(blob);\r\n reader.onload = function(event) {\r\n callback(event.target.result);\r\n };\r\n }\r\n\r\n function processInWebWorker(_function) {\r\n try {\r\n var blob = URL.createObjectURL(new Blob([_function.toString(),\r\n 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(blob);\r\n URL.revokeObjectURL(blob);\r\n return worker;\r\n } catch (e) {}\r\n }\r\n }\r\n\r\n function handleRecordingDuration(counter) {\r\n counter = counter || 0;\r\n\r\n if (self.state === 'paused') {\r\n setTimeout(function() {\r\n handleRecordingDuration(counter);\r\n }, 1000);\r\n return;\r\n }\r\n\r\n if (self.state === 'stopped') {\r\n return;\r\n }\r\n\r\n if (counter >= self.recordingDuration) {\r\n stopRecording(self.onRecordingStopped);\r\n return;\r\n }\r\n\r\n counter += 1000; // 1-second\r\n\r\n setTimeout(function() {\r\n handleRecordingDuration(counter);\r\n }, 1000);\r\n }\r\n\r\n function setState(state) {\r\n if (!self) {\r\n return;\r\n }\r\n\r\n self.state = state;\r\n\r\n if (typeof self.onStateChanged.call === 'function') {\r\n self.onStateChanged.call(self, state);\r\n } else {\r\n self.onStateChanged(state);\r\n }\r\n }\r\n\r\n var WARNING = 'It seems that recorder is destroyed or \"startRecording\" is not invoked for ' + config.type + ' recorder.';\r\n\r\n function warningLog() {\r\n if (config.disableLogs === true) {\r\n return;\r\n }\r\n\r\n console.warn(WARNING);\r\n }\r\n\r\n var mediaRecorder;\r\n\r\n var returnObject = {\r\n /**\r\n * This method starts the recording.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * var recorder = RecordRTC(mediaStream, {\r\n * type: 'video'\r\n * });\r\n * recorder.startRecording();\r\n */\r\n startRecording: startRecording,\r\n\r\n /**\r\n * This method stops the recording. It is strongly recommended to get \"blob\" or \"URI\" inside the callback to make sure all recorders finished their job.\r\n * @param {function} callback - Callback to get the recorded blob.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * // use either \"this\" or \"recorder\" object; both are identical\r\n * video.src = this.toURL();\r\n * var blob = this.getBlob();\r\n * });\r\n */\r\n stopRecording: stopRecording,\r\n\r\n /**\r\n * This method pauses the recording. You can resume recording using \"resumeRecording\" method.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @todo Firefox is unable to pause the recording. Fix it.\r\n * @example\r\n * recorder.pauseRecording(); // pause the recording\r\n * recorder.resumeRecording(); // resume again\r\n */\r\n pauseRecording: pauseRecording,\r\n\r\n /**\r\n * This method resumes the recording.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.pauseRecording(); // first of all, pause the recording\r\n * recorder.resumeRecording(); // now resume it\r\n */\r\n resumeRecording: resumeRecording,\r\n\r\n /**\r\n * This method initializes the recording.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @todo This method should be deprecated.\r\n * @example\r\n * recorder.initRecorder();\r\n */\r\n initRecorder: initRecorder,\r\n\r\n /**\r\n * Ask RecordRTC to auto-stop the recording after 5 minutes.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * var fiveMinutes = 5 * 1000 * 60;\r\n * recorder.setRecordingDuration(fiveMinutes, function() {\r\n * var blob = this.getBlob();\r\n * video.src = this.toURL();\r\n * });\r\n * \r\n * // or otherwise\r\n * recorder.setRecordingDuration(fiveMinutes).onRecordingStopped(function() {\r\n * var blob = this.getBlob();\r\n * video.src = this.toURL();\r\n * });\r\n */\r\n setRecordingDuration: function(recordingDuration, callback) {\r\n if (typeof recordingDuration === 'undefined') {\r\n throw 'recordingDuration is required.';\r\n }\r\n\r\n if (typeof recordingDuration !== 'number') {\r\n throw 'recordingDuration must be a number.';\r\n }\r\n\r\n self.recordingDuration = recordingDuration;\r\n self.onRecordingStopped = callback || function() {};\r\n\r\n return {\r\n onRecordingStopped: function(callback) {\r\n self.onRecordingStopped = callback;\r\n }\r\n };\r\n },\r\n\r\n /**\r\n * This method can be used to clear/reset all the recorded data.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @todo Figure out the difference between \"reset\" and \"clearRecordedData\" methods.\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n clearRecordedData: function() {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n mediaRecorder.clearRecordedData();\r\n\r\n if (!config.disableLogs) {\r\n console.log('Cleared old recorded data.');\r\n }\r\n },\r\n\r\n /**\r\n * Get the recorded blob. Use this method inside the \"stopRecording\" callback.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * var blob = this.getBlob();\r\n *\r\n * var file = new File([blob], 'filename.webm', {\r\n * type: 'video/webm'\r\n * });\r\n *\r\n * var formData = new FormData();\r\n * formData.append('file', file); // upload \"File\" object rather than a \"Blob\"\r\n * uploadToServer(formData);\r\n * });\r\n * @returns {Blob} Returns recorded data as \"Blob\" object.\r\n */\r\n getBlob: function() {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n return mediaRecorder.blob;\r\n },\r\n\r\n /**\r\n * Get data-URI instead of Blob.\r\n * @param {function} callback - Callback to get the Data-URI.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * recorder.getDataURL(function(dataURI) {\r\n * video.src = dataURI;\r\n * });\r\n * });\r\n */\r\n getDataURL: getDataURL,\r\n\r\n /**\r\n * Get virtual/temporary URL. Usage of this URL is limited to current tab.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * video.src = this.toURL();\r\n * });\r\n * @returns {String} Returns a virtual/temporary URL for the recorded \"Blob\".\r\n */\r\n toURL: function() {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n return URL.createObjectURL(mediaRecorder.blob);\r\n },\r\n\r\n /**\r\n * Get internal recording object (i.e. internal module) e.g. MutliStreamRecorder, MediaStreamRecorder, StereoAudioRecorder or WhammyRecorder etc.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * var internalRecorder = recorder.getInternalRecorder();\r\n * if(internalRecorder instanceof MultiStreamRecorder) {\r\n * internalRecorder.addStreams([newAudioStream]);\r\n * internalRecorder.resetVideoStreams([screenStream]);\r\n * }\r\n * @returns {Object} Returns internal recording object.\r\n */\r\n getInternalRecorder: function() {\r\n return mediaRecorder;\r\n },\r\n\r\n /**\r\n * Invoke save-as dialog to save the recorded blob into your disk.\r\n * @param {string} fileName - Set your own file name.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * this.save('file-name');\r\n *\r\n * // or manually:\r\n * invokeSaveAsDialog(this.getBlob(), 'filename.webm');\r\n * });\r\n */\r\n save: function(fileName) {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n invokeSaveAsDialog(mediaRecorder.blob, fileName);\r\n },\r\n\r\n /**\r\n * This method gets a blob from indexed-DB storage.\r\n * @param {function} callback - Callback to get the recorded blob.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.getFromDisk(function(dataURL) {\r\n * video.src = dataURL;\r\n * });\r\n */\r\n getFromDisk: function(callback) {\r\n if (!mediaRecorder) {\r\n warningLog();\r\n return;\r\n }\r\n\r\n RecordRTC.getFromDisk(config.type, callback);\r\n },\r\n\r\n /**\r\n * This method appends an array of webp images to the recorded video-blob. It takes an \"array\" object.\r\n * @type {Array.}\r\n * @param {Array} arrayOfWebPImages - Array of webp images.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @todo This method should be deprecated.\r\n * @example\r\n * var arrayOfWebPImages = [];\r\n * arrayOfWebPImages.push({\r\n * duration: index,\r\n * image: 'data:image/webp;base64,...'\r\n * });\r\n * recorder.setAdvertisementArray(arrayOfWebPImages);\r\n */\r\n setAdvertisementArray: function(arrayOfWebPImages) {\r\n config.advertisement = [];\r\n\r\n var length = arrayOfWebPImages.length;\r\n for (var i = 0; i < length; i++) {\r\n config.advertisement.push({\r\n duration: i,\r\n image: arrayOfWebPImages[i]\r\n });\r\n }\r\n },\r\n\r\n /**\r\n * It is equivalent to \"recorder.getBlob()\" method. Usage of \"getBlob\" is recommended, though.\r\n * @property {Blob} blob - Recorded Blob can be accessed using this property.\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * var blob = this.blob;\r\n *\r\n * // below one is recommended\r\n * var blob = this.getBlob();\r\n * });\r\n */\r\n blob: null,\r\n\r\n /**\r\n * This works only with {recorderType:StereoAudioRecorder}. Use this property on \"stopRecording\" to verify the encoder's sample-rates.\r\n * @property {number} bufferSize - Buffer-size used to encode the WAV container\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * alert('Recorder used this buffer-size: ' + this.bufferSize);\r\n * });\r\n */\r\n bufferSize: 0,\r\n\r\n /**\r\n * This works only with {recorderType:StereoAudioRecorder}. Use this property on \"stopRecording\" to verify the encoder's sample-rates.\r\n * @property {number} sampleRate - Sample-rates used to encode the WAV container\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * alert('Recorder used these sample-rates: ' + this.sampleRate);\r\n * });\r\n */\r\n sampleRate: 0,\r\n\r\n /**\r\n * {recorderType:StereoAudioRecorder} returns ArrayBuffer object.\r\n * @property {ArrayBuffer} buffer - Audio ArrayBuffer, supported only in Chrome.\r\n * @memberof RecordRTC\r\n * @instance\r\n * @readonly\r\n * @example\r\n * recorder.stopRecording(function() {\r\n * var arrayBuffer = this.buffer;\r\n * alert(arrayBuffer.byteLength);\r\n * });\r\n */\r\n buffer: null,\r\n\r\n /**\r\n * This method resets the recorder. So that you can reuse single recorder instance many times.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.reset();\r\n * recorder.startRecording();\r\n */\r\n reset: function() {\r\n if (self.state === 'recording' && !config.disableLogs) {\r\n console.warn('Stop an active recorder.');\r\n }\r\n\r\n if (mediaRecorder && typeof mediaRecorder.clearRecordedData === 'function') {\r\n mediaRecorder.clearRecordedData();\r\n }\r\n mediaRecorder = null;\r\n setState('inactive');\r\n self.blob = null;\r\n },\r\n\r\n /**\r\n * This method is called whenever recorder's state changes. Use this as an \"event\".\r\n * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive.\r\n * @method\r\n * @memberof RecordRTC\r\n * @instance\r\n * @example\r\n * recorder.onStateChanged = function(state) {\r\n * console.log('Recorder state: ', state);\r\n * };\r\n */\r\n onStateChanged: function(state) {\r\n if (!config.disableLogs) {\r\n console.log('Recorder state changed:', state);\r\n }\r\n },\r\n\r\n /**\r\n * A recorder can have inactive, recording, paused or stopped states.\r\n * @property {String} state - A recorder's state can be: recording, paused, stopped or inactive.\r\n * @memberof RecordRTC\r\n * @static\r\n * @readonly\r\n * @example\r\n * // this looper function will keep you updated about the recorder's states.\r\n * (function looper() {\r\n * document.querySelector('h1').innerHTML = 'Recorder\\'s state is: ' + recorder.state;\r\n * if(recorder.state === 'stopped') return; // ignore+stop\r\n * setTimeout(looper, 1000); // update after every 3-seconds\r\n * })();\r\n * recorder.startRecording();\r\n */\r\n state: 'inactive',\r\n\r\n /**\r\n * Get recorder's readonly state.\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * var state = recorder.getState();\r\n * @returns {String} Returns recording state.\r\n */\r\n getState: function() {\r\n return self.state;\r\n },\r\n\r\n /**\r\n * Destroy RecordRTC instance. Clear all recorders and objects.\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * recorder.destroy();\r\n */\r\n destroy: function() {\r\n var disableLogsCache = config.disableLogs;\r\n\r\n config = {\r\n disableLogs: true\r\n };\r\n self.reset();\r\n setState('destroyed');\r\n returnObject = self = null;\r\n\r\n if (Storage.AudioContextConstructor) {\r\n Storage.AudioContextConstructor.close();\r\n Storage.AudioContextConstructor = null;\r\n }\r\n\r\n config.disableLogs = disableLogsCache;\r\n\r\n if (!config.disableLogs) {\r\n console.log('RecordRTC is destroyed.');\r\n }\r\n },\r\n\r\n /**\r\n * RecordRTC version number\r\n * @property {String} version - Release version number.\r\n * @memberof RecordRTC\r\n * @static\r\n * @readonly\r\n * @example\r\n * alert(recorder.version);\r\n */\r\n version: '5.6.2'\r\n };\r\n\r\n if (!this) {\r\n self = returnObject;\r\n return returnObject;\r\n }\r\n\r\n // if someone wants to use RecordRTC with the \"new\" keyword.\r\n for (var prop in returnObject) {\r\n this[prop] = returnObject[prop];\r\n }\r\n\r\n self = this;\r\n\r\n return returnObject;\r\n}\r\n\r\nRecordRTC.version = '5.6.2';\r\n\r\nif (typeof module !== 'undefined' /* && !!module.exports*/ ) {\r\n module.exports = RecordRTC;\r\n}\r\n\r\nif (typeof define === 'function' && define.amd) {\r\n define('RecordRTC', [], function() {\r\n return RecordRTC;\r\n });\r\n}\n\r\nRecordRTC.getFromDisk = function(type, callback) {\r\n if (!callback) {\r\n throw 'callback is mandatory.';\r\n }\r\n\r\n console.log('Getting recorded ' + (type === 'all' ? 'blobs' : type + ' blob ') + ' from disk!');\r\n DiskStorage.Fetch(function(dataURL, _type) {\r\n if (type !== 'all' && _type === type + 'Blob' && callback) {\r\n callback(dataURL);\r\n }\r\n\r\n if (type === 'all' && callback) {\r\n callback(dataURL, _type.replace('Blob', ''));\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * This method can be used to store recorded blobs into IndexedDB storage.\r\n * @param {object} options - {audio: Blob, video: Blob, gif: Blob}\r\n * @method\r\n * @memberof RecordRTC\r\n * @example\r\n * RecordRTC.writeToDisk({\r\n * audio: audioBlob,\r\n * video: videoBlob,\r\n * gif : gifBlob\r\n * });\r\n */\r\nRecordRTC.writeToDisk = function(options) {\r\n console.log('Writing recorded blob(s) to disk!');\r\n options = options || {};\r\n if (options.audio && options.video && options.gif) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n videoBlob: videoDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n });\r\n } else if (options.audio && options.video) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n videoBlob: videoDataURL\r\n });\r\n });\r\n });\r\n } else if (options.audio && options.gif) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n } else if (options.video && options.gif) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n videoBlob: videoDataURL,\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n });\r\n } else if (options.audio) {\r\n options.audio.getDataURL(function(audioDataURL) {\r\n DiskStorage.Store({\r\n audioBlob: audioDataURL\r\n });\r\n });\r\n } else if (options.video) {\r\n options.video.getDataURL(function(videoDataURL) {\r\n DiskStorage.Store({\r\n videoBlob: videoDataURL\r\n });\r\n });\r\n } else if (options.gif) {\r\n options.gif.getDataURL(function(gifDataURL) {\r\n DiskStorage.Store({\r\n gifBlob: gifDataURL\r\n });\r\n });\r\n }\r\n};\n\r\n// __________________________\r\n// RecordRTC-Configuration.js\r\n\r\n/**\r\n * {@link RecordRTCConfiguration} is an inner/private helper for {@link RecordRTC}.\r\n * @summary It configures the 2nd parameter passed over {@link RecordRTC} and returns a valid \"config\" object.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef RecordRTCConfiguration\r\n * @class\r\n * @example\r\n * var options = RecordRTCConfiguration(mediaStream, options);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {type:\"video\", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, getNativeBlob:true, etc.}\r\n */\r\n\r\nfunction RecordRTCConfiguration(mediaStream, config) {\r\n if (!config.recorderType && !config.type) {\r\n if (!!config.audio && !!config.video) {\r\n config.type = 'video';\r\n } else if (!!config.audio && !config.video) {\r\n config.type = 'audio';\r\n }\r\n }\r\n\r\n if (config.recorderType && !config.type) {\r\n if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder || (typeof WebAssemblyRecorder !== 'undefined' && config.recorderType === WebAssemblyRecorder)) {\r\n config.type = 'video';\r\n } else if (config.recorderType === GifRecorder) {\r\n config.type = 'gif';\r\n } else if (config.recorderType === StereoAudioRecorder) {\r\n config.type = 'audio';\r\n } else if (config.recorderType === MediaStreamRecorder) {\r\n if (getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) {\r\n config.type = 'video';\r\n } else if (!getTracks(mediaStream, 'audio').length && getTracks(mediaStream, 'video').length) {\r\n config.type = 'video';\r\n } else if (getTracks(mediaStream, 'audio').length && !getTracks(mediaStream, 'video').length) {\r\n config.type = 'audio';\r\n } else {\r\n // config.type = 'UnKnown';\r\n }\r\n }\r\n }\r\n\r\n if (typeof MediaStreamRecorder !== 'undefined' && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) {\r\n if (!config.mimeType) {\r\n config.mimeType = 'video/webm';\r\n }\r\n\r\n if (!config.type) {\r\n config.type = config.mimeType.split('/')[0];\r\n }\r\n\r\n if (!config.bitsPerSecond) {\r\n // config.bitsPerSecond = 128000;\r\n }\r\n }\r\n\r\n // consider default type=audio\r\n if (!config.type) {\r\n if (config.mimeType) {\r\n config.type = config.mimeType.split('/')[0];\r\n }\r\n if (!config.type) {\r\n config.type = 'audio';\r\n }\r\n }\r\n\r\n return config;\r\n}\n\r\n// __________________\r\n// GetRecorderType.js\r\n\r\n/**\r\n * {@link GetRecorderType} is an inner/private helper for {@link RecordRTC}.\r\n * @summary It returns best recorder-type available for your browser.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef GetRecorderType\r\n * @class\r\n * @example\r\n * var RecorderType = GetRecorderType(options);\r\n * var recorder = new RecorderType(options);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {type:\"video\", disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}\r\n */\r\n\r\nfunction GetRecorderType(mediaStream, config) {\r\n var recorder;\r\n\r\n // StereoAudioRecorder can work with all three: Edge, Firefox and Chrome\r\n // todo: detect if it is Edge, then auto use: StereoAudioRecorder\r\n if (isChrome || isEdge || isOpera) {\r\n // Media Stream Recording API has not been implemented in chrome yet;\r\n // That's why using WebAudio API to record stereo audio in WAV format\r\n recorder = StereoAudioRecorder;\r\n }\r\n\r\n if (typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype && !isChrome) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n\r\n // video recorder (in WebM format)\r\n if (config.type === 'video' && (isChrome || isOpera)) {\r\n recorder = WhammyRecorder;\r\n\r\n if (typeof WebAssemblyRecorder !== 'undefined' && typeof ReadableStream !== 'undefined') {\r\n recorder = WebAssemblyRecorder;\r\n }\r\n }\r\n\r\n // video recorder (in Gif format)\r\n if (config.type === 'gif') {\r\n recorder = GifRecorder;\r\n }\r\n\r\n // html2canvas recording!\r\n if (config.type === 'canvas') {\r\n recorder = CanvasRecorder;\r\n }\r\n\r\n if (isMediaRecorderCompatible() && recorder !== CanvasRecorder && recorder !== GifRecorder && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) {\r\n if (getTracks(mediaStream, 'video').length || getTracks(mediaStream, 'audio').length) {\r\n // audio-only recording\r\n if (config.type === 'audio') {\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('audio/webm')) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n // else recorder = StereoAudioRecorder;\r\n } else {\r\n // video or screen tracks\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && MediaRecorder.isTypeSupported('video/webm')) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (mediaStream instanceof Array && mediaStream.length) {\r\n recorder = MultiStreamRecorder;\r\n }\r\n\r\n if (config.recorderType) {\r\n recorder = config.recorderType;\r\n }\r\n\r\n if (!config.disableLogs && !!recorder && !!recorder.name) {\r\n console.log('Using recorderType:', recorder.name || recorder.constructor.name);\r\n }\r\n\r\n if (!recorder && isSafari) {\r\n recorder = MediaStreamRecorder;\r\n }\r\n\r\n return recorder;\r\n}\n\r\n// _____________\r\n// MRecordRTC.js\r\n\r\n/**\r\n * MRecordRTC runs on top of {@link RecordRTC} to bring multiple recordings in a single place, by providing simple API.\r\n * @summary MRecordRTC stands for \"Multiple-RecordRTC\".\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef MRecordRTC\r\n * @class\r\n * @example\r\n * var recorder = new MRecordRTC();\r\n * recorder.addStream(MediaStream);\r\n * recorder.mediaType = {\r\n * audio: true, // or StereoAudioRecorder or MediaStreamRecorder\r\n * video: true, // or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder\r\n * gif: true // or GifRecorder\r\n * };\r\n * // mimeType is optional and should be set only in advance cases.\r\n * recorder.mimeType = {\r\n * audio: 'audio/wav',\r\n * video: 'video/webm',\r\n * gif: 'image/gif'\r\n * };\r\n * recorder.startRecording();\r\n * @see For further information:\r\n * @see {@link https://github.com/muaz-khan/RecordRTC/tree/master/MRecordRTC|MRecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @requires {@link RecordRTC}\r\n */\r\n\r\nfunction MRecordRTC(mediaStream) {\r\n\r\n /**\r\n * This method attaches MediaStream object to {@link MRecordRTC}.\r\n * @param {MediaStream} mediaStream - A MediaStream object, either fetched using getUserMedia API, or generated using captureStreamUntilEnded or WebAudio API.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.addStream(MediaStream);\r\n */\r\n this.addStream = function(_mediaStream) {\r\n if (_mediaStream) {\r\n mediaStream = _mediaStream;\r\n }\r\n };\r\n\r\n /**\r\n * This property can be used to set the recording type e.g. audio, or video, or gif, or canvas.\r\n * @property {object} mediaType - {audio: true, video: true, gif: true}\r\n * @memberof MRecordRTC\r\n * @example\r\n * var recorder = new MRecordRTC();\r\n * recorder.mediaType = {\r\n * audio: true, // TRUE or StereoAudioRecorder or MediaStreamRecorder\r\n * video: true, // TRUE or WhammyRecorder or MediaStreamRecorder or WebAssemblyRecorder or CanvasRecorder\r\n * gif : true // TRUE or GifRecorder\r\n * };\r\n */\r\n this.mediaType = {\r\n audio: true,\r\n video: true\r\n };\r\n\r\n /**\r\n * This method starts recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.startRecording();\r\n */\r\n this.startRecording = function() {\r\n var mediaType = this.mediaType;\r\n var recorderType;\r\n var mimeType = this.mimeType || {\r\n audio: null,\r\n video: null,\r\n gif: null\r\n };\r\n\r\n if (typeof mediaType.audio !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'audio').length) {\r\n mediaType.audio = false;\r\n }\r\n\r\n if (typeof mediaType.video !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) {\r\n mediaType.video = false;\r\n }\r\n\r\n if (typeof mediaType.gif !== 'function' && isMediaRecorderCompatible() && !getTracks(mediaStream, 'video').length) {\r\n mediaType.gif = false;\r\n }\r\n\r\n if (!mediaType.audio && !mediaType.video && !mediaType.gif) {\r\n throw 'MediaStream must have either audio or video tracks.';\r\n }\r\n\r\n if (!!mediaType.audio) {\r\n recorderType = null;\r\n if (typeof mediaType.audio === 'function') {\r\n recorderType = mediaType.audio;\r\n }\r\n\r\n this.audioRecorder = new RecordRTC(mediaStream, {\r\n type: 'audio',\r\n bufferSize: this.bufferSize,\r\n sampleRate: this.sampleRate,\r\n numberOfAudioChannels: this.numberOfAudioChannels || 2,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.audio,\r\n timeSlice: this.timeSlice,\r\n onTimeStamp: this.onTimeStamp\r\n });\r\n\r\n if (!mediaType.video) {\r\n this.audioRecorder.startRecording();\r\n }\r\n }\r\n\r\n if (!!mediaType.video) {\r\n recorderType = null;\r\n if (typeof mediaType.video === 'function') {\r\n recorderType = mediaType.video;\r\n }\r\n\r\n var newStream = mediaStream;\r\n\r\n if (isMediaRecorderCompatible() && !!mediaType.audio && typeof mediaType.audio === 'function') {\r\n var videoTrack = getTracks(mediaStream, 'video')[0];\r\n\r\n if (isFirefox) {\r\n newStream = new MediaStream();\r\n newStream.addTrack(videoTrack);\r\n\r\n if (recorderType && recorderType === WhammyRecorder) {\r\n // Firefox does NOT supports webp-encoding yet\r\n // But Firefox do supports WebAssemblyRecorder\r\n recorderType = MediaStreamRecorder;\r\n }\r\n } else {\r\n newStream = new MediaStream();\r\n newStream.addTrack(videoTrack);\r\n }\r\n }\r\n\r\n this.videoRecorder = new RecordRTC(newStream, {\r\n type: 'video',\r\n video: this.video,\r\n canvas: this.canvas,\r\n frameInterval: this.frameInterval || 10,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.video,\r\n timeSlice: this.timeSlice,\r\n onTimeStamp: this.onTimeStamp,\r\n workerPath: this.workerPath,\r\n webAssemblyPath: this.webAssemblyPath,\r\n frameRate: this.frameRate, // used by WebAssemblyRecorder; values: usually 30; accepts any.\r\n bitrate: this.bitrate // used by WebAssemblyRecorder; values: 0 to 1000+\r\n });\r\n\r\n if (!mediaType.audio) {\r\n this.videoRecorder.startRecording();\r\n }\r\n }\r\n\r\n if (!!mediaType.audio && !!mediaType.video) {\r\n var self = this;\r\n\r\n var isSingleRecorder = isMediaRecorderCompatible() === true;\r\n\r\n if (mediaType.audio instanceof StereoAudioRecorder && !!mediaType.video) {\r\n isSingleRecorder = false;\r\n } else if (mediaType.audio !== true && mediaType.video !== true && mediaType.audio !== mediaType.video) {\r\n isSingleRecorder = false;\r\n }\r\n\r\n if (isSingleRecorder === true) {\r\n self.audioRecorder = null;\r\n self.videoRecorder.startRecording();\r\n } else {\r\n self.videoRecorder.initRecorder(function() {\r\n self.audioRecorder.initRecorder(function() {\r\n // Both recorders are ready to record things accurately\r\n self.videoRecorder.startRecording();\r\n self.audioRecorder.startRecording();\r\n });\r\n });\r\n }\r\n }\r\n\r\n if (!!mediaType.gif) {\r\n recorderType = null;\r\n if (typeof mediaType.gif === 'function') {\r\n recorderType = mediaType.gif;\r\n }\r\n this.gifRecorder = new RecordRTC(mediaStream, {\r\n type: 'gif',\r\n frameRate: this.frameRate || 200,\r\n quality: this.quality || 10,\r\n disableLogs: this.disableLogs,\r\n recorderType: recorderType,\r\n mimeType: mimeType.gif\r\n });\r\n this.gifRecorder.startRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method stops recording.\r\n * @param {function} callback - Callback function is invoked when all encoders finished their jobs.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.stopRecording(function(recording){\r\n * var audioBlob = recording.audio;\r\n * var videoBlob = recording.video;\r\n * var gifBlob = recording.gif;\r\n * });\r\n */\r\n this.stopRecording = function(callback) {\r\n callback = callback || function() {};\r\n\r\n if (this.audioRecorder) {\r\n this.audioRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'audio');\r\n });\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'video');\r\n });\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.stopRecording(function(blobURL) {\r\n callback(blobURL, 'gif');\r\n });\r\n }\r\n };\r\n\r\n /**\r\n * This method pauses recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.pauseRecording();\r\n */\r\n this.pauseRecording = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.pauseRecording();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.pauseRecording();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.pauseRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes recording.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.resumeRecording();\r\n */\r\n this.resumeRecording = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.resumeRecording();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.resumeRecording();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.resumeRecording();\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to manually get all recorded blobs.\r\n * @param {function} callback - All recorded blobs are passed back to the \"callback\" function.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.getBlob(function(recording){\r\n * var audioBlob = recording.audio;\r\n * var videoBlob = recording.video;\r\n * var gifBlob = recording.gif;\r\n * });\r\n * // or\r\n * var audioBlob = recorder.getBlob().audio;\r\n * var videoBlob = recorder.getBlob().video;\r\n */\r\n this.getBlob = function(callback) {\r\n var output = {};\r\n\r\n if (this.audioRecorder) {\r\n output.audio = this.audioRecorder.getBlob();\r\n }\r\n\r\n if (this.videoRecorder) {\r\n output.video = this.videoRecorder.getBlob();\r\n }\r\n\r\n if (this.gifRecorder) {\r\n output.gif = this.gifRecorder.getBlob();\r\n }\r\n\r\n if (callback) {\r\n callback(output);\r\n }\r\n\r\n return output;\r\n };\r\n\r\n /**\r\n * Destroy all recorder instances.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.destroy();\r\n */\r\n this.destroy = function() {\r\n if (this.audioRecorder) {\r\n this.audioRecorder.destroy();\r\n this.audioRecorder = null;\r\n }\r\n\r\n if (this.videoRecorder) {\r\n this.videoRecorder.destroy();\r\n this.videoRecorder = null;\r\n }\r\n\r\n if (this.gifRecorder) {\r\n this.gifRecorder.destroy();\r\n this.gifRecorder = null;\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to manually get all recorded blobs' DataURLs.\r\n * @param {function} callback - All recorded blobs' DataURLs are passed back to the \"callback\" function.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.getDataURL(function(recording){\r\n * var audioDataURL = recording.audio;\r\n * var videoDataURL = recording.video;\r\n * var gifDataURL = recording.gif;\r\n * });\r\n */\r\n this.getDataURL = function(callback) {\r\n this.getBlob(function(blob) {\r\n if (blob.audio && blob.video) {\r\n getDataURL(blob.audio, function(_audioDataURL) {\r\n getDataURL(blob.video, function(_videoDataURL) {\r\n callback({\r\n audio: _audioDataURL,\r\n video: _videoDataURL\r\n });\r\n });\r\n });\r\n } else if (blob.audio) {\r\n getDataURL(blob.audio, function(_audioDataURL) {\r\n callback({\r\n audio: _audioDataURL\r\n });\r\n });\r\n } else if (blob.video) {\r\n getDataURL(blob.video, function(_videoDataURL) {\r\n callback({\r\n video: _videoDataURL\r\n });\r\n });\r\n }\r\n });\r\n\r\n function getDataURL(blob, callback00) {\r\n if (typeof Worker !== 'undefined') {\r\n var webWorker = processInWebWorker(function readFile(_blob) {\r\n postMessage(new FileReaderSync().readAsDataURL(_blob));\r\n });\r\n\r\n webWorker.onmessage = function(event) {\r\n callback00(event.data);\r\n };\r\n\r\n webWorker.postMessage(blob);\r\n } else {\r\n var reader = new FileReader();\r\n reader.readAsDataURL(blob);\r\n reader.onload = function(event) {\r\n callback00(event.target.result);\r\n };\r\n }\r\n }\r\n\r\n function processInWebWorker(_function) {\r\n var blob = URL.createObjectURL(new Blob([_function.toString(),\r\n 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(blob);\r\n var url;\r\n if (typeof URL !== 'undefined') {\r\n url = URL;\r\n } else if (typeof webkitURL !== 'undefined') {\r\n url = webkitURL;\r\n } else {\r\n throw 'Neither URL nor webkitURL detected.';\r\n }\r\n url.revokeObjectURL(blob);\r\n return worker;\r\n }\r\n };\r\n\r\n /**\r\n * This method can be used to ask {@link MRecordRTC} to write all recorded blobs into IndexedDB storage.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.writeToDisk();\r\n */\r\n this.writeToDisk = function() {\r\n RecordRTC.writeToDisk({\r\n audio: this.audioRecorder,\r\n video: this.videoRecorder,\r\n gif: this.gifRecorder\r\n });\r\n };\r\n\r\n /**\r\n * This method can be used to invoke a save-as dialog for all recorded blobs.\r\n * @param {object} args - {audio: 'audio-name', video: 'video-name', gif: 'gif-name'}\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * recorder.save({\r\n * audio: 'audio-file-name',\r\n * video: 'video-file-name',\r\n * gif : 'gif-file-name'\r\n * });\r\n */\r\n this.save = function(args) {\r\n args = args || {\r\n audio: true,\r\n video: true,\r\n gif: true\r\n };\r\n\r\n if (!!args.audio && this.audioRecorder) {\r\n this.audioRecorder.save(typeof args.audio === 'string' ? args.audio : '');\r\n }\r\n\r\n if (!!args.video && this.videoRecorder) {\r\n this.videoRecorder.save(typeof args.video === 'string' ? args.video : '');\r\n }\r\n if (!!args.gif && this.gifRecorder) {\r\n this.gifRecorder.save(typeof args.gif === 'string' ? args.gif : '');\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * This method can be used to get all recorded blobs from IndexedDB storage.\r\n * @param {string} type - 'all' or 'audio' or 'video' or 'gif'\r\n * @param {function} callback - Callback function to get all stored blobs.\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * MRecordRTC.getFromDisk('all', function(dataURL, type){\r\n * if(type === 'audio') { }\r\n * if(type === 'video') { }\r\n * if(type === 'gif') { }\r\n * });\r\n */\r\nMRecordRTC.getFromDisk = RecordRTC.getFromDisk;\r\n\r\n/**\r\n * This method can be used to store recorded blobs into IndexedDB storage.\r\n * @param {object} options - {audio: Blob, video: Blob, gif: Blob}\r\n * @method\r\n * @memberof MRecordRTC\r\n * @example\r\n * MRecordRTC.writeToDisk({\r\n * audio: audioBlob,\r\n * video: videoBlob,\r\n * gif : gifBlob\r\n * });\r\n */\r\nMRecordRTC.writeToDisk = RecordRTC.writeToDisk;\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MRecordRTC = MRecordRTC;\r\n}\n\r\nvar browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45';\r\n\r\n(function(that) {\r\n if (!that) {\r\n return;\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (typeof global === 'undefined') {\r\n return;\r\n }\r\n\r\n global.navigator = {\r\n userAgent: browserFakeUserAgent,\r\n getUserMedia: function() {}\r\n };\r\n\r\n if (!global.console) {\r\n global.console = {};\r\n }\r\n\r\n if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') {\r\n global.console.error = global.console.log = global.console.log || function() {\r\n console.log(arguments);\r\n };\r\n }\r\n\r\n if (typeof document === 'undefined') {\r\n /*global document:true */\r\n that.document = {\r\n documentElement: {\r\n appendChild: function() {\r\n return '';\r\n }\r\n }\r\n };\r\n\r\n document.createElement = document.captureStream = document.mozCaptureStream = function() {\r\n var obj = {\r\n getContext: function() {\r\n return obj;\r\n },\r\n play: function() {},\r\n pause: function() {},\r\n drawImage: function() {},\r\n toDataURL: function() {\r\n return '';\r\n },\r\n style: {}\r\n };\r\n return obj;\r\n };\r\n\r\n that.HTMLVideoElement = function() {};\r\n }\r\n\r\n if (typeof location === 'undefined') {\r\n /*global location:true */\r\n that.location = {\r\n protocol: 'file:',\r\n href: '',\r\n hash: ''\r\n };\r\n }\r\n\r\n if (typeof screen === 'undefined') {\r\n /*global screen:true */\r\n that.screen = {\r\n width: 0,\r\n height: 0\r\n };\r\n }\r\n\r\n if (typeof URL === 'undefined') {\r\n /*global screen:true */\r\n that.URL = {\r\n createObjectURL: function() {\r\n return '';\r\n },\r\n revokeObjectURL: function() {\r\n return '';\r\n }\r\n };\r\n }\r\n\r\n /*global window:true */\r\n that.window = global;\r\n})(typeof global !== 'undefined' ? global : null);\n\r\n// _____________________________\r\n// Cross-Browser-Declarations.js\r\n\r\n// animation-frame used in WebM recording\r\n\r\n/*jshint -W079 */\r\nvar requestAnimationFrame = window.requestAnimationFrame;\r\nif (typeof requestAnimationFrame === 'undefined') {\r\n if (typeof webkitRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = webkitRequestAnimationFrame;\r\n } else if (typeof mozRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = mozRequestAnimationFrame;\r\n } else if (typeof msRequestAnimationFrame !== 'undefined') {\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = msRequestAnimationFrame;\r\n } else if (typeof requestAnimationFrame === 'undefined') {\r\n // via: https://gist.github.com/paulirish/1579671\r\n var lastTime = 0;\r\n\r\n /*global requestAnimationFrame:true */\r\n requestAnimationFrame = function(callback, element) {\r\n var currTime = new Date().getTime();\r\n var timeToCall = Math.max(0, 16 - (currTime - lastTime));\r\n var id = setTimeout(function() {\r\n callback(currTime + timeToCall);\r\n }, timeToCall);\r\n lastTime = currTime + timeToCall;\r\n return id;\r\n };\r\n }\r\n}\r\n\r\n/*jshint -W079 */\r\nvar cancelAnimationFrame = window.cancelAnimationFrame;\r\nif (typeof cancelAnimationFrame === 'undefined') {\r\n if (typeof webkitCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = webkitCancelAnimationFrame;\r\n } else if (typeof mozCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = mozCancelAnimationFrame;\r\n } else if (typeof msCancelAnimationFrame !== 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = msCancelAnimationFrame;\r\n } else if (typeof cancelAnimationFrame === 'undefined') {\r\n /*global cancelAnimationFrame:true */\r\n cancelAnimationFrame = function(id) {\r\n clearTimeout(id);\r\n };\r\n }\r\n}\r\n\r\n// WebAudio API representer\r\nvar AudioContext = window.AudioContext;\r\n\r\nif (typeof AudioContext === 'undefined') {\r\n if (typeof webkitAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = webkitAudioContext;\r\n }\r\n\r\n if (typeof mozAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = mozAudioContext;\r\n }\r\n}\r\n\r\n/*jshint -W079 */\r\nvar URL = window.URL;\r\n\r\nif (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {\r\n /*global URL:true */\r\n URL = webkitURL;\r\n}\r\n\r\nif (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?\r\n if (typeof navigator.webkitGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.webkitGetUserMedia;\r\n }\r\n\r\n if (typeof navigator.mozGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.mozGetUserMedia;\r\n }\r\n}\r\n\r\nvar isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveBlob || !!navigator.msSaveOrOpenBlob);\r\nvar isOpera = !!window.opera || navigator.userAgent.indexOf('OPR/') !== -1;\r\nvar isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 && ('netscape' in window) && / rv:/.test(navigator.userAgent);\r\nvar isChrome = (!isOpera && !isEdge && !!navigator.webkitGetUserMedia) || isElectron() || navigator.userAgent.toLowerCase().indexOf('chrome/') !== -1;\r\n\r\nvar isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\r\n\r\nif (isSafari && !isChrome && navigator.userAgent.indexOf('CriOS') !== -1) {\r\n isSafari = false;\r\n isChrome = true;\r\n}\r\n\r\nvar MediaStream = window.MediaStream;\r\n\r\nif (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {\r\n MediaStream = webkitMediaStream;\r\n}\r\n\r\n/*global MediaStream:true */\r\nif (typeof MediaStream !== 'undefined') {\r\n // override \"stop\" method for all browsers\r\n if (typeof MediaStream.prototype.stop === 'undefined') {\r\n MediaStream.prototype.stop = function() {\r\n this.getTracks().forEach(function(track) {\r\n track.stop();\r\n });\r\n };\r\n }\r\n}\r\n\r\n// below function via: http://goo.gl/B3ae8c\r\n/**\r\n * Return human-readable file size.\r\n * @param {number} bytes - Pass bytes and get formatted string.\r\n * @returns {string} - formatted string\r\n * @example\r\n * bytesToSize(1024*1024*5) === '5 GB'\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction bytesToSize(bytes) {\r\n var k = 1000;\r\n var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\r\n if (bytes === 0) {\r\n return '0 Bytes';\r\n }\r\n var i = parseInt(Math.floor(Math.log(bytes) / Math.log(k)), 10);\r\n return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];\r\n}\r\n\r\n/**\r\n * @param {Blob} file - File or Blob object. This parameter is required.\r\n * @param {string} fileName - Optional file name e.g. \"Recorded-Video.webm\"\r\n * @example\r\n * invokeSaveAsDialog(blob or file, [optional] fileName);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction invokeSaveAsDialog(file, fileName) {\r\n if (!file) {\r\n throw 'Blob object is required.';\r\n }\r\n\r\n if (!file.type) {\r\n try {\r\n file.type = 'video/webm';\r\n } catch (e) {}\r\n }\r\n\r\n var fileExtension = (file.type || 'video/webm').split('/')[1];\r\n if (fileExtension.indexOf(';') !== -1) {\r\n // extended mimetype, e.g. 'video/webm;codecs=vp8,opus'\r\n fileExtension = fileExtension.split(';')[0];\r\n }\r\n if (fileName && fileName.indexOf('.') !== -1) {\r\n var splitted = fileName.split('.');\r\n fileName = splitted[0];\r\n fileExtension = splitted[1];\r\n }\r\n\r\n var fileFullName = (fileName || (Math.round(Math.random() * 9999999999) + 888888888)) + '.' + fileExtension;\r\n\r\n if (typeof navigator.msSaveOrOpenBlob !== 'undefined') {\r\n return navigator.msSaveOrOpenBlob(file, fileFullName);\r\n } else if (typeof navigator.msSaveBlob !== 'undefined') {\r\n return navigator.msSaveBlob(file, fileFullName);\r\n }\r\n\r\n var hyperlink = document.createElement('a');\r\n hyperlink.href = URL.createObjectURL(file);\r\n hyperlink.download = fileFullName;\r\n\r\n hyperlink.style = 'display:none;opacity:0;color:transparent;';\r\n (document.body || document.documentElement).appendChild(hyperlink);\r\n\r\n if (typeof hyperlink.click === 'function') {\r\n hyperlink.click();\r\n } else {\r\n hyperlink.target = '_blank';\r\n hyperlink.dispatchEvent(new MouseEvent('click', {\r\n view: window,\r\n bubbles: true,\r\n cancelable: true\r\n }));\r\n }\r\n\r\n URL.revokeObjectURL(hyperlink.href);\r\n}\r\n\r\n/**\r\n * from: https://github.com/cheton/is-electron/blob/master/index.js\r\n **/\r\nfunction isElectron() {\r\n // Renderer process\r\n if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') {\r\n return true;\r\n }\r\n\r\n // Main process\r\n if (typeof process !== 'undefined' && typeof process.versions === 'object' && !!process.versions.electron) {\r\n return true;\r\n }\r\n\r\n // Detect the user agent when the `nodeIntegration` option is set to true\r\n if (typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent.indexOf('Electron') >= 0) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nfunction getTracks(stream, kind) {\r\n if (!stream || !stream.getTracks) {\r\n return [];\r\n }\r\n\r\n return stream.getTracks().filter(function(t) {\r\n return t.kind === (kind || 'audio');\r\n });\r\n}\r\n\r\nfunction setSrcObject(stream, element) {\r\n if ('srcObject' in element) {\r\n element.srcObject = stream;\r\n } else if ('mozSrcObject' in element) {\r\n element.mozSrcObject = stream;\r\n } else {\r\n element.srcObject = stream;\r\n }\r\n}\r\n\r\n/**\r\n * @param {Blob} file - File or Blob object.\r\n * @param {function} callback - Callback function.\r\n * @example\r\n * getSeekableBlob(blob or file, callback);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\nfunction getSeekableBlob(inputBlob, callback) {\r\n // EBML.js copyrights goes to: https://github.com/legokichi/ts-ebml\r\n if (typeof EBML === 'undefined') {\r\n throw new Error('Please link: https://www.webrtc-experiment.com/EBML.js');\r\n }\r\n\r\n var reader = new EBML.Reader();\r\n var decoder = new EBML.Decoder();\r\n var tools = EBML.tools;\r\n\r\n var fileReader = new FileReader();\r\n fileReader.onload = function(e) {\r\n var ebmlElms = decoder.decode(this.result);\r\n ebmlElms.forEach(function(element) {\r\n reader.read(element);\r\n });\r\n reader.stop();\r\n var refinedMetadataBuf = tools.makeMetadataSeekable(reader.metadatas, reader.duration, reader.cues);\r\n var body = this.result.slice(reader.metadataSize);\r\n var newBlob = new Blob([refinedMetadataBuf, body], {\r\n type: 'video/webm'\r\n });\r\n\r\n callback(newBlob);\r\n };\r\n fileReader.readAsArrayBuffer(inputBlob);\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.invokeSaveAsDialog = invokeSaveAsDialog;\r\n RecordRTC.getTracks = getTracks;\r\n RecordRTC.getSeekableBlob = getSeekableBlob;\r\n RecordRTC.bytesToSize = bytesToSize;\r\n RecordRTC.isElectron = isElectron;\r\n}\r\n\r\n// __________ (used to handle stuff like http://goo.gl/xmE5eg) issue #129\r\n// Storage.js\r\n\r\n/**\r\n * Storage is a standalone object used by {@link RecordRTC} to store reusable objects e.g. \"new AudioContext\".\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @example\r\n * Storage.AudioContext === webkitAudioContext\r\n * @property {webkitAudioContext} AudioContext - Keeps a reference to AudioContext object.\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\nvar Storage = {};\r\n\r\nif (typeof AudioContext !== 'undefined') {\r\n Storage.AudioContext = AudioContext;\r\n} else if (typeof webkitAudioContext !== 'undefined') {\r\n Storage.AudioContext = webkitAudioContext;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.Storage = Storage;\r\n}\n\r\nfunction isMediaRecorderCompatible() {\r\n if (isFirefox || isSafari || isEdge) {\r\n return true;\r\n }\r\n\r\n var nVer = navigator.appVersion;\r\n var nAgt = navigator.userAgent;\r\n var fullVersion = '' + parseFloat(navigator.appVersion);\r\n var majorVersion = parseInt(navigator.appVersion, 10);\r\n var nameOffset, verOffset, ix;\r\n\r\n if (isChrome || isOpera) {\r\n verOffset = nAgt.indexOf('Chrome');\r\n fullVersion = nAgt.substring(verOffset + 7);\r\n }\r\n\r\n // trim the fullVersion string at semicolon/space if present\r\n if ((ix = fullVersion.indexOf(';')) !== -1) {\r\n fullVersion = fullVersion.substring(0, ix);\r\n }\r\n\r\n if ((ix = fullVersion.indexOf(' ')) !== -1) {\r\n fullVersion = fullVersion.substring(0, ix);\r\n }\r\n\r\n majorVersion = parseInt('' + fullVersion, 10);\r\n\r\n if (isNaN(majorVersion)) {\r\n fullVersion = '' + parseFloat(navigator.appVersion);\r\n majorVersion = parseInt(navigator.appVersion, 10);\r\n }\r\n\r\n return majorVersion >= 49;\r\n}\n\r\n// ______________________\r\n// MediaStreamRecorder.js\r\n\r\n/**\r\n * MediaStreamRecorder is an abstraction layer for {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. It is used by {@link RecordRTC} to record MediaStream(s) in both Chrome and Firefox.\r\n * @summary Runs top over {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://github.com/muaz-khan|Muaz Khan}\r\n * @typedef MediaStreamRecorder\r\n * @class\r\n * @example\r\n * var config = {\r\n * mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis\r\n * audioBitsPerSecond : 256 * 8 * 1024,\r\n * videoBitsPerSecond : 256 * 8 * 1024,\r\n * bitsPerSecond: 256 * 8 * 1024, // if this is provided, skip above two\r\n * checkForInactiveTracks: true,\r\n * timeSlice: 1000, // concatenate intervals based blobs\r\n * ondataavailable: function() {} // get intervals based blobs\r\n * }\r\n * var recorder = new MediaStreamRecorder(mediaStream, config);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n *\r\n * // or\r\n * var blob = recorder.blob;\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {disableLogs:true, initCallback: function, mimeType: \"video/webm\", timeSlice: 1000}\r\n * @throws Will throw an error if first argument \"MediaStream\" is missing. Also throws error if \"MediaRecorder API\" are not supported by the browser.\r\n */\r\n\r\nfunction MediaStreamRecorder(mediaStream, config) {\r\n var self = this;\r\n\r\n if (typeof mediaStream === 'undefined') {\r\n throw 'First argument \"MediaStream\" is required.';\r\n }\r\n\r\n if (typeof MediaRecorder === 'undefined') {\r\n throw 'Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.';\r\n }\r\n\r\n config = config || {\r\n // bitsPerSecond: 256 * 8 * 1024,\r\n mimeType: 'video/webm'\r\n };\r\n\r\n if (config.type === 'audio') {\r\n if (getTracks(mediaStream, 'video').length && getTracks(mediaStream, 'audio').length) {\r\n var stream;\r\n if (!!navigator.mozGetUserMedia) {\r\n stream = new MediaStream();\r\n stream.addTrack(getTracks(mediaStream, 'audio')[0]);\r\n } else {\r\n // webkitMediaStream\r\n stream = new MediaStream(getTracks(mediaStream, 'audio'));\r\n }\r\n mediaStream = stream;\r\n }\r\n\r\n if (!config.mimeType || config.mimeType.toString().toLowerCase().indexOf('audio') === -1) {\r\n config.mimeType = isChrome ? 'audio/webm' : 'audio/ogg';\r\n }\r\n\r\n if (config.mimeType && config.mimeType.toString().toLowerCase() !== 'audio/ogg' && !!navigator.mozGetUserMedia) {\r\n // forcing better codecs on Firefox (via #166)\r\n config.mimeType = 'audio/ogg';\r\n }\r\n }\r\n\r\n var arrayOfBlobs = [];\r\n\r\n /**\r\n * This method returns array of blobs. Use only with \"timeSlice\". Its useful to preview recording anytime, without using the \"stop\" method.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var arrayOfBlobs = recorder.getArrayOfBlobs();\r\n * @returns {Array} Returns array of recorded blobs.\r\n */\r\n this.getArrayOfBlobs = function() {\r\n return arrayOfBlobs;\r\n };\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n // set defaults\r\n self.blob = null;\r\n self.clearRecordedData();\r\n self.timestamps = [];\r\n allStates = [];\r\n arrayOfBlobs = [];\r\n\r\n var recorderHints = config;\r\n\r\n if (!config.disableLogs) {\r\n console.log('Passing following config over MediaRecorder API.', recorderHints);\r\n }\r\n\r\n if (mediaRecorder) {\r\n // mandatory to make sure Firefox doesn't fails to record streams 3-4 times without reloading the page.\r\n mediaRecorder = null;\r\n }\r\n\r\n if (isChrome && !isMediaRecorderCompatible()) {\r\n // to support video-only recording on stable\r\n recorderHints = 'video/vp8';\r\n }\r\n\r\n if (typeof MediaRecorder.isTypeSupported === 'function' && recorderHints.mimeType) {\r\n if (!MediaRecorder.isTypeSupported(recorderHints.mimeType)) {\r\n if (!config.disableLogs) {\r\n console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType);\r\n }\r\n\r\n recorderHints.mimeType = config.type === 'audio' ? 'audio/webm' : 'video/webm';\r\n }\r\n }\r\n\r\n // using MediaRecorder API here\r\n try {\r\n mediaRecorder = new MediaRecorder(mediaStream, recorderHints);\r\n\r\n // reset\r\n config.mimeType = recorderHints.mimeType;\r\n } catch (e) {\r\n // chrome-based fallback\r\n mediaRecorder = new MediaRecorder(mediaStream);\r\n }\r\n\r\n // old hack?\r\n if (recorderHints.mimeType && !MediaRecorder.isTypeSupported && 'canRecordMimeType' in mediaRecorder && mediaRecorder.canRecordMimeType(recorderHints.mimeType) === false) {\r\n if (!config.disableLogs) {\r\n console.warn('MediaRecorder API seems unable to record mimeType:', recorderHints.mimeType);\r\n }\r\n }\r\n\r\n // Dispatching OnDataAvailable Handler\r\n mediaRecorder.ondataavailable = function(e) {\r\n if (e.data) {\r\n allStates.push('ondataavailable: ' + bytesToSize(e.data.size));\r\n }\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n if (e.data && e.data.size) {\r\n arrayOfBlobs.push(e.data);\r\n updateTimeStamp();\r\n\r\n if (typeof config.ondataavailable === 'function') {\r\n // intervals based blobs\r\n var blob = config.getNativeBlob ? e.data : new Blob([e.data], {\r\n type: getMimeType(recorderHints)\r\n });\r\n config.ondataavailable(blob);\r\n }\r\n }\r\n return;\r\n }\r\n\r\n if (!e.data || !e.data.size || e.data.size < 100 || self.blob) {\r\n // make sure that stopRecording always getting fired\r\n // even if there is invalid data\r\n if (self.recordingCallback) {\r\n self.recordingCallback(new Blob([], {\r\n type: getMimeType(recorderHints)\r\n }));\r\n self.recordingCallback = null;\r\n }\r\n return;\r\n }\r\n\r\n self.blob = config.getNativeBlob ? e.data : new Blob([e.data], {\r\n type: getMimeType(recorderHints)\r\n });\r\n\r\n if (self.recordingCallback) {\r\n self.recordingCallback(self.blob);\r\n self.recordingCallback = null;\r\n }\r\n };\r\n\r\n mediaRecorder.onstart = function() {\r\n allStates.push('started');\r\n };\r\n\r\n mediaRecorder.onpause = function() {\r\n allStates.push('paused');\r\n };\r\n\r\n mediaRecorder.onresume = function() {\r\n allStates.push('resumed');\r\n };\r\n\r\n mediaRecorder.onstop = function() {\r\n allStates.push('stopped');\r\n };\r\n\r\n mediaRecorder.onerror = function(error) {\r\n if (!error) {\r\n return;\r\n }\r\n\r\n if (!error.name) {\r\n error.name = 'UnknownError';\r\n }\r\n\r\n allStates.push('error: ' + error);\r\n\r\n if (!config.disableLogs) {\r\n // via: https://w3c.github.io/mediacapture-record/MediaRecorder.html#exception-summary\r\n if (error.name.toString().toLowerCase().indexOf('invalidstate') !== -1) {\r\n console.error('The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.', error);\r\n } else if (error.name.toString().toLowerCase().indexOf('notsupported') !== -1) {\r\n console.error('MIME type (', recorderHints.mimeType, ') is not supported.', error);\r\n } else if (error.name.toString().toLowerCase().indexOf('security') !== -1) {\r\n console.error('MediaRecorder security error', error);\r\n }\r\n\r\n // older code below\r\n else if (error.name === 'OutOfMemory') {\r\n console.error('The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'IllegalStreamModification') {\r\n console.error('A modification to the stream has occurred that makes it impossible to continue recording. An example would be the addition of a Track while recording is occurring. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'OtherRecordingError') {\r\n console.error('Used for an fatal error other than those listed above. User agents SHOULD provide as much additional information as possible in the message attribute.', error);\r\n } else if (error.name === 'GenericError') {\r\n console.error('The UA cannot provide the codec or recording option that has been requested.', error);\r\n } else {\r\n console.error('MediaRecorder Error', error);\r\n }\r\n }\r\n\r\n (function(looper) {\r\n if (!self.manuallyStopped && mediaRecorder && mediaRecorder.state === 'inactive') {\r\n delete config.timeslice;\r\n\r\n // 10 minutes, enough?\r\n mediaRecorder.start(10 * 60 * 1000);\r\n return;\r\n }\r\n\r\n setTimeout(looper, 1000);\r\n })();\r\n\r\n if (mediaRecorder.state !== 'inactive' && mediaRecorder.state !== 'stopped') {\r\n mediaRecorder.stop();\r\n }\r\n };\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n updateTimeStamp();\r\n mediaRecorder.start(config.timeSlice);\r\n } else {\r\n // default is 60 minutes; enough?\r\n // use config => {timeSlice: 1000} otherwise\r\n\r\n mediaRecorder.start(3.6e+6);\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback(); // old code\r\n }\r\n };\r\n\r\n /**\r\n * @property {Array} timestamps - Array of time stamps\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * console.log(recorder.timestamps);\r\n */\r\n this.timestamps = [];\r\n\r\n function updateTimeStamp() {\r\n self.timestamps.push(new Date().getTime());\r\n\r\n if (typeof config.onTimeStamp === 'function') {\r\n config.onTimeStamp(self.timestamps[self.timestamps.length - 1], self.timestamps);\r\n }\r\n }\r\n\r\n function getMimeType(secondObject) {\r\n if (mediaRecorder && mediaRecorder.mimeType) {\r\n return mediaRecorder.mimeType;\r\n }\r\n\r\n return secondObject.mimeType || 'video/webm';\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n self.manuallyStopped = true; // used inside the mediaRecorder.onerror\r\n\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n this.recordingCallback = callback;\r\n\r\n if (mediaRecorder.state === 'recording') {\r\n mediaRecorder.stop();\r\n }\r\n\r\n if (typeof config.timeSlice === 'number') {\r\n setTimeout(function() {\r\n self.blob = new Blob(arrayOfBlobs, {\r\n type: getMimeType(config)\r\n });\r\n\r\n self.recordingCallback(self.blob);\r\n }, 100);\r\n }\r\n };\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n if (mediaRecorder.state === 'recording') {\r\n mediaRecorder.pause();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n if (mediaRecorder.state === 'paused') {\r\n mediaRecorder.resume();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (mediaRecorder && mediaRecorder.state === 'recording') {\r\n self.stop(clearRecordedDataCB);\r\n }\r\n\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n arrayOfBlobs = [];\r\n mediaRecorder = null;\r\n self.timestamps = [];\r\n }\r\n\r\n // Reference to \"MediaRecorder\" object\r\n var mediaRecorder;\r\n\r\n /**\r\n * Access to native MediaRecorder API\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @instance\r\n * @example\r\n * var internal = recorder.getInternalRecorder();\r\n * internal.ondataavailable = function() {}; // override\r\n * internal.stream, internal.onpause, internal.onstop, etc.\r\n * @returns {Object} Returns internal recording object.\r\n */\r\n this.getInternalRecorder = function() {\r\n return mediaRecorder;\r\n };\r\n\r\n function isMediaStreamActive() {\r\n if ('active' in mediaStream) {\r\n if (!mediaStream.active) {\r\n return false;\r\n }\r\n } else if ('ended' in mediaStream) { // old hack\r\n if (mediaStream.ended) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * @property {Blob} blob - Recorded data as \"Blob\" object.\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = null;\r\n\r\n\r\n /**\r\n * Get MediaRecorder readonly state.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var state = recorder.getState();\r\n * @returns {String} Returns recording state.\r\n */\r\n this.getState = function() {\r\n if (!mediaRecorder) {\r\n return 'inactive';\r\n }\r\n\r\n return mediaRecorder.state || 'inactive';\r\n };\r\n\r\n // list of all recording states\r\n var allStates = [];\r\n\r\n /**\r\n * Get MediaRecorder all recording states.\r\n * @method\r\n * @memberof MediaStreamRecorder\r\n * @example\r\n * var state = recorder.getAllStates();\r\n * @returns {Array} Returns all recording states\r\n */\r\n this.getAllStates = function() {\r\n return allStates;\r\n };\r\n\r\n // if any Track within the MediaStream is muted or not enabled at any time, \r\n // the browser will only record black frames \r\n // or silence since that is the content produced by the Track\r\n // so we need to stopRecording as soon as any single track ends.\r\n if (typeof config.checkForInactiveTracks === 'undefined') {\r\n config.checkForInactiveTracks = false; // disable to minimize CPU usage\r\n }\r\n\r\n var self = this;\r\n\r\n // this method checks if media stream is stopped\r\n // or if any track is ended.\r\n (function looper() {\r\n if (!mediaRecorder || config.checkForInactiveTracks === false) {\r\n return;\r\n }\r\n\r\n if (isMediaStreamActive() === false) {\r\n if (!config.disableLogs) {\r\n console.log('MediaStream seems stopped.');\r\n }\r\n self.stop();\r\n return;\r\n }\r\n\r\n setTimeout(looper, 1000); // check every second\r\n })();\r\n\r\n // for debugging\r\n this.name = 'MediaStreamRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MediaStreamRecorder = MediaStreamRecorder;\r\n}\r\n\r\n// source code from: http://typedarray.org/wp-content/projects/WebAudioRecorder/script.js\r\n// https://github.com/mattdiamond/Recorderjs#license-mit\r\n// ______________________\r\n// StereoAudioRecorder.js\r\n\r\n/**\r\n * StereoAudioRecorder is a standalone class used by {@link RecordRTC} to bring \"stereo\" audio-recording in chrome.\r\n * @summary JavaScript standalone object for stereo audio recording.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef StereoAudioRecorder\r\n * @class\r\n * @example\r\n * var recorder = new StereoAudioRecorder(MediaStream, {\r\n * sampleRate: 44100,\r\n * bufferSize: 4096\r\n * });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {sampleRate: 44100, bufferSize: 4096, numberOfAudioChannels: 1, etc.}\r\n */\r\n\r\nfunction StereoAudioRecorder(mediaStream, config) {\r\n if (!getTracks(mediaStream, 'audio').length) {\r\n throw 'Your stream has no audio tracks.';\r\n }\r\n\r\n config = config || {};\r\n\r\n var self = this;\r\n\r\n // variables\r\n var leftchannel = [];\r\n var rightchannel = [];\r\n var recording = false;\r\n var recordingLength = 0;\r\n var jsAudioNode;\r\n\r\n var numberOfAudioChannels = 2;\r\n\r\n /**\r\n * Set sample rates such as 8K or 16K. Reference: http://stackoverflow.com/a/28977136/552182\r\n * @property {number} desiredSampRate - Desired Bits per sample * 1000\r\n * @memberof StereoAudioRecorder\r\n * @instance\r\n * @example\r\n * var recorder = StereoAudioRecorder(mediaStream, {\r\n * desiredSampRate: 16 * 1000 // bits-per-sample * 1000\r\n * });\r\n */\r\n var desiredSampRate = config.desiredSampRate;\r\n\r\n // backward compatibility\r\n if (config.leftChannel === true) {\r\n numberOfAudioChannels = 1;\r\n }\r\n\r\n if (config.numberOfAudioChannels === 1) {\r\n numberOfAudioChannels = 1;\r\n }\r\n\r\n if (!numberOfAudioChannels || numberOfAudioChannels < 1) {\r\n numberOfAudioChannels = 2;\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('StereoAudioRecorder is set to record number of channels: ' + numberOfAudioChannels);\r\n }\r\n\r\n // if any Track within the MediaStream is muted or not enabled at any time, \r\n // the browser will only record black frames \r\n // or silence since that is the content produced by the Track\r\n // so we need to stopRecording as soon as any single track ends.\r\n if (typeof config.checkForInactiveTracks === 'undefined') {\r\n config.checkForInactiveTracks = true;\r\n }\r\n\r\n function isMediaStreamActive() {\r\n if (config.checkForInactiveTracks === false) {\r\n // always return \"true\"\r\n return true;\r\n }\r\n\r\n if ('active' in mediaStream) {\r\n if (!mediaStream.active) {\r\n return false;\r\n }\r\n } else if ('ended' in mediaStream) { // old hack\r\n if (mediaStream.ended) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (isMediaStreamActive() === false) {\r\n throw 'Please make sure MediaStream is active.';\r\n }\r\n\r\n resetVariables();\r\n\r\n isAudioProcessStarted = isPaused = false;\r\n recording = true;\r\n\r\n if (typeof config.timeSlice !== 'undefined') {\r\n looper();\r\n }\r\n };\r\n\r\n function mergeLeftRightBuffers(config, callback) {\r\n function mergeAudioBuffers(config, cb) {\r\n var numberOfAudioChannels = config.numberOfAudioChannels;\r\n\r\n // todo: \"slice(0)\" --- is it causes loop? Should be removed?\r\n var leftBuffers = config.leftBuffers.slice(0);\r\n var rightBuffers = config.rightBuffers.slice(0);\r\n var sampleRate = config.sampleRate;\r\n var internalInterleavedLength = config.internalInterleavedLength;\r\n var desiredSampRate = config.desiredSampRate;\r\n\r\n if (numberOfAudioChannels === 2) {\r\n leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);\r\n rightBuffers = mergeBuffers(rightBuffers, internalInterleavedLength);\r\n\r\n if (desiredSampRate) {\r\n leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate);\r\n rightBuffers = interpolateArray(rightBuffers, desiredSampRate, sampleRate);\r\n }\r\n }\r\n\r\n if (numberOfAudioChannels === 1) {\r\n leftBuffers = mergeBuffers(leftBuffers, internalInterleavedLength);\r\n\r\n if (desiredSampRate) {\r\n leftBuffers = interpolateArray(leftBuffers, desiredSampRate, sampleRate);\r\n }\r\n }\r\n\r\n // set sample rate as desired sample rate\r\n if (desiredSampRate) {\r\n sampleRate = desiredSampRate;\r\n }\r\n\r\n // for changing the sampling rate, reference:\r\n // http://stackoverflow.com/a/28977136/552182\r\n function interpolateArray(data, newSampleRate, oldSampleRate) {\r\n var fitCount = Math.round(data.length * (newSampleRate / oldSampleRate));\r\n var newData = [];\r\n var springFactor = Number((data.length - 1) / (fitCount - 1));\r\n newData[0] = data[0];\r\n for (var i = 1; i < fitCount - 1; i++) {\r\n var tmp = i * springFactor;\r\n var before = Number(Math.floor(tmp)).toFixed();\r\n var after = Number(Math.ceil(tmp)).toFixed();\r\n var atPoint = tmp - before;\r\n newData[i] = linearInterpolate(data[before], data[after], atPoint);\r\n }\r\n newData[fitCount - 1] = data[data.length - 1];\r\n return newData;\r\n }\r\n\r\n function linearInterpolate(before, after, atPoint) {\r\n return before + (after - before) * atPoint;\r\n }\r\n\r\n function mergeBuffers(channelBuffer, rLength) {\r\n var result = new Float64Array(rLength);\r\n var offset = 0;\r\n var lng = channelBuffer.length;\r\n\r\n for (var i = 0; i < lng; i++) {\r\n var buffer = channelBuffer[i];\r\n result.set(buffer, offset);\r\n offset += buffer.length;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n function interleave(leftChannel, rightChannel) {\r\n var length = leftChannel.length + rightChannel.length;\r\n\r\n var result = new Float64Array(length);\r\n\r\n var inputIndex = 0;\r\n\r\n for (var index = 0; index < length;) {\r\n result[index++] = leftChannel[inputIndex];\r\n result[index++] = rightChannel[inputIndex];\r\n inputIndex++;\r\n }\r\n return result;\r\n }\r\n\r\n function writeUTFBytes(view, offset, string) {\r\n var lng = string.length;\r\n for (var i = 0; i < lng; i++) {\r\n view.setUint8(offset + i, string.charCodeAt(i));\r\n }\r\n }\r\n\r\n // interleave both channels together\r\n var interleaved;\r\n\r\n if (numberOfAudioChannels === 2) {\r\n interleaved = interleave(leftBuffers, rightBuffers);\r\n }\r\n\r\n if (numberOfAudioChannels === 1) {\r\n interleaved = leftBuffers;\r\n }\r\n\r\n var interleavedLength = interleaved.length;\r\n\r\n // create wav file\r\n var resultingBufferLength = 44 + interleavedLength * 2;\r\n\r\n var buffer = new ArrayBuffer(resultingBufferLength);\r\n\r\n var view = new DataView(buffer);\r\n\r\n // RIFF chunk descriptor/identifier \r\n writeUTFBytes(view, 0, 'RIFF');\r\n\r\n // RIFF chunk length\r\n // changed \"44\" to \"36\" via #401\r\n view.setUint32(4, 36 + interleavedLength * 2, true);\r\n\r\n // RIFF type \r\n writeUTFBytes(view, 8, 'WAVE');\r\n\r\n // format chunk identifier \r\n // FMT sub-chunk\r\n writeUTFBytes(view, 12, 'fmt ');\r\n\r\n // format chunk length \r\n view.setUint32(16, 16, true);\r\n\r\n // sample format (raw)\r\n view.setUint16(20, 1, true);\r\n\r\n // stereo (2 channels)\r\n view.setUint16(22, numberOfAudioChannels, true);\r\n\r\n // sample rate \r\n view.setUint32(24, sampleRate, true);\r\n\r\n // byte rate (sample rate * block align)\r\n view.setUint32(28, sampleRate * numberOfAudioChannels * 2, true);\r\n\r\n // block align (channel count * bytes per sample) \r\n view.setUint16(32, numberOfAudioChannels * 2, true);\r\n\r\n // bits per sample \r\n view.setUint16(34, 16, true);\r\n\r\n // data sub-chunk\r\n // data chunk identifier \r\n writeUTFBytes(view, 36, 'data');\r\n\r\n // data chunk length \r\n view.setUint32(40, interleavedLength * 2, true);\r\n\r\n // write the PCM samples\r\n var lng = interleavedLength;\r\n var index = 44;\r\n var volume = 1;\r\n for (var i = 0; i < lng; i++) {\r\n view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);\r\n index += 2;\r\n }\r\n\r\n if (cb) {\r\n return cb({\r\n buffer: buffer,\r\n view: view\r\n });\r\n }\r\n\r\n postMessage({\r\n buffer: buffer,\r\n view: view\r\n });\r\n }\r\n\r\n if (config.noWorker) {\r\n mergeAudioBuffers(config, function(data) {\r\n callback(data.buffer, data.view);\r\n });\r\n return;\r\n }\r\n\r\n\r\n var webWorker = processInWebWorker(mergeAudioBuffers);\r\n\r\n webWorker.onmessage = function(event) {\r\n callback(event.data.buffer, event.data.view);\r\n\r\n // release memory\r\n URL.revokeObjectURL(webWorker.workerURL);\r\n\r\n // kill webworker (or Chrome will kill your page after ~25 calls)\r\n webWorker.terminate();\r\n };\r\n\r\n webWorker.postMessage(config);\r\n }\r\n\r\n function processInWebWorker(_function) {\r\n var workerURL = URL.createObjectURL(new Blob([_function.toString(),\r\n ';this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(workerURL);\r\n worker.workerURL = workerURL;\r\n return worker;\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n // stop recording\r\n recording = false;\r\n\r\n mergeLeftRightBuffers({\r\n desiredSampRate: desiredSampRate,\r\n sampleRate: sampleRate,\r\n numberOfAudioChannels: numberOfAudioChannels,\r\n internalInterleavedLength: recordingLength,\r\n leftBuffers: leftchannel,\r\n rightBuffers: numberOfAudioChannels === 1 ? [] : rightchannel,\r\n noWorker: config.noWorker\r\n }, function(buffer, view) {\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n self.blob = new Blob([view], {\r\n type: 'audio/wav'\r\n });\r\n\r\n /**\r\n * @property {ArrayBuffer} buffer - The recorded buffer object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var buffer = recorder.buffer;\r\n * });\r\n */\r\n self.buffer = new ArrayBuffer(view.buffer.byteLength);\r\n\r\n /**\r\n * @property {DataView} view - The recorded data-view object.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var view = recorder.view;\r\n * });\r\n */\r\n self.view = view;\r\n\r\n self.sampleRate = desiredSampRate || sampleRate;\r\n self.bufferSize = bufferSize;\r\n\r\n // recorded audio length\r\n self.length = recordingLength;\r\n\r\n isAudioProcessStarted = false;\r\n\r\n if (callback) {\r\n callback(self.blob);\r\n }\r\n });\r\n };\r\n\r\n if (typeof RecordRTC.Storage === 'undefined') {\r\n RecordRTC.Storage = {\r\n AudioContextConstructor: null,\r\n AudioContext: window.AudioContext || window.webkitAudioContext\r\n };\r\n }\r\n\r\n if (!RecordRTC.Storage.AudioContextConstructor || RecordRTC.Storage.AudioContextConstructor.state === 'closed') {\r\n RecordRTC.Storage.AudioContextConstructor = new RecordRTC.Storage.AudioContext();\r\n }\r\n\r\n var context = RecordRTC.Storage.AudioContextConstructor;\r\n\r\n // creates an audio node from the microphone incoming stream\r\n var audioInput = context.createMediaStreamSource(mediaStream);\r\n\r\n var legalBufferValues = [0, 256, 512, 1024, 2048, 4096, 8192, 16384];\r\n\r\n /**\r\n * From the spec: This value controls how frequently the audioprocess event is\r\n * dispatched and how many sample-frames need to be processed each call.\r\n * Lower values for buffer size will result in a lower (better) latency.\r\n * Higher values will be necessary to avoid audio breakup and glitches\r\n * The size of the buffer (in sample-frames) which needs to\r\n * be processed each time onprocessaudio is called.\r\n * Legal values are (256, 512, 1024, 2048, 4096, 8192, 16384).\r\n * @property {number} bufferSize - Buffer-size for how frequently the audioprocess event is dispatched.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder = new StereoAudioRecorder(mediaStream, {\r\n * bufferSize: 4096\r\n * });\r\n */\r\n\r\n // \"0\" means, let chrome decide the most accurate buffer-size for current platform.\r\n var bufferSize = typeof config.bufferSize === 'undefined' ? 4096 : config.bufferSize;\r\n\r\n if (legalBufferValues.indexOf(bufferSize) === -1) {\r\n if (!config.disableLogs) {\r\n console.log('Legal values for buffer-size are ' + JSON.stringify(legalBufferValues, null, '\\t'));\r\n }\r\n }\r\n\r\n if (context.createJavaScriptNode) {\r\n jsAudioNode = context.createJavaScriptNode(bufferSize, numberOfAudioChannels, numberOfAudioChannels);\r\n } else if (context.createScriptProcessor) {\r\n jsAudioNode = context.createScriptProcessor(bufferSize, numberOfAudioChannels, numberOfAudioChannels);\r\n } else {\r\n throw 'WebAudio API has no support on this browser.';\r\n }\r\n\r\n // connect the stream to the script processor\r\n audioInput.connect(jsAudioNode);\r\n\r\n if (!config.bufferSize) {\r\n bufferSize = jsAudioNode.bufferSize; // device buffer-size\r\n }\r\n\r\n /**\r\n * The sample rate (in sample-frames per second) at which the\r\n * AudioContext handles audio. It is assumed that all AudioNodes\r\n * in the context run at this rate. In making this assumption,\r\n * sample-rate converters or \"varispeed\" processors are not supported\r\n * in real-time processing.\r\n * The sampleRate parameter describes the sample-rate of the\r\n * linear PCM audio data in the buffer in sample-frames per second.\r\n * An implementation must support sample-rates in at least\r\n * the range 22050 to 96000.\r\n * @property {number} sampleRate - Buffer-size for how frequently the audioprocess event is dispatched.\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder = new StereoAudioRecorder(mediaStream, {\r\n * sampleRate: 44100\r\n * });\r\n */\r\n var sampleRate = typeof config.sampleRate !== 'undefined' ? config.sampleRate : context.sampleRate || 44100;\r\n\r\n if (sampleRate < 22050 || sampleRate > 96000) {\r\n // Ref: http://stackoverflow.com/a/26303918/552182\r\n if (!config.disableLogs) {\r\n console.log('sample-rate must be under range 22050 and 96000.');\r\n }\r\n }\r\n\r\n if (!config.disableLogs) {\r\n if (config.desiredSampRate) {\r\n console.log('Desired sample-rate: ' + config.desiredSampRate);\r\n }\r\n }\r\n\r\n var isPaused = false;\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPaused = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (isMediaStreamActive() === false) {\r\n throw 'Please make sure MediaStream is active.';\r\n }\r\n\r\n if (!recording) {\r\n if (!config.disableLogs) {\r\n console.log('Seems recording has been restarted.');\r\n }\r\n this.record();\r\n return;\r\n }\r\n\r\n isPaused = false;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n config.checkForInactiveTracks = false;\r\n\r\n if (recording) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n\r\n clearRecordedDataCB();\r\n };\r\n\r\n function resetVariables() {\r\n leftchannel = [];\r\n rightchannel = [];\r\n recordingLength = 0;\r\n isAudioProcessStarted = false;\r\n recording = false;\r\n isPaused = false;\r\n context = null;\r\n\r\n self.leftchannel = leftchannel;\r\n self.rightchannel = rightchannel;\r\n self.numberOfAudioChannels = numberOfAudioChannels;\r\n self.desiredSampRate = desiredSampRate;\r\n self.sampleRate = sampleRate;\r\n self.recordingLength = recordingLength;\r\n\r\n intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n }\r\n\r\n function clearRecordedDataCB() {\r\n if (jsAudioNode) {\r\n jsAudioNode.onaudioprocess = null;\r\n jsAudioNode.disconnect();\r\n jsAudioNode = null;\r\n }\r\n\r\n if (audioInput) {\r\n audioInput.disconnect();\r\n audioInput = null;\r\n }\r\n\r\n resetVariables();\r\n }\r\n\r\n // for debugging\r\n this.name = 'StereoAudioRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var isAudioProcessStarted = false;\r\n\r\n function onAudioProcessDataAvailable(e) {\r\n if (isPaused) {\r\n return;\r\n }\r\n\r\n if (isMediaStreamActive() === false) {\r\n if (!config.disableLogs) {\r\n console.log('MediaStream seems stopped.');\r\n }\r\n jsAudioNode.disconnect();\r\n recording = false;\r\n }\r\n\r\n if (!recording) {\r\n if (audioInput) {\r\n audioInput.disconnect();\r\n audioInput = null;\r\n }\r\n return;\r\n }\r\n\r\n /**\r\n * This method is called on \"onaudioprocess\" event's first invocation.\r\n * @method {function} onAudioProcessStarted\r\n * @memberof StereoAudioRecorder\r\n * @example\r\n * recorder.onAudioProcessStarted: function() { };\r\n */\r\n if (!isAudioProcessStarted) {\r\n isAudioProcessStarted = true;\r\n if (config.onAudioProcessStarted) {\r\n config.onAudioProcessStarted();\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n }\r\n\r\n var left = e.inputBuffer.getChannelData(0);\r\n\r\n // we clone the samples\r\n var chLeft = new Float32Array(left);\r\n leftchannel.push(chLeft);\r\n\r\n if (numberOfAudioChannels === 2) {\r\n var right = e.inputBuffer.getChannelData(1);\r\n var chRight = new Float32Array(right);\r\n rightchannel.push(chRight);\r\n }\r\n\r\n recordingLength += bufferSize;\r\n\r\n // export raw PCM\r\n self.recordingLength = recordingLength;\r\n\r\n if (typeof config.timeSlice !== 'undefined') {\r\n intervalsBasedBuffers.recordingLength += bufferSize;\r\n intervalsBasedBuffers.left.push(chLeft);\r\n\r\n if (numberOfAudioChannels === 2) {\r\n intervalsBasedBuffers.right.push(chRight);\r\n }\r\n }\r\n }\r\n\r\n jsAudioNode.onaudioprocess = onAudioProcessDataAvailable;\r\n\r\n // to prevent self audio to be connected with speakers\r\n if (context.createMediaStreamDestination) {\r\n jsAudioNode.connect(context.createMediaStreamDestination());\r\n } else {\r\n jsAudioNode.connect(context.destination);\r\n }\r\n\r\n // export raw PCM\r\n this.leftchannel = leftchannel;\r\n this.rightchannel = rightchannel;\r\n this.numberOfAudioChannels = numberOfAudioChannels;\r\n this.desiredSampRate = desiredSampRate;\r\n this.sampleRate = sampleRate;\r\n self.recordingLength = recordingLength;\r\n\r\n // helper for intervals based blobs\r\n var intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n\r\n // this looper is used to support intervals based blobs (via timeSlice+ondataavailable)\r\n function looper() {\r\n if (!recording || typeof config.ondataavailable !== 'function' || typeof config.timeSlice === 'undefined') {\r\n return;\r\n }\r\n\r\n if (intervalsBasedBuffers.left.length) {\r\n mergeLeftRightBuffers({\r\n desiredSampRate: desiredSampRate,\r\n sampleRate: sampleRate,\r\n numberOfAudioChannels: numberOfAudioChannels,\r\n internalInterleavedLength: intervalsBasedBuffers.recordingLength,\r\n leftBuffers: intervalsBasedBuffers.left,\r\n rightBuffers: numberOfAudioChannels === 1 ? [] : intervalsBasedBuffers.right\r\n }, function(buffer, view) {\r\n var blob = new Blob([view], {\r\n type: 'audio/wav'\r\n });\r\n config.ondataavailable(blob);\r\n\r\n setTimeout(looper, config.timeSlice);\r\n });\r\n\r\n intervalsBasedBuffers = {\r\n left: [],\r\n right: [],\r\n recordingLength: 0\r\n };\r\n } else {\r\n setTimeout(looper, config.timeSlice);\r\n }\r\n }\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.StereoAudioRecorder = StereoAudioRecorder;\r\n}\r\n\r\n// _________________\r\n// CanvasRecorder.js\r\n\r\n/**\r\n * CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}.\r\n * @summary HTML2Canvas recording into video WebM.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef CanvasRecorder\r\n * @class\r\n * @example\r\n * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc.\r\n * @param {object} config - {disableLogs:true, initCallback: function}\r\n */\r\n\r\nfunction CanvasRecorder(htmlElement, config) {\r\n if (typeof html2canvas === 'undefined') {\r\n throw 'Please link: https://www.webrtc-experiment.com/screenshot.js';\r\n }\r\n\r\n config = config || {};\r\n if (!config.frameInterval) {\r\n config.frameInterval = 10;\r\n }\r\n\r\n // via DetectRTC.js\r\n var isCanvasSupportsStreamCapturing = false;\r\n ['captureStream', 'mozCaptureStream', 'webkitCaptureStream'].forEach(function(item) {\r\n if (item in document.createElement('canvas')) {\r\n isCanvasSupportsStreamCapturing = true;\r\n }\r\n });\r\n\r\n var _isChrome = (!!window.webkitRTCPeerConnection || !!window.webkitGetUserMedia) && !!window.chrome;\r\n\r\n var chromeVersion = 50;\r\n var matchArray = navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\r\n if (_isChrome && matchArray && matchArray[2]) {\r\n chromeVersion = parseInt(matchArray[2], 10);\r\n }\r\n\r\n if (_isChrome && chromeVersion < 52) {\r\n isCanvasSupportsStreamCapturing = false;\r\n }\r\n\r\n if (config.useWhammyRecorder) {\r\n isCanvasSupportsStreamCapturing = false;\r\n }\r\n\r\n var globalCanvas, mediaStreamRecorder;\r\n\r\n if (isCanvasSupportsStreamCapturing) {\r\n if (!config.disableLogs) {\r\n console.log('Your browser supports both MediRecorder API and canvas.captureStream!');\r\n }\r\n\r\n if (htmlElement instanceof HTMLCanvasElement) {\r\n globalCanvas = htmlElement;\r\n } else if (htmlElement instanceof CanvasRenderingContext2D) {\r\n globalCanvas = htmlElement.canvas;\r\n } else {\r\n throw 'Please pass either HTMLCanvasElement or CanvasRenderingContext2D.';\r\n }\r\n } else if (!!navigator.mozGetUserMedia) {\r\n if (!config.disableLogs) {\r\n console.error('Canvas recording is NOT supported in Firefox.');\r\n }\r\n }\r\n\r\n var isRecording;\r\n\r\n /**\r\n * This method records Canvas.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n isRecording = true;\r\n\r\n if (isCanvasSupportsStreamCapturing && !config.useWhammyRecorder) {\r\n // CanvasCaptureMediaStream\r\n var canvasMediaStream;\r\n if ('captureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.captureStream(25); // 25 FPS\r\n } else if ('mozCaptureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.mozCaptureStream(25);\r\n } else if ('webkitCaptureStream' in globalCanvas) {\r\n canvasMediaStream = globalCanvas.webkitCaptureStream(25);\r\n }\r\n\r\n try {\r\n var mdStream = new MediaStream();\r\n mdStream.addTrack(getTracks(canvasMediaStream, 'video')[0]);\r\n canvasMediaStream = mdStream;\r\n } catch (e) {}\r\n\r\n if (!canvasMediaStream) {\r\n throw 'captureStream API are NOT available.';\r\n }\r\n\r\n // Note: Jan 18, 2016 status is that, \r\n // Firefox MediaRecorder API can't record CanvasCaptureMediaStream object.\r\n mediaStreamRecorder = new MediaStreamRecorder(canvasMediaStream, {\r\n mimeType: config.mimeType || 'video/webm'\r\n });\r\n mediaStreamRecorder.record();\r\n } else {\r\n whammy.frames = [];\r\n lastTime = new Date().getTime();\r\n drawCanvasFrame();\r\n }\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n this.getWebPImages = function(callback) {\r\n if (htmlElement.nodeName.toLowerCase() !== 'canvas') {\r\n callback();\r\n return;\r\n }\r\n\r\n var framesLength = whammy.frames.length;\r\n whammy.frames.forEach(function(frame, idx) {\r\n var framesRemaining = framesLength - idx;\r\n if (!config.disableLogs) {\r\n console.log(framesRemaining + '/' + framesLength + ' frames remaining');\r\n }\r\n\r\n if (config.onEncodingCallback) {\r\n config.onEncodingCallback(framesRemaining, framesLength);\r\n }\r\n\r\n var webp = frame.image.toDataURL('image/webp', 1);\r\n whammy.frames[idx].image = webp;\r\n });\r\n\r\n if (!config.disableLogs) {\r\n console.log('Generating WebM');\r\n }\r\n\r\n callback();\r\n };\r\n\r\n /**\r\n * This method stops recording Canvas.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n isRecording = false;\r\n\r\n var that = this;\r\n\r\n if (isCanvasSupportsStreamCapturing && mediaStreamRecorder) {\r\n mediaStreamRecorder.stop(callback);\r\n return;\r\n }\r\n\r\n this.getWebPImages(function() {\r\n /**\r\n * @property {Blob} blob - Recorded frames in video/webm blob.\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n whammy.compile(function(blob) {\r\n if (!config.disableLogs) {\r\n console.log('Recording finished!');\r\n }\r\n\r\n that.blob = blob;\r\n\r\n if (that.blob.forEach) {\r\n that.blob = new Blob([], {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n if (callback) {\r\n callback(that.blob);\r\n }\r\n\r\n whammy.frames = [];\r\n });\r\n });\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n\r\n if (mediaStreamRecorder instanceof MediaStreamRecorder) {\r\n mediaStreamRecorder.pause();\r\n return;\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n\r\n if (mediaStreamRecorder instanceof MediaStreamRecorder) {\r\n mediaStreamRecorder.resume();\r\n return;\r\n }\r\n\r\n if (!isRecording) {\r\n this.record();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof CanvasRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (isRecording) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n whammy.frames = [];\r\n isRecording = false;\r\n isPausedRecording = false;\r\n }\r\n\r\n // for debugging\r\n this.name = 'CanvasRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n function cloneCanvas() {\r\n //create a new canvas\r\n var newCanvas = document.createElement('canvas');\r\n var context = newCanvas.getContext('2d');\r\n\r\n //set dimensions\r\n newCanvas.width = htmlElement.width;\r\n newCanvas.height = htmlElement.height;\r\n\r\n //apply the old canvas to the new one\r\n context.drawImage(htmlElement, 0, 0);\r\n\r\n //return the new canvas\r\n return newCanvas;\r\n }\r\n\r\n function drawCanvasFrame() {\r\n if (isPausedRecording) {\r\n lastTime = new Date().getTime();\r\n return setTimeout(drawCanvasFrame, 500);\r\n }\r\n\r\n if (htmlElement.nodeName.toLowerCase() === 'canvas') {\r\n var duration = new Date().getTime() - lastTime;\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n whammy.frames.push({\r\n image: cloneCanvas(),\r\n duration: duration\r\n });\r\n\r\n if (isRecording) {\r\n setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n return;\r\n }\r\n\r\n html2canvas(htmlElement, {\r\n grabMouse: typeof config.showMousePointer === 'undefined' || config.showMousePointer,\r\n onrendered: function(canvas) {\r\n var duration = new Date().getTime() - lastTime;\r\n if (!duration) {\r\n return setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n whammy.frames.push({\r\n image: canvas.toDataURL('image/webp', 1),\r\n duration: duration\r\n });\r\n\r\n if (isRecording) {\r\n setTimeout(drawCanvasFrame, config.frameInterval);\r\n }\r\n }\r\n });\r\n }\r\n\r\n var lastTime = new Date().getTime();\r\n\r\n var whammy = new Whammy.Video(100);\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.CanvasRecorder = CanvasRecorder;\r\n}\n\r\n// _________________\r\n// WhammyRecorder.js\r\n\r\n/**\r\n * WhammyRecorder is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It runs top over {@link Whammy}.\r\n * @summary Video recording feature in Chrome.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef WhammyRecorder\r\n * @class\r\n * @example\r\n * var recorder = new WhammyRecorder(mediaStream);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {disableLogs: true, initCallback: function, video: HTMLVideoElement, etc.}\r\n */\r\n\r\nfunction WhammyRecorder(mediaStream, config) {\r\n\r\n config = config || {};\r\n\r\n if (!config.frameInterval) {\r\n config.frameInterval = 10;\r\n }\r\n\r\n if (!config.disableLogs) {\r\n console.log('Using frames-interval:', config.frameInterval);\r\n }\r\n\r\n /**\r\n * This method records video.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (!config.width) {\r\n config.width = 320;\r\n }\r\n\r\n if (!config.height) {\r\n config.height = 240;\r\n }\r\n\r\n if (!config.video) {\r\n config.video = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n if (!config.canvas) {\r\n config.canvas = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n canvas.width = config.canvas.width || 320;\r\n canvas.height = config.canvas.height || 240;\r\n\r\n context = canvas.getContext('2d');\r\n\r\n // setting defaults\r\n if (config.video && config.video instanceof HTMLVideoElement) {\r\n video = config.video.cloneNode();\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n } else {\r\n video = document.createElement('video');\r\n\r\n setSrcObject(mediaStream, video);\r\n\r\n video.onloadedmetadata = function() { // \"onloadedmetadata\" may NOT work in FF?\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n video.width = config.video.width;\r\n video.height = config.video.height;\r\n }\r\n\r\n video.muted = true;\r\n video.play();\r\n\r\n lastTime = new Date().getTime();\r\n whammy = new Whammy.Video();\r\n\r\n if (!config.disableLogs) {\r\n console.log('canvas resolutions', canvas.width, '*', canvas.height);\r\n console.log('video width/height', video.width || canvas.width, '*', video.height || canvas.height);\r\n }\r\n\r\n drawFrames(config.frameInterval);\r\n };\r\n\r\n /**\r\n * Draw and push frames to Whammy\r\n * @param {integer} frameInterval - set minimum interval (in milliseconds) between each time we push a frame to Whammy\r\n */\r\n function drawFrames(frameInterval) {\r\n frameInterval = typeof frameInterval !== 'undefined' ? frameInterval : 10;\r\n\r\n var duration = new Date().getTime() - lastTime;\r\n if (!duration) {\r\n return setTimeout(drawFrames, frameInterval, frameInterval);\r\n }\r\n\r\n if (isPausedRecording) {\r\n lastTime = new Date().getTime();\r\n return setTimeout(drawFrames, 100);\r\n }\r\n\r\n // via #206, by Jack i.e. @Seymourr\r\n lastTime = new Date().getTime();\r\n\r\n if (video.paused) {\r\n // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316\r\n // Tweak for Android Chrome\r\n video.play();\r\n }\r\n\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n whammy.frames.push({\r\n duration: duration,\r\n image: canvas.toDataURL('image/webp')\r\n });\r\n\r\n if (!isStopDrawing) {\r\n setTimeout(drawFrames, frameInterval, frameInterval);\r\n }\r\n }\r\n\r\n function asyncLoop(o) {\r\n var i = -1,\r\n length = o.length;\r\n\r\n (function loop() {\r\n i++;\r\n if (i === length) {\r\n o.callback();\r\n return;\r\n }\r\n\r\n // \"setTimeout\" added by Jim McLeod\r\n setTimeout(function() {\r\n o.functionToLoop(loop, i);\r\n }, 1);\r\n })();\r\n }\r\n\r\n\r\n /**\r\n * remove black frames from the beginning to the specified frame\r\n * @param {Array} _frames - array of frames to be checked\r\n * @param {number} _framesToCheck - number of frame until check will be executed (-1 - will drop all frames until frame not matched will be found)\r\n * @param {number} _pixTolerance - 0 - very strict (only black pixel color) ; 1 - all\r\n * @param {number} _frameTolerance - 0 - very strict (only black frame color) ; 1 - all\r\n * @returns {Array} - array of frames\r\n */\r\n // pull#293 by @volodalexey\r\n function dropBlackFrames(_frames, _framesToCheck, _pixTolerance, _frameTolerance, callback) {\r\n var localCanvas = document.createElement('canvas');\r\n localCanvas.width = canvas.width;\r\n localCanvas.height = canvas.height;\r\n var context2d = localCanvas.getContext('2d');\r\n var resultFrames = [];\r\n\r\n var checkUntilNotBlack = _framesToCheck === -1;\r\n var endCheckFrame = (_framesToCheck && _framesToCheck > 0 && _framesToCheck <= _frames.length) ?\r\n _framesToCheck : _frames.length;\r\n var sampleColor = {\r\n r: 0,\r\n g: 0,\r\n b: 0\r\n };\r\n var maxColorDifference = Math.sqrt(\r\n Math.pow(255, 2) +\r\n Math.pow(255, 2) +\r\n Math.pow(255, 2)\r\n );\r\n var pixTolerance = _pixTolerance && _pixTolerance >= 0 && _pixTolerance <= 1 ? _pixTolerance : 0;\r\n var frameTolerance = _frameTolerance && _frameTolerance >= 0 && _frameTolerance <= 1 ? _frameTolerance : 0;\r\n var doNotCheckNext = false;\r\n\r\n asyncLoop({\r\n length: endCheckFrame,\r\n functionToLoop: function(loop, f) {\r\n var matchPixCount, endPixCheck, maxPixCount;\r\n\r\n var finishImage = function() {\r\n if (!doNotCheckNext && maxPixCount - matchPixCount <= maxPixCount * frameTolerance) {\r\n // console.log('removed black frame : ' + f + ' ; frame duration ' + _frames[f].duration);\r\n } else {\r\n // console.log('frame is passed : ' + f);\r\n if (checkUntilNotBlack) {\r\n doNotCheckNext = true;\r\n }\r\n resultFrames.push(_frames[f]);\r\n }\r\n loop();\r\n };\r\n\r\n if (!doNotCheckNext) {\r\n var image = new Image();\r\n image.onload = function() {\r\n context2d.drawImage(image, 0, 0, canvas.width, canvas.height);\r\n var imageData = context2d.getImageData(0, 0, canvas.width, canvas.height);\r\n matchPixCount = 0;\r\n endPixCheck = imageData.data.length;\r\n maxPixCount = imageData.data.length / 4;\r\n\r\n for (var pix = 0; pix < endPixCheck; pix += 4) {\r\n var currentColor = {\r\n r: imageData.data[pix],\r\n g: imageData.data[pix + 1],\r\n b: imageData.data[pix + 2]\r\n };\r\n var colorDifference = Math.sqrt(\r\n Math.pow(currentColor.r - sampleColor.r, 2) +\r\n Math.pow(currentColor.g - sampleColor.g, 2) +\r\n Math.pow(currentColor.b - sampleColor.b, 2)\r\n );\r\n // difference in color it is difference in color vectors (r1,g1,b1) <=> (r2,g2,b2)\r\n if (colorDifference <= maxColorDifference * pixTolerance) {\r\n matchPixCount++;\r\n }\r\n }\r\n finishImage();\r\n };\r\n image.src = _frames[f].image;\r\n } else {\r\n finishImage();\r\n }\r\n },\r\n callback: function() {\r\n resultFrames = resultFrames.concat(_frames.slice(endCheckFrame));\r\n\r\n if (resultFrames.length <= 0) {\r\n // at least one last frame should be available for next manipulation\r\n // if total duration of all frames will be < 1000 than ffmpeg doesn't work well...\r\n resultFrames.push(_frames[_frames.length - 1]);\r\n }\r\n callback(resultFrames);\r\n }\r\n });\r\n }\r\n\r\n var isStopDrawing = false;\r\n\r\n /**\r\n * This method stops recording video.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n isStopDrawing = true;\r\n\r\n var _this = this;\r\n // analyse of all frames takes some time!\r\n setTimeout(function() {\r\n // e.g. dropBlackFrames(frames, 10, 1, 1) - will cut all 10 frames\r\n // e.g. dropBlackFrames(frames, 10, 0.5, 0.5) - will analyse 10 frames\r\n // e.g. dropBlackFrames(frames, 10) === dropBlackFrames(frames, 10, 0, 0) - will analyse 10 frames with strict black color\r\n dropBlackFrames(whammy.frames, -1, null, null, function(frames) {\r\n whammy.frames = frames;\r\n\r\n // to display advertisement images!\r\n if (config.advertisement && config.advertisement.length) {\r\n whammy.frames = config.advertisement.concat(whammy.frames);\r\n }\r\n\r\n /**\r\n * @property {Blob} blob - Recorded frames in video/webm blob.\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.stop(function() {\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n whammy.compile(function(blob) {\r\n _this.blob = blob;\r\n\r\n if (_this.blob.forEach) {\r\n _this.blob = new Blob([], {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n if (callback) {\r\n callback(_this.blob);\r\n }\r\n });\r\n });\r\n }, 10);\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n\r\n if (isStopDrawing) {\r\n this.record();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof WhammyRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (!isStopDrawing) {\r\n this.stop(clearRecordedDataCB);\r\n }\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n whammy.frames = [];\r\n isStopDrawing = true;\r\n isPausedRecording = false;\r\n }\r\n\r\n // for debugging\r\n this.name = 'WhammyRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n\r\n var video;\r\n var lastTime;\r\n var whammy;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.WhammyRecorder = WhammyRecorder;\r\n}\n\r\n// https://github.com/antimatter15/whammy/blob/master/LICENSE\r\n// _________\r\n// Whammy.js\r\n\r\n// todo: Firefox now supports webp for webm containers!\r\n// their MediaRecorder implementation works well!\r\n// should we provide an option to record via Whammy.js or MediaRecorder API is a better solution?\r\n\r\n/**\r\n * Whammy is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It is written by {@link https://github.com/antimatter15|antimatter15}\r\n * @summary A real time javascript webm encoder based on a canvas hack.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef Whammy\r\n * @class\r\n * @example\r\n * var recorder = new Whammy().Video(15);\r\n * recorder.add(context || canvas || dataURL);\r\n * var output = recorder.compile();\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\nvar Whammy = (function() {\r\n // a more abstract-ish API\r\n\r\n function WhammyVideo(duration) {\r\n this.frames = [];\r\n this.duration = duration || 1;\r\n this.quality = 0.8;\r\n }\r\n\r\n /**\r\n * Pass Canvas or Context or image/webp(string) to {@link Whammy} encoder.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * recorder.add(canvas || context || 'image/webp');\r\n * @param {string} frame - Canvas || Context || image/webp\r\n * @param {number} duration - Stick a duration (in milliseconds)\r\n */\r\n WhammyVideo.prototype.add = function(frame, duration) {\r\n if ('canvas' in frame) { //CanvasRenderingContext2D\r\n frame = frame.canvas;\r\n }\r\n\r\n if ('toDataURL' in frame) {\r\n frame = frame.toDataURL('image/webp', this.quality);\r\n }\r\n\r\n if (!(/^data:image\\/webp;base64,/ig).test(frame)) {\r\n throw 'Input must be formatted properly as a base64 encoded DataURI of type image/webp';\r\n }\r\n this.frames.push({\r\n image: frame,\r\n duration: duration || this.duration\r\n });\r\n };\r\n\r\n function processInWebWorker(_function) {\r\n var blob = URL.createObjectURL(new Blob([_function.toString(),\r\n 'this.onmessage = function (eee) {' + _function.name + '(eee.data);}'\r\n ], {\r\n type: 'application/javascript'\r\n }));\r\n\r\n var worker = new Worker(blob);\r\n URL.revokeObjectURL(blob);\r\n return worker;\r\n }\r\n\r\n function whammyInWebWorker(frames) {\r\n function ArrayToWebM(frames) {\r\n var info = checkFrames(frames);\r\n if (!info) {\r\n return [];\r\n }\r\n\r\n var clusterMaxDuration = 30000;\r\n\r\n var EBML = [{\r\n 'id': 0x1a45dfa3, // EBML\r\n 'data': [{\r\n 'data': 1,\r\n 'id': 0x4286 // EBMLVersion\r\n }, {\r\n 'data': 1,\r\n 'id': 0x42f7 // EBMLReadVersion\r\n }, {\r\n 'data': 4,\r\n 'id': 0x42f2 // EBMLMaxIDLength\r\n }, {\r\n 'data': 8,\r\n 'id': 0x42f3 // EBMLMaxSizeLength\r\n }, {\r\n 'data': 'webm',\r\n 'id': 0x4282 // DocType\r\n }, {\r\n 'data': 2,\r\n 'id': 0x4287 // DocTypeVersion\r\n }, {\r\n 'data': 2,\r\n 'id': 0x4285 // DocTypeReadVersion\r\n }]\r\n }, {\r\n 'id': 0x18538067, // Segment\r\n 'data': [{\r\n 'id': 0x1549a966, // Info\r\n 'data': [{\r\n 'data': 1e6, //do things in millisecs (num of nanosecs for duration scale)\r\n 'id': 0x2ad7b1 // TimecodeScale\r\n }, {\r\n 'data': 'whammy',\r\n 'id': 0x4d80 // MuxingApp\r\n }, {\r\n 'data': 'whammy',\r\n 'id': 0x5741 // WritingApp\r\n }, {\r\n 'data': doubleToString(info.duration),\r\n 'id': 0x4489 // Duration\r\n }]\r\n }, {\r\n 'id': 0x1654ae6b, // Tracks\r\n 'data': [{\r\n 'id': 0xae, // TrackEntry\r\n 'data': [{\r\n 'data': 1,\r\n 'id': 0xd7 // TrackNumber\r\n }, {\r\n 'data': 1,\r\n 'id': 0x73c5 // TrackUID\r\n }, {\r\n 'data': 0,\r\n 'id': 0x9c // FlagLacing\r\n }, {\r\n 'data': 'und',\r\n 'id': 0x22b59c // Language\r\n }, {\r\n 'data': 'V_VP8',\r\n 'id': 0x86 // CodecID\r\n }, {\r\n 'data': 'VP8',\r\n 'id': 0x258688 // CodecName\r\n }, {\r\n 'data': 1,\r\n 'id': 0x83 // TrackType\r\n }, {\r\n 'id': 0xe0, // Video\r\n 'data': [{\r\n 'data': info.width,\r\n 'id': 0xb0 // PixelWidth\r\n }, {\r\n 'data': info.height,\r\n 'id': 0xba // PixelHeight\r\n }]\r\n }]\r\n }]\r\n }]\r\n }];\r\n\r\n //Generate clusters (max duration)\r\n var frameNumber = 0;\r\n var clusterTimecode = 0;\r\n while (frameNumber < frames.length) {\r\n\r\n var clusterFrames = [];\r\n var clusterDuration = 0;\r\n do {\r\n clusterFrames.push(frames[frameNumber]);\r\n clusterDuration += frames[frameNumber].duration;\r\n frameNumber++;\r\n } while (frameNumber < frames.length && clusterDuration < clusterMaxDuration);\r\n\r\n var clusterCounter = 0;\r\n var cluster = {\r\n 'id': 0x1f43b675, // Cluster\r\n 'data': getClusterData(clusterTimecode, clusterCounter, clusterFrames)\r\n }; //Add cluster to segment\r\n EBML[1].data.push(cluster);\r\n clusterTimecode += clusterDuration;\r\n }\r\n\r\n return generateEBML(EBML);\r\n }\r\n\r\n function getClusterData(clusterTimecode, clusterCounter, clusterFrames) {\r\n return [{\r\n 'data': clusterTimecode,\r\n 'id': 0xe7 // Timecode\r\n }].concat(clusterFrames.map(function(webp) {\r\n var block = makeSimpleBlock({\r\n discardable: 0,\r\n frame: webp.data.slice(4),\r\n invisible: 0,\r\n keyframe: 1,\r\n lacing: 0,\r\n trackNum: 1,\r\n timecode: Math.round(clusterCounter)\r\n });\r\n clusterCounter += webp.duration;\r\n return {\r\n data: block,\r\n id: 0xa3\r\n };\r\n }));\r\n }\r\n\r\n // sums the lengths of all the frames and gets the duration\r\n\r\n function checkFrames(frames) {\r\n if (!frames[0]) {\r\n postMessage({\r\n error: 'Something went wrong. Maybe WebP format is not supported in the current browser.'\r\n });\r\n return;\r\n }\r\n\r\n var width = frames[0].width,\r\n height = frames[0].height,\r\n duration = frames[0].duration;\r\n\r\n for (var i = 1; i < frames.length; i++) {\r\n duration += frames[i].duration;\r\n }\r\n return {\r\n duration: duration,\r\n width: width,\r\n height: height\r\n };\r\n }\r\n\r\n function numToBuffer(num) {\r\n var parts = [];\r\n while (num > 0) {\r\n parts.push(num & 0xff);\r\n num = num >> 8;\r\n }\r\n return new Uint8Array(parts.reverse());\r\n }\r\n\r\n function strToBuffer(str) {\r\n return new Uint8Array(str.split('').map(function(e) {\r\n return e.charCodeAt(0);\r\n }));\r\n }\r\n\r\n function bitsToBuffer(bits) {\r\n var data = [];\r\n var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : '';\r\n bits = pad + bits;\r\n for (var i = 0; i < bits.length; i += 8) {\r\n data.push(parseInt(bits.substr(i, 8), 2));\r\n }\r\n return new Uint8Array(data);\r\n }\r\n\r\n function generateEBML(json) {\r\n var ebml = [];\r\n for (var i = 0; i < json.length; i++) {\r\n var data = json[i].data;\r\n\r\n if (typeof data === 'object') {\r\n data = generateEBML(data);\r\n }\r\n\r\n if (typeof data === 'number') {\r\n data = bitsToBuffer(data.toString(2));\r\n }\r\n\r\n if (typeof data === 'string') {\r\n data = strToBuffer(data);\r\n }\r\n\r\n var len = data.size || data.byteLength || data.length;\r\n var zeroes = Math.ceil(Math.ceil(Math.log(len) / Math.log(2)) / 8);\r\n var sizeToString = len.toString(2);\r\n var padded = (new Array((zeroes * 7 + 7 + 1) - sizeToString.length)).join('0') + sizeToString;\r\n var size = (new Array(zeroes)).join('0') + '1' + padded;\r\n\r\n ebml.push(numToBuffer(json[i].id));\r\n ebml.push(bitsToBuffer(size));\r\n ebml.push(data);\r\n }\r\n\r\n return new Blob(ebml, {\r\n type: 'video/webm'\r\n });\r\n }\r\n\r\n function toBinStrOld(bits) {\r\n var data = '';\r\n var pad = (bits.length % 8) ? (new Array(1 + 8 - (bits.length % 8))).join('0') : '';\r\n bits = pad + bits;\r\n for (var i = 0; i < bits.length; i += 8) {\r\n data += String.fromCharCode(parseInt(bits.substr(i, 8), 2));\r\n }\r\n return data;\r\n }\r\n\r\n function makeSimpleBlock(data) {\r\n var flags = 0;\r\n\r\n if (data.keyframe) {\r\n flags |= 128;\r\n }\r\n\r\n if (data.invisible) {\r\n flags |= 8;\r\n }\r\n\r\n if (data.lacing) {\r\n flags |= (data.lacing << 1);\r\n }\r\n\r\n if (data.discardable) {\r\n flags |= 1;\r\n }\r\n\r\n if (data.trackNum > 127) {\r\n throw 'TrackNumber > 127 not supported';\r\n }\r\n\r\n var out = [data.trackNum | 0x80, data.timecode >> 8, data.timecode & 0xff, flags].map(function(e) {\r\n return String.fromCharCode(e);\r\n }).join('') + data.frame;\r\n\r\n return out;\r\n }\r\n\r\n function parseWebP(riff) {\r\n var VP8 = riff.RIFF[0].WEBP[0];\r\n\r\n var frameStart = VP8.indexOf('\\x9d\\x01\\x2a'); // A VP8 keyframe starts with the 0x9d012a header\r\n for (var i = 0, c = []; i < 4; i++) {\r\n c[i] = VP8.charCodeAt(frameStart + 3 + i);\r\n }\r\n\r\n var width, height, tmp;\r\n\r\n //the code below is literally copied verbatim from the bitstream spec\r\n tmp = (c[1] << 8) | c[0];\r\n width = tmp & 0x3FFF;\r\n tmp = (c[3] << 8) | c[2];\r\n height = tmp & 0x3FFF;\r\n return {\r\n width: width,\r\n height: height,\r\n data: VP8,\r\n riff: riff\r\n };\r\n }\r\n\r\n function getStrLength(string, offset) {\r\n return parseInt(string.substr(offset + 4, 4).split('').map(function(i) {\r\n var unpadded = i.charCodeAt(0).toString(2);\r\n return (new Array(8 - unpadded.length + 1)).join('0') + unpadded;\r\n }).join(''), 2);\r\n }\r\n\r\n function parseRIFF(string) {\r\n var offset = 0;\r\n var chunks = {};\r\n\r\n while (offset < string.length) {\r\n var id = string.substr(offset, 4);\r\n var len = getStrLength(string, offset);\r\n var data = string.substr(offset + 4 + 4, len);\r\n offset += 4 + 4 + len;\r\n chunks[id] = chunks[id] || [];\r\n\r\n if (id === 'RIFF' || id === 'LIST') {\r\n chunks[id].push(parseRIFF(data));\r\n } else {\r\n chunks[id].push(data);\r\n }\r\n }\r\n return chunks;\r\n }\r\n\r\n function doubleToString(num) {\r\n return [].slice.call(\r\n new Uint8Array((new Float64Array([num])).buffer), 0).map(function(e) {\r\n return String.fromCharCode(e);\r\n }).reverse().join('');\r\n }\r\n\r\n var webm = new ArrayToWebM(frames.map(function(frame) {\r\n var webp = parseWebP(parseRIFF(atob(frame.image.slice(23))));\r\n webp.duration = frame.duration;\r\n return webp;\r\n }));\r\n\r\n postMessage(webm);\r\n }\r\n\r\n /**\r\n * Encodes frames in WebM container. It uses WebWorkinvoke to invoke 'ArrayToWebM' method.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * recorder.compile(function(blob) {\r\n * // blob.size - blob.type\r\n * });\r\n */\r\n WhammyVideo.prototype.compile = function(callback) {\r\n var webWorker = processInWebWorker(whammyInWebWorker);\r\n\r\n webWorker.onmessage = function(event) {\r\n if (event.data.error) {\r\n console.error(event.data.error);\r\n return;\r\n }\r\n callback(event.data);\r\n };\r\n\r\n webWorker.postMessage(this.frames);\r\n };\r\n\r\n return {\r\n /**\r\n * A more abstract-ish API.\r\n * @method\r\n * @memberof Whammy\r\n * @example\r\n * recorder = new Whammy().Video(0.8, 100);\r\n * @param {?number} speed - 0.8\r\n * @param {?number} quality - 100\r\n */\r\n Video: WhammyVideo\r\n };\r\n})();\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.Whammy = Whammy;\r\n}\n\r\n// ______________ (indexed-db)\r\n// DiskStorage.js\r\n\r\n/**\r\n * DiskStorage is a standalone object used by {@link RecordRTC} to store recorded blobs in IndexedDB storage.\r\n * @summary Writing blobs into IndexedDB.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @example\r\n * DiskStorage.Store({\r\n * audioBlob: yourAudioBlob,\r\n * videoBlob: yourVideoBlob,\r\n * gifBlob : yourGifBlob\r\n * });\r\n * DiskStorage.Fetch(function(dataURL, type) {\r\n * if(type === 'audioBlob') { }\r\n * if(type === 'videoBlob') { }\r\n * if(type === 'gifBlob') { }\r\n * });\r\n * // DiskStorage.dataStoreName = 'recordRTC';\r\n * // DiskStorage.onError = function(error) { };\r\n * @property {function} init - This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally.\r\n * @property {function} Fetch - This method fetches stored blobs from IndexedDB.\r\n * @property {function} Store - This method stores blobs in IndexedDB.\r\n * @property {function} onError - This function is invoked for any known/unknown error.\r\n * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage.\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n */\r\n\r\n\r\nvar DiskStorage = {\r\n /**\r\n * This method must be called once to initialize IndexedDB ObjectStore. Though, it is auto-used internally.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.init();\r\n */\r\n init: function() {\r\n var self = this;\r\n\r\n if (typeof indexedDB === 'undefined' || typeof indexedDB.open === 'undefined') {\r\n console.error('IndexedDB API are not available in this browser.');\r\n return;\r\n }\r\n\r\n var dbVersion = 1;\r\n var dbName = this.dbName || location.href.replace(/\\/|:|#|%|\\.|\\[|\\]/g, ''),\r\n db;\r\n var request = indexedDB.open(dbName, dbVersion);\r\n\r\n function createObjectStore(dataBase) {\r\n dataBase.createObjectStore(self.dataStoreName);\r\n }\r\n\r\n function putInDB() {\r\n var transaction = db.transaction([self.dataStoreName], 'readwrite');\r\n\r\n if (self.videoBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.videoBlob, 'videoBlob');\r\n }\r\n\r\n if (self.gifBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.gifBlob, 'gifBlob');\r\n }\r\n\r\n if (self.audioBlob) {\r\n transaction.objectStore(self.dataStoreName).put(self.audioBlob, 'audioBlob');\r\n }\r\n\r\n function getFromStore(portionName) {\r\n transaction.objectStore(self.dataStoreName).get(portionName).onsuccess = function(event) {\r\n if (self.callback) {\r\n self.callback(event.target.result, portionName);\r\n }\r\n };\r\n }\r\n\r\n getFromStore('audioBlob');\r\n getFromStore('videoBlob');\r\n getFromStore('gifBlob');\r\n }\r\n\r\n request.onerror = self.onError;\r\n\r\n request.onsuccess = function() {\r\n db = request.result;\r\n db.onerror = self.onError;\r\n\r\n if (db.setVersion) {\r\n if (db.version !== dbVersion) {\r\n var setVersion = db.setVersion(dbVersion);\r\n setVersion.onsuccess = function() {\r\n createObjectStore(db);\r\n putInDB();\r\n };\r\n } else {\r\n putInDB();\r\n }\r\n } else {\r\n putInDB();\r\n }\r\n };\r\n request.onupgradeneeded = function(event) {\r\n createObjectStore(event.target.result);\r\n };\r\n },\r\n /**\r\n * This method fetches stored blobs from IndexedDB.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.Fetch(function(dataURL, type) {\r\n * if(type === 'audioBlob') { }\r\n * if(type === 'videoBlob') { }\r\n * if(type === 'gifBlob') { }\r\n * });\r\n */\r\n Fetch: function(callback) {\r\n this.callback = callback;\r\n this.init();\r\n\r\n return this;\r\n },\r\n /**\r\n * This method stores blobs in IndexedDB.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.Store({\r\n * audioBlob: yourAudioBlob,\r\n * videoBlob: yourVideoBlob,\r\n * gifBlob : yourGifBlob\r\n * });\r\n */\r\n Store: function(config) {\r\n this.audioBlob = config.audioBlob;\r\n this.videoBlob = config.videoBlob;\r\n this.gifBlob = config.gifBlob;\r\n\r\n this.init();\r\n\r\n return this;\r\n },\r\n /**\r\n * This function is invoked for any known/unknown error.\r\n * @method\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.onError = function(error){\r\n * alerot( JSON.stringify(error) );\r\n * };\r\n */\r\n onError: function(error) {\r\n console.error(JSON.stringify(error, null, '\\t'));\r\n },\r\n\r\n /**\r\n * @property {string} dataStoreName - Name of the ObjectStore created in IndexedDB storage.\r\n * @memberof DiskStorage\r\n * @internal\r\n * @example\r\n * DiskStorage.dataStoreName = 'recordRTC';\r\n */\r\n dataStoreName: 'recordRTC',\r\n dbName: null\r\n};\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.DiskStorage = DiskStorage;\r\n}\n\r\n// ______________\r\n// GifRecorder.js\r\n\r\n/**\r\n * GifRecorder is standalone calss used by {@link RecordRTC} to record video or canvas into animated gif.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef GifRecorder\r\n * @class\r\n * @example\r\n * var recorder = new GifRecorder(mediaStream || canvas || context, { onGifPreview: function, onGifRecordingStarted: function, width: 1280, height: 720, frameRate: 200, quality: 10 });\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * img.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object or HTMLCanvasElement or CanvasRenderingContext2D.\r\n * @param {object} config - {disableLogs:true, initCallback: function, width: 320, height: 240, frameRate: 200, quality: 10}\r\n */\r\n\r\nfunction GifRecorder(mediaStream, config) {\r\n if (typeof GIFEncoder === 'undefined') {\r\n var script = document.createElement('script');\r\n script.src = 'https://www.webrtc-experiment.com/gif-recorder.js';\r\n (document.body || document.documentElement).appendChild(script);\r\n }\r\n\r\n config = config || {};\r\n\r\n var isHTMLObject = mediaStream instanceof CanvasRenderingContext2D || mediaStream instanceof HTMLCanvasElement;\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n if (typeof GIFEncoder === 'undefined') {\r\n setTimeout(self.record, 1000);\r\n return;\r\n }\r\n\r\n if (!isLoadedMetaData) {\r\n setTimeout(self.record, 1000);\r\n return;\r\n }\r\n\r\n if (!isHTMLObject) {\r\n if (!config.width) {\r\n config.width = video.offsetWidth || 320;\r\n }\r\n\r\n if (!config.height) {\r\n config.height = video.offsetHeight || 240;\r\n }\r\n\r\n if (!config.video) {\r\n config.video = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n if (!config.canvas) {\r\n config.canvas = {\r\n width: config.width,\r\n height: config.height\r\n };\r\n }\r\n\r\n canvas.width = config.canvas.width || 320;\r\n canvas.height = config.canvas.height || 240;\r\n\r\n video.width = config.video.width || 320;\r\n video.height = config.video.height || 240;\r\n }\r\n\r\n // external library to record as GIF images\r\n gifEncoder = new GIFEncoder();\r\n\r\n // void setRepeat(int iter) \r\n // Sets the number of times the set of GIF frames should be played. \r\n // Default is 1; 0 means play indefinitely.\r\n gifEncoder.setRepeat(0);\r\n\r\n // void setFrameRate(Number fps) \r\n // Sets frame rate in frames per second. \r\n // Equivalent to setDelay(1000/fps).\r\n // Using \"setDelay\" instead of \"setFrameRate\"\r\n gifEncoder.setDelay(config.frameRate || 200);\r\n\r\n // void setQuality(int quality) \r\n // Sets quality of color quantization (conversion of images to the \r\n // maximum 256 colors allowed by the GIF specification). \r\n // Lower values (minimum = 1) produce better colors, \r\n // but slow processing significantly. 10 is the default, \r\n // and produces good color mapping at reasonable speeds. \r\n // Values greater than 20 do not yield significant improvements in speed.\r\n gifEncoder.setQuality(config.quality || 10);\r\n\r\n // Boolean start() \r\n // This writes the GIF Header and returns false if it fails.\r\n gifEncoder.start();\r\n\r\n if (typeof config.onGifRecordingStarted === 'function') {\r\n config.onGifRecordingStarted();\r\n }\r\n\r\n startTime = Date.now();\r\n\r\n function drawVideoFrame(time) {\r\n if (self.clearedRecordedData === true) {\r\n return;\r\n }\r\n\r\n if (isPausedRecording) {\r\n return setTimeout(function() {\r\n drawVideoFrame(time);\r\n }, 100);\r\n }\r\n\r\n lastAnimationFrame = requestAnimationFrame(drawVideoFrame);\r\n\r\n if (typeof lastFrameTime === undefined) {\r\n lastFrameTime = time;\r\n }\r\n\r\n // ~10 fps\r\n if (time - lastFrameTime < 90) {\r\n return;\r\n }\r\n\r\n if (!isHTMLObject && video.paused) {\r\n // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316\r\n // Tweak for Android Chrome\r\n video.play();\r\n }\r\n\r\n if (!isHTMLObject) {\r\n context.drawImage(video, 0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n if (config.onGifPreview) {\r\n config.onGifPreview(canvas.toDataURL('image/png'));\r\n }\r\n\r\n gifEncoder.addFrame(context);\r\n lastFrameTime = time;\r\n }\r\n\r\n lastAnimationFrame = requestAnimationFrame(drawVideoFrame);\r\n\r\n if (config.initCallback) {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * img.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n callback = callback || function() {};\r\n\r\n if (lastAnimationFrame) {\r\n cancelAnimationFrame(lastAnimationFrame);\r\n }\r\n\r\n endTime = Date.now();\r\n\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = new Blob([new Uint8Array(gifEncoder.stream().bin)], {\r\n type: 'image/gif'\r\n });\r\n\r\n callback(this.blob);\r\n\r\n // bug: find a way to clear old recorded blobs\r\n gifEncoder.stream().bin = [];\r\n };\r\n\r\n var isPausedRecording = false;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPausedRecording = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPausedRecording = false;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof GifRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n self.clearedRecordedData = true;\r\n clearRecordedDataCB();\r\n };\r\n\r\n function clearRecordedDataCB() {\r\n if (gifEncoder) {\r\n gifEncoder.stream().bin = [];\r\n }\r\n }\r\n\r\n // for debugging\r\n this.name = 'GifRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n\r\n if (isHTMLObject) {\r\n if (mediaStream instanceof CanvasRenderingContext2D) {\r\n context = mediaStream;\r\n canvas = context.canvas;\r\n } else if (mediaStream instanceof HTMLCanvasElement) {\r\n context = mediaStream.getContext('2d');\r\n canvas = mediaStream;\r\n }\r\n }\r\n\r\n var isLoadedMetaData = true;\r\n\r\n if (!isHTMLObject) {\r\n var video = document.createElement('video');\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.playsInline = true;\r\n\r\n isLoadedMetaData = false;\r\n video.onloadedmetadata = function() {\r\n isLoadedMetaData = true;\r\n };\r\n\r\n setSrcObject(mediaStream, video);\r\n\r\n video.play();\r\n }\r\n\r\n var lastAnimationFrame = null;\r\n var startTime, endTime, lastFrameTime;\r\n\r\n var gifEncoder;\r\n\r\n var self = this;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.GifRecorder = GifRecorder;\r\n}\n\r\n// Last time updated: 2019-06-21 4:09:42 AM UTC\r\n\r\n// ________________________\r\n// MultiStreamsMixer v1.2.2\r\n\r\n// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer\r\n\r\n// --------------------------------------------------\r\n// Muaz Khan - www.MuazKhan.com\r\n// MIT License - www.WebRTC-Experiment.com/licence\r\n// --------------------------------------------------\r\n\r\nfunction MultiStreamsMixer(arrayOfMediaStreams, elementClass) {\r\n\r\n var browserFakeUserAgent = 'Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45';\r\n\r\n (function(that) {\r\n if (typeof RecordRTC !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (!that) {\r\n return;\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n return;\r\n }\r\n\r\n if (typeof global === 'undefined') {\r\n return;\r\n }\r\n\r\n global.navigator = {\r\n userAgent: browserFakeUserAgent,\r\n getUserMedia: function() {}\r\n };\r\n\r\n if (!global.console) {\r\n global.console = {};\r\n }\r\n\r\n if (typeof global.console.log === 'undefined' || typeof global.console.error === 'undefined') {\r\n global.console.error = global.console.log = global.console.log || function() {\r\n console.log(arguments);\r\n };\r\n }\r\n\r\n if (typeof document === 'undefined') {\r\n /*global document:true */\r\n that.document = {\r\n documentElement: {\r\n appendChild: function() {\r\n return '';\r\n }\r\n }\r\n };\r\n\r\n document.createElement = document.captureStream = document.mozCaptureStream = function() {\r\n var obj = {\r\n getContext: function() {\r\n return obj;\r\n },\r\n play: function() {},\r\n pause: function() {},\r\n drawImage: function() {},\r\n toDataURL: function() {\r\n return '';\r\n },\r\n style: {}\r\n };\r\n return obj;\r\n };\r\n\r\n that.HTMLVideoElement = function() {};\r\n }\r\n\r\n if (typeof location === 'undefined') {\r\n /*global location:true */\r\n that.location = {\r\n protocol: 'file:',\r\n href: '',\r\n hash: ''\r\n };\r\n }\r\n\r\n if (typeof screen === 'undefined') {\r\n /*global screen:true */\r\n that.screen = {\r\n width: 0,\r\n height: 0\r\n };\r\n }\r\n\r\n if (typeof URL === 'undefined') {\r\n /*global screen:true */\r\n that.URL = {\r\n createObjectURL: function() {\r\n return '';\r\n },\r\n revokeObjectURL: function() {\r\n return '';\r\n }\r\n };\r\n }\r\n\r\n /*global window:true */\r\n that.window = global;\r\n })(typeof global !== 'undefined' ? global : null);\r\n\r\n // requires: chrome://flags/#enable-experimental-web-platform-features\r\n\r\n elementClass = elementClass || 'multi-streams-mixer';\r\n\r\n var videos = [];\r\n var isStopDrawingFrames = false;\r\n\r\n var canvas = document.createElement('canvas');\r\n var context = canvas.getContext('2d');\r\n canvas.style.opacity = 0;\r\n canvas.style.position = 'absolute';\r\n canvas.style.zIndex = -1;\r\n canvas.style.top = '-1000em';\r\n canvas.style.left = '-1000em';\r\n canvas.className = elementClass;\r\n (document.body || document.documentElement).appendChild(canvas);\r\n\r\n this.disableLogs = false;\r\n this.frameInterval = 10;\r\n\r\n this.width = 360;\r\n this.height = 240;\r\n\r\n // use gain node to prevent echo\r\n this.useGainNode = true;\r\n\r\n var self = this;\r\n\r\n // _____________________________\r\n // Cross-Browser-Declarations.js\r\n\r\n // WebAudio API representer\r\n var AudioContext = window.AudioContext;\r\n\r\n if (typeof AudioContext === 'undefined') {\r\n if (typeof webkitAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = webkitAudioContext;\r\n }\r\n\r\n if (typeof mozAudioContext !== 'undefined') {\r\n /*global AudioContext:true */\r\n AudioContext = mozAudioContext;\r\n }\r\n }\r\n\r\n /*jshint -W079 */\r\n var URL = window.URL;\r\n\r\n if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {\r\n /*global URL:true */\r\n URL = webkitURL;\r\n }\r\n\r\n if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?\r\n if (typeof navigator.webkitGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.webkitGetUserMedia;\r\n }\r\n\r\n if (typeof navigator.mozGetUserMedia !== 'undefined') {\r\n navigator.getUserMedia = navigator.mozGetUserMedia;\r\n }\r\n }\r\n\r\n var MediaStream = window.MediaStream;\r\n\r\n if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {\r\n MediaStream = webkitMediaStream;\r\n }\r\n\r\n /*global MediaStream:true */\r\n if (typeof MediaStream !== 'undefined') {\r\n // override \"stop\" method for all browsers\r\n if (typeof MediaStream.prototype.stop === 'undefined') {\r\n MediaStream.prototype.stop = function() {\r\n this.getTracks().forEach(function(track) {\r\n track.stop();\r\n });\r\n };\r\n }\r\n }\r\n\r\n var Storage = {};\r\n\r\n if (typeof AudioContext !== 'undefined') {\r\n Storage.AudioContext = AudioContext;\r\n } else if (typeof webkitAudioContext !== 'undefined') {\r\n Storage.AudioContext = webkitAudioContext;\r\n }\r\n\r\n function setSrcObject(stream, element) {\r\n if ('srcObject' in element) {\r\n element.srcObject = stream;\r\n } else if ('mozSrcObject' in element) {\r\n element.mozSrcObject = stream;\r\n } else {\r\n element.srcObject = stream;\r\n }\r\n }\r\n\r\n this.startDrawingFrames = function() {\r\n drawVideosToCanvas();\r\n };\r\n\r\n function drawVideosToCanvas() {\r\n if (isStopDrawingFrames) {\r\n return;\r\n }\r\n\r\n var videosLength = videos.length;\r\n\r\n var fullcanvas = false;\r\n var remaining = [];\r\n videos.forEach(function(video) {\r\n if (!video.stream) {\r\n video.stream = {};\r\n }\r\n\r\n if (video.stream.fullcanvas) {\r\n fullcanvas = video;\r\n } else {\r\n // todo: video.stream.active or video.stream.live to fix blank frames issues?\r\n remaining.push(video);\r\n }\r\n });\r\n\r\n if (fullcanvas) {\r\n canvas.width = fullcanvas.stream.width;\r\n canvas.height = fullcanvas.stream.height;\r\n } else if (remaining.length) {\r\n canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;\r\n\r\n var height = 1;\r\n if (videosLength === 3 || videosLength === 4) {\r\n height = 2;\r\n }\r\n if (videosLength === 5 || videosLength === 6) {\r\n height = 3;\r\n }\r\n if (videosLength === 7 || videosLength === 8) {\r\n height = 4;\r\n }\r\n if (videosLength === 9 || videosLength === 10) {\r\n height = 5;\r\n }\r\n canvas.height = remaining[0].height * height;\r\n } else {\r\n canvas.width = self.width || 360;\r\n canvas.height = self.height || 240;\r\n }\r\n\r\n if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {\r\n drawImage(fullcanvas);\r\n }\r\n\r\n remaining.forEach(function(video, idx) {\r\n drawImage(video, idx);\r\n });\r\n\r\n setTimeout(drawVideosToCanvas, self.frameInterval);\r\n }\r\n\r\n function drawImage(video, idx) {\r\n if (isStopDrawingFrames) {\r\n return;\r\n }\r\n\r\n var x = 0;\r\n var y = 0;\r\n var width = video.width;\r\n var height = video.height;\r\n\r\n if (idx === 1) {\r\n x = video.width;\r\n }\r\n\r\n if (idx === 2) {\r\n y = video.height;\r\n }\r\n\r\n if (idx === 3) {\r\n x = video.width;\r\n y = video.height;\r\n }\r\n\r\n if (idx === 4) {\r\n y = video.height * 2;\r\n }\r\n\r\n if (idx === 5) {\r\n x = video.width;\r\n y = video.height * 2;\r\n }\r\n\r\n if (idx === 6) {\r\n y = video.height * 3;\r\n }\r\n\r\n if (idx === 7) {\r\n x = video.width;\r\n y = video.height * 3;\r\n }\r\n\r\n if (typeof video.stream.left !== 'undefined') {\r\n x = video.stream.left;\r\n }\r\n\r\n if (typeof video.stream.top !== 'undefined') {\r\n y = video.stream.top;\r\n }\r\n\r\n if (typeof video.stream.width !== 'undefined') {\r\n width = video.stream.width;\r\n }\r\n\r\n if (typeof video.stream.height !== 'undefined') {\r\n height = video.stream.height;\r\n }\r\n\r\n context.drawImage(video, x, y, width, height);\r\n\r\n if (typeof video.stream.onRender === 'function') {\r\n video.stream.onRender(context, x, y, width, height, idx);\r\n }\r\n }\r\n\r\n function getMixedStream() {\r\n isStopDrawingFrames = false;\r\n var mixedVideoStream = getMixedVideoStream();\r\n\r\n var mixedAudioStream = getMixedAudioStream();\r\n if (mixedAudioStream) {\r\n mixedAudioStream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).forEach(function(track) {\r\n mixedVideoStream.addTrack(track);\r\n });\r\n }\r\n\r\n var fullcanvas;\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n if (stream.fullcanvas) {\r\n fullcanvas = true;\r\n }\r\n });\r\n\r\n // mixedVideoStream.prototype.appendStreams = appendStreams;\r\n // mixedVideoStream.prototype.resetVideoStreams = resetVideoStreams;\r\n // mixedVideoStream.prototype.clearRecordedData = clearRecordedData;\r\n\r\n return mixedVideoStream;\r\n }\r\n\r\n function getMixedVideoStream() {\r\n resetVideoStreams();\r\n\r\n var capturedStream;\r\n\r\n if ('captureStream' in canvas) {\r\n capturedStream = canvas.captureStream();\r\n } else if ('mozCaptureStream' in canvas) {\r\n capturedStream = canvas.mozCaptureStream();\r\n } else if (!self.disableLogs) {\r\n console.error('Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features');\r\n }\r\n\r\n var videoStream = new MediaStream();\r\n\r\n capturedStream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).forEach(function(track) {\r\n videoStream.addTrack(track);\r\n });\r\n\r\n canvas.stream = videoStream;\r\n\r\n return videoStream;\r\n }\r\n\r\n function getMixedAudioStream() {\r\n // via: @pehrsons\r\n if (!Storage.AudioContextConstructor) {\r\n Storage.AudioContextConstructor = new Storage.AudioContext();\r\n }\r\n\r\n self.audioContext = Storage.AudioContextConstructor;\r\n\r\n self.audioSources = [];\r\n\r\n if (self.useGainNode === true) {\r\n self.gainNode = self.audioContext.createGain();\r\n self.gainNode.connect(self.audioContext.destination);\r\n self.gainNode.gain.value = 0; // don't hear self\r\n }\r\n\r\n var audioTracksLength = 0;\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n if (!stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).length) {\r\n return;\r\n }\r\n\r\n audioTracksLength++;\r\n\r\n var audioSource = self.audioContext.createMediaStreamSource(stream);\r\n\r\n if (self.useGainNode === true) {\r\n audioSource.connect(self.gainNode);\r\n }\r\n\r\n self.audioSources.push(audioSource);\r\n });\r\n\r\n if (!audioTracksLength) {\r\n // because \"self.audioContext\" is not initialized\r\n // that's why we've to ignore rest of the code\r\n return;\r\n }\r\n\r\n self.audioDestination = self.audioContext.createMediaStreamDestination();\r\n self.audioSources.forEach(function(audioSource) {\r\n audioSource.connect(self.audioDestination);\r\n });\r\n return self.audioDestination.stream;\r\n }\r\n\r\n function getVideo(stream) {\r\n var video = document.createElement('video');\r\n\r\n setSrcObject(stream, video);\r\n\r\n video.className = elementClass;\r\n\r\n video.muted = true;\r\n video.volume = 0;\r\n\r\n video.width = stream.width || self.width || 360;\r\n video.height = stream.height || self.height || 240;\r\n\r\n video.play();\r\n\r\n return video;\r\n }\r\n\r\n this.appendStreams = function(streams) {\r\n if (!streams) {\r\n throw 'First parameter is required.';\r\n }\r\n\r\n if (!(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n streams.forEach(function(stream) {\r\n var newStream = new MediaStream();\r\n\r\n if (stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).length) {\r\n var video = getVideo(stream);\r\n video.stream = stream;\r\n videos.push(video);\r\n\r\n newStream.addTrack(stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n })[0]);\r\n }\r\n\r\n if (stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n }).length) {\r\n var audioSource = self.audioContext.createMediaStreamSource(stream);\r\n self.audioDestination = self.audioContext.createMediaStreamDestination();\r\n audioSource.connect(self.audioDestination);\r\n\r\n newStream.addTrack(self.audioDestination.stream.getTracks().filter(function(t) {\r\n return t.kind === 'audio';\r\n })[0]);\r\n }\r\n\r\n arrayOfMediaStreams.push(newStream);\r\n });\r\n };\r\n\r\n this.releaseStreams = function() {\r\n videos = [];\r\n isStopDrawingFrames = true;\r\n\r\n if (self.gainNode) {\r\n self.gainNode.disconnect();\r\n self.gainNode = null;\r\n }\r\n\r\n if (self.audioSources.length) {\r\n self.audioSources.forEach(function(source) {\r\n source.disconnect();\r\n });\r\n self.audioSources = [];\r\n }\r\n\r\n if (self.audioDestination) {\r\n self.audioDestination.disconnect();\r\n self.audioDestination = null;\r\n }\r\n\r\n if (self.audioContext) {\r\n self.audioContext.close();\r\n }\r\n\r\n self.audioContext = null;\r\n\r\n context.clearRect(0, 0, canvas.width, canvas.height);\r\n\r\n if (canvas.stream) {\r\n canvas.stream.stop();\r\n canvas.stream = null;\r\n }\r\n };\r\n\r\n this.resetVideoStreams = function(streams) {\r\n if (streams && !(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n resetVideoStreams(streams);\r\n };\r\n\r\n function resetVideoStreams(streams) {\r\n videos = [];\r\n streams = streams || arrayOfMediaStreams;\r\n\r\n // via: @adrian-ber\r\n streams.forEach(function(stream) {\r\n if (!stream.getTracks().filter(function(t) {\r\n return t.kind === 'video';\r\n }).length) {\r\n return;\r\n }\r\n\r\n var video = getVideo(stream);\r\n video.stream = stream;\r\n videos.push(video);\r\n });\r\n }\r\n\r\n // for debugging\r\n this.name = 'MultiStreamsMixer';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n this.getMixedStream = getMixedStream;\r\n\r\n}\r\n\r\nif (typeof RecordRTC === 'undefined') {\r\n if (typeof module !== 'undefined' /* && !!module.exports*/ ) {\r\n module.exports = MultiStreamsMixer;\r\n }\r\n\r\n if (typeof define === 'function' && define.amd) {\r\n define('MultiStreamsMixer', [], function() {\r\n return MultiStreamsMixer;\r\n });\r\n }\r\n}\n\r\n// ______________________\r\n// MultiStreamRecorder.js\r\n\r\n/*\r\n * Video conference recording, using captureStream API along with WebAudio and Canvas2D API.\r\n */\r\n\r\n/**\r\n * MultiStreamRecorder can record multiple videos in single container.\r\n * @summary Multi-videos recorder.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef MultiStreamRecorder\r\n * @class\r\n * @example\r\n * var options = {\r\n * mimeType: 'video/webm'\r\n * }\r\n * var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n *\r\n * // or\r\n * var blob = recorder.blob;\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams.\r\n * @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: \"video/webm\"}\r\n */\r\n\r\nfunction MultiStreamRecorder(arrayOfMediaStreams, options) {\r\n arrayOfMediaStreams = arrayOfMediaStreams || [];\r\n var self = this;\r\n\r\n var mixer;\r\n var mediaRecorder;\r\n\r\n options = options || {\r\n elementClass: 'multi-streams-mixer',\r\n mimeType: 'video/webm',\r\n video: {\r\n width: 360,\r\n height: 240\r\n }\r\n };\r\n\r\n if (!options.frameInterval) {\r\n options.frameInterval = 10;\r\n }\r\n\r\n if (!options.video) {\r\n options.video = {};\r\n }\r\n\r\n if (!options.video.width) {\r\n options.video.width = 360;\r\n }\r\n\r\n if (!options.video.height) {\r\n options.video.height = 240;\r\n }\r\n\r\n /**\r\n * This method records all MediaStreams.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n // github/muaz-khan/MultiStreamsMixer\r\n mixer = new MultiStreamsMixer(arrayOfMediaStreams, options.elementClass || 'multi-streams-mixer');\r\n\r\n if (getAllVideoTracks().length) {\r\n mixer.frameInterval = options.frameInterval || 10;\r\n mixer.width = options.video.width || 360;\r\n mixer.height = options.video.height || 240;\r\n mixer.startDrawingFrames();\r\n }\r\n\r\n if (options.previewStream && typeof options.previewStream === 'function') {\r\n options.previewStream(mixer.getMixedStream());\r\n }\r\n\r\n // record using MediaRecorder API\r\n mediaRecorder = new MediaStreamRecorder(mixer.getMixedStream(), options);\r\n mediaRecorder.record();\r\n };\r\n\r\n function getAllVideoTracks() {\r\n var tracks = [];\r\n arrayOfMediaStreams.forEach(function(stream) {\r\n getTracks(stream, 'video').forEach(function(track) {\r\n tracks.push(track);\r\n });\r\n });\r\n return tracks;\r\n }\r\n\r\n /**\r\n * This method stops recording MediaStream.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n if (!mediaRecorder) {\r\n return;\r\n }\r\n\r\n mediaRecorder.stop(function(blob) {\r\n self.blob = blob;\r\n\r\n callback(blob);\r\n\r\n self.clearRecordedData();\r\n });\r\n };\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.pause();\r\n }\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.resume();\r\n }\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n if (mediaRecorder) {\r\n mediaRecorder.clearRecordedData();\r\n mediaRecorder = null;\r\n }\r\n\r\n if (mixer) {\r\n mixer.releaseStreams();\r\n mixer = null;\r\n }\r\n };\r\n\r\n /**\r\n * Add extra media-streams to existing recordings.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams\r\n * @example\r\n * recorder.addStreams([newAudioStream, newVideoStream]);\r\n */\r\n this.addStreams = function(streams) {\r\n if (!streams) {\r\n throw 'First parameter is required.';\r\n }\r\n\r\n if (!(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n arrayOfMediaStreams.concat(streams);\r\n\r\n if (!mediaRecorder || !mixer) {\r\n return;\r\n }\r\n\r\n mixer.appendStreams(streams);\r\n\r\n if (options.previewStream && typeof options.previewStream === 'function') {\r\n options.previewStream(mixer.getMixedStream());\r\n }\r\n };\r\n\r\n /**\r\n * Reset videos during live recording. Replace old videos e.g. replace cameras with full-screen.\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @param {MediaStreams} mediaStreams - Array of MediaStreams\r\n * @example\r\n * recorder.resetVideoStreams([newVideo1, newVideo2]);\r\n */\r\n this.resetVideoStreams = function(streams) {\r\n if (!mixer) {\r\n return;\r\n }\r\n\r\n if (streams && !(streams instanceof Array)) {\r\n streams = [streams];\r\n }\r\n\r\n mixer.resetVideoStreams(streams);\r\n };\r\n\r\n /**\r\n * Returns MultiStreamsMixer\r\n * @method\r\n * @memberof MultiStreamRecorder\r\n * @example\r\n * let mixer = recorder.getMixer();\r\n * mixer.appendStreams([newStream]);\r\n */\r\n this.getMixer = function() {\r\n return mixer;\r\n };\r\n\r\n // for debugging\r\n this.name = 'MultiStreamRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.MultiStreamRecorder = MultiStreamRecorder;\r\n}\n\r\n// _____________________\r\n// RecordRTC.promises.js\r\n\r\n/**\r\n * RecordRTCPromisesHandler adds promises support in {@link RecordRTC}. Try a {@link https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/RecordRTCPromisesHandler.html|demo here}\r\n * @summary Promises for {@link RecordRTC}\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef RecordRTCPromisesHandler\r\n * @class\r\n * @example\r\n * var recorder = new RecordRTCPromisesHandler(mediaStream, options);\r\n * recorder.startRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n * // Note: You can access all RecordRTC API using \"recorder.recordRTC\" e.g. \r\n * recorder.recordRTC.onStateChanged = function(state) {};\r\n * recorder.recordRTC.setRecordingDuration(5000);\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc.\r\n * @param {object} config - {type:\"video\", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.}\r\n * @throws Will throw an error if \"new\" keyword is not used to initiate \"RecordRTCPromisesHandler\". Also throws error if first argument \"MediaStream\" is missing.\r\n * @requires {@link RecordRTC}\r\n */\r\n\r\nfunction RecordRTCPromisesHandler(mediaStream, options) {\r\n if (!this) {\r\n throw 'Use \"new RecordRTCPromisesHandler()\"';\r\n }\r\n\r\n if (typeof mediaStream === 'undefined') {\r\n throw 'First argument \"MediaStream\" is required.';\r\n }\r\n\r\n var self = this;\r\n\r\n /**\r\n * @property {Blob} blob - Access/reach the native {@link RecordRTC} object.\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let internal = recorder.recordRTC.getInternalRecorder();\r\n * alert(internal instanceof MediaStreamRecorder);\r\n * recorder.recordRTC.onStateChanged = function(state) {};\r\n */\r\n self.recordRTC = new RecordRTC(mediaStream, options);\r\n\r\n /**\r\n * This method records MediaStream.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.startRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.startRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.startRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method stops the recording.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * var blob = recorder.getBlob();\r\n * }).catch(errorCB);\r\n */\r\n this.stopRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.stopRecording(function(url) {\r\n self.blob = self.recordRTC.getBlob();\r\n\r\n if (!self.blob || !self.blob.size) {\r\n reject('Empty blob.', self.blob);\r\n return;\r\n }\r\n\r\n resolve(url);\r\n });\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method pauses the recording. You can resume recording using \"resumeRecording\" method.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.pauseRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.pauseRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.pauseRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method resumes the recording.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.resumeRecording()\r\n * .then(successCB)\r\n * .catch(errorCB);\r\n */\r\n this.resumeRecording = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.resumeRecording();\r\n resolve();\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns data-url for the recorded blob.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * recorder.getDataURL().then(function(dataURL) {\r\n * window.open(dataURL);\r\n * }).catch(errorCB);;\r\n * }).catch(errorCB);\r\n */\r\n this.getDataURL = function(callback) {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n self.recordRTC.getDataURL(function(dataURL) {\r\n resolve(dataURL);\r\n });\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns the recorded blob.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.stopRecording().then(function() {\r\n * recorder.getBlob().then(function(blob) {})\r\n * }).catch(errorCB);\r\n */\r\n this.getBlob = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getBlob());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method returns the internal recording object.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let internalRecorder = await recorder.getInternalRecorder();\r\n * if(internalRecorder instanceof MultiStreamRecorder) {\r\n * internalRecorder.addStreams([newAudioStream]);\r\n * internalRecorder.resetVideoStreams([screenStream]);\r\n * }\r\n * @returns {Object} \r\n */\r\n this.getInternalRecorder = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getInternalRecorder());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * This method resets the recorder. So that you can reuse single recorder instance many times.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * await recorder.reset();\r\n * recorder.startRecording(); // record again\r\n */\r\n this.reset = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.reset());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * Destroy RecordRTC instance. Clear all recorders and objects.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * recorder.destroy().then(successCB).catch(errorCB);\r\n */\r\n this.destroy = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.destroy());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * Get recorder's readonly state.\r\n * @method\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * let state = await recorder.getState();\r\n * // or\r\n * recorder.getState().then(state => { console.log(state); })\r\n * @returns {String} Returns recording state.\r\n */\r\n this.getState = function() {\r\n return new Promise(function(resolve, reject) {\r\n try {\r\n resolve(self.recordRTC.getState());\r\n } catch (e) {\r\n reject(e);\r\n }\r\n });\r\n };\r\n\r\n /**\r\n * @property {Blob} blob - Recorded data as \"Blob\" object.\r\n * @memberof RecordRTCPromisesHandler\r\n * @example\r\n * await recorder.stopRecording();\r\n * let blob = recorder.getBlob(); // or \"recorder.recordRTC.blob\"\r\n * invokeSaveAsDialog(blob);\r\n */\r\n this.blob = null;\r\n\r\n /**\r\n * RecordRTC version number\r\n * @property {String} version - Release version number.\r\n * @memberof RecordRTCPromisesHandler\r\n * @static\r\n * @readonly\r\n * @example\r\n * alert(recorder.version);\r\n */\r\n this.version = '5.6.2';\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.RecordRTCPromisesHandler = RecordRTCPromisesHandler;\r\n}\n\r\n// ______________________\r\n// WebAssemblyRecorder.js\r\n\r\n/**\r\n * WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos.\r\n * @summary Video recording feature in Chrome, Firefox and maybe Edge.\r\n * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT}\r\n * @author {@link https://MuazKhan.com|Muaz Khan}\r\n * @typedef WebAssemblyRecorder\r\n * @class\r\n * @example\r\n * var recorder = new WebAssemblyRecorder(mediaStream);\r\n * recorder.record();\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code}\r\n * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API.\r\n * @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', frameRate: 30, width: 1920, height: 1080, bitrate: 1024, realtime: true}\r\n */\r\nfunction WebAssemblyRecorder(stream, config) {\r\n // based on: github.com/GoogleChromeLabs/webm-wasm\r\n\r\n if (typeof ReadableStream === 'undefined' || typeof WritableStream === 'undefined') {\r\n // because it fixes readable/writable streams issues\r\n console.error('Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js');\r\n }\r\n\r\n config = config || {};\r\n\r\n config.width = config.width || 640;\r\n config.height = config.height || 480;\r\n config.frameRate = config.frameRate || 30;\r\n config.bitrate = config.bitrate || 1200;\r\n config.realtime = config.realtime || true;\r\n\r\n function createBufferURL(buffer, type) {\r\n return URL.createObjectURL(new Blob([buffer], {\r\n type: type || ''\r\n }));\r\n }\r\n\r\n var finished;\r\n\r\n function cameraStream() {\r\n return new ReadableStream({\r\n start: function(controller) {\r\n var cvs = document.createElement('canvas');\r\n var video = document.createElement('video');\r\n var first = true;\r\n video.srcObject = stream;\r\n video.muted = true;\r\n video.height = config.height;\r\n video.width = config.width;\r\n video.volume = 0;\r\n video.onplaying = function() {\r\n cvs.width = config.width;\r\n cvs.height = config.height;\r\n var ctx = cvs.getContext('2d');\r\n var frameTimeout = 1000 / config.frameRate;\r\n var cameraTimer = setInterval(function f() {\r\n if (finished) {\r\n clearInterval(cameraTimer);\r\n controller.close();\r\n }\r\n\r\n if (first) {\r\n first = false;\r\n if (config.onVideoProcessStarted) {\r\n config.onVideoProcessStarted();\r\n }\r\n }\r\n\r\n ctx.drawImage(video, 0, 0);\r\n if (controller._controlledReadableStream.state !== 'closed') {\r\n try {\r\n controller.enqueue(\r\n ctx.getImageData(0, 0, config.width, config.height)\r\n );\r\n } catch (e) {}\r\n }\r\n }, frameTimeout);\r\n };\r\n video.play();\r\n }\r\n });\r\n }\r\n\r\n var worker;\r\n\r\n function startRecording(stream, buffer) {\r\n if (!config.workerPath && !buffer) {\r\n finished = false;\r\n\r\n // is it safe to use @latest ?\r\n\r\n fetch(\r\n 'https://unpkg.com/webm-wasm@latest/dist/webm-worker.js'\r\n ).then(function(r) {\r\n r.arrayBuffer().then(function(buffer) {\r\n startRecording(stream, buffer);\r\n });\r\n });\r\n return;\r\n }\r\n\r\n if (!config.workerPath && buffer instanceof ArrayBuffer) {\r\n var blob = new Blob([buffer], {\r\n type: 'text/javascript'\r\n });\r\n config.workerPath = URL.createObjectURL(blob);\r\n }\r\n\r\n if (!config.workerPath) {\r\n console.error('workerPath parameter is missing.');\r\n }\r\n\r\n worker = new Worker(config.workerPath);\r\n\r\n worker.postMessage(config.webAssemblyPath || 'https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm');\r\n worker.addEventListener('message', function(event) {\r\n if (event.data === 'READY') {\r\n worker.postMessage({\r\n width: config.width,\r\n height: config.height,\r\n bitrate: config.bitrate || 1200,\r\n timebaseDen: config.frameRate || 30,\r\n realtime: config.realtime\r\n });\r\n\r\n cameraStream().pipeTo(new WritableStream({\r\n write: function(image) {\r\n if (finished) {\r\n console.error('Got image, but recorder is finished!');\r\n return;\r\n }\r\n\r\n worker.postMessage(image.data.buffer, [image.data.buffer]);\r\n }\r\n }));\r\n } else if (!!event.data) {\r\n if (!isPaused) {\r\n arrayOfBuffers.push(event.data);\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * This method records video.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.record();\r\n */\r\n this.record = function() {\r\n arrayOfBuffers = [];\r\n isPaused = false;\r\n this.blob = null;\r\n startRecording(stream);\r\n\r\n if (typeof config.initCallback === 'function') {\r\n config.initCallback();\r\n }\r\n };\r\n\r\n var isPaused;\r\n\r\n /**\r\n * This method pauses the recording process.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.pause();\r\n */\r\n this.pause = function() {\r\n isPaused = true;\r\n };\r\n\r\n /**\r\n * This method resumes the recording process.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.resume();\r\n */\r\n this.resume = function() {\r\n isPaused = false;\r\n };\r\n\r\n function terminate(callback) {\r\n if (!worker) {\r\n if (callback) {\r\n callback();\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Wait for null event data to indicate that the encoding is complete\r\n worker.addEventListener('message', function(event) {\r\n if (event.data === null) {\r\n worker.terminate();\r\n worker = null;\r\n\r\n if (callback) {\r\n callback();\r\n }\r\n }\r\n });\r\n\r\n worker.postMessage(null);\r\n }\r\n\r\n var arrayOfBuffers = [];\r\n\r\n /**\r\n * This method stops recording video.\r\n * @param {function} callback - Callback function, that is used to pass recorded blob back to the callee.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.stop(function(blob) {\r\n * video.src = URL.createObjectURL(blob);\r\n * });\r\n */\r\n this.stop = function(callback) {\r\n finished = true;\r\n\r\n var recorder = this;\r\n\r\n terminate(function() {\r\n recorder.blob = new Blob(arrayOfBuffers, {\r\n type: 'video/webm'\r\n });\r\n\r\n callback(recorder.blob);\r\n });\r\n };\r\n\r\n // for debugging\r\n this.name = 'WebAssemblyRecorder';\r\n this.toString = function() {\r\n return this.name;\r\n };\r\n\r\n /**\r\n * This method resets currently recorded data.\r\n * @method\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.clearRecordedData();\r\n */\r\n this.clearRecordedData = function() {\r\n arrayOfBuffers = [];\r\n isPaused = false;\r\n this.blob = null;\r\n\r\n // todo: if recording-ON then STOP it first\r\n };\r\n\r\n /**\r\n * @property {Blob} blob - The recorded blob object.\r\n * @memberof WebAssemblyRecorder\r\n * @example\r\n * recorder.stop(function(){\r\n * var blob = recorder.blob;\r\n * });\r\n */\r\n this.blob = null;\r\n}\r\n\r\nif (typeof RecordRTC !== 'undefined') {\r\n RecordRTC.WebAssemblyRecorder = WebAssemblyRecorder;\r\n}\n"],"names":["RecordRTC","mediaStream","config","RecordRTCConfiguration","type","self","this","initRecorder","initCallback","Recorder","GetRecorderType","mediaRecorder","record","setState","disableLogs","console","log","constructor","name","stopRecording","callback","state","resumeRecording","setTimeout","warn","stop","_callback","warningLog","__blob","Object","keys","forEach","key","blob","bytesToSize","size","url","URL","createObjectURL","e","call","autoWriteToDisk","getDataURL","dataURL","parameter","DiskStorage","Store","readFile","_blob","postMessage","FileReaderSync","readAsDataURL","_mediaRecorder","Worker","navigator","mozGetUserMedia","reader","FileReader","onload","event","target","result","webWorker","_function","Blob","toString","worker","revokeObjectURL","processInWebWorker","onmessage","data","handleRecordingDuration","counter","recordingDuration","onRecordingStopped","onStateChanged","WARNING","returnObject","startRecording","config2","version","clearRecordedData","pauseRecording","pause","resume","setRecordingDuration","getBlob","toURL","getInternalRecorder","save","fileName","invokeSaveAsDialog","getFromDisk","setAdvertisementArray","arrayOfWebPImages","advertisement","length","i","push","duration","image","bufferSize","sampleRate","buffer","reset","getState","destroy","disableLogsCache","Storage","AudioContextConstructor","close","prop","recorderType","audio","video","WhammyRecorder","CanvasRecorder","WebAssemblyRecorder","GifRecorder","StereoAudioRecorder","MediaStreamRecorder","getTracks","MediaRecorder","prototype","mimeType","split","bitsPerSecond","recorder","isChrome","isEdge","isOpera","ReadableStream","isMediaRecorderCompatible","isTypeSupported","Array","MultiStreamRecorder","isSafari","MRecordRTC","addStream","_mediaStream","mediaType","gif","audioRecorder","numberOfAudioChannels","timeSlice","onTimeStamp","newStream","videoTrack","isFirefox","MediaStream","addTrack","videoRecorder","canvas","frameInterval","workerPath","webAssemblyPath","frameRate","bitrate","isSingleRecorder","gifRecorder","quality","blobURL","output","callback00","webkitURL","_audioDataURL","_videoDataURL","writeToDisk","args","module","exports","Fetch","_type","replace","options","audioDataURL","videoDataURL","gifDataURL","audioBlob","videoBlob","gifBlob","that","global","window","userAgent","getUserMedia","error","arguments","document","documentElement","appendChild","createElement","captureStream","mozCaptureStream","obj","getContext","play","drawImage","toDataURL","style","HTMLVideoElement","location","protocol","href","hash","screen","width","height","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","msRequestAnimationFrame","lastTime","element","currTime","Date","getTime","timeToCall","Math","max","id","cancelAnimationFrame","webkitCancelAnimationFrame","mozCancelAnimationFrame","msCancelAnimationFrame","clearTimeout","AudioContext","webkitAudioContext","mozAudioContext","webkitGetUserMedia","indexOf","msSaveBlob","msSaveOrOpenBlob","opera","toLowerCase","test","isElectron","bytes","parseInt","floor","pow","toPrecision","file","fileExtension","splitted","fileFullName","round","random","hyperlink","download","body","click","dispatchEvent","MouseEvent","view","bubbles","cancelable","process","versions","electron","stream","kind","filter","t","setSrcObject","srcObject","mozSrcObject","webkitMediaStream","track","getSeekableBlob","inputBlob","EBML","Error","Reader","decoder","Decoder","tools","fileReader","decode","read","refinedMetadataBuf","makeMetadataSeekable","metadatas","cues","slice","metadataSize","newBlob","readAsArrayBuffer","appVersion","verOffset","ix","nAgt","fullVersion","parseFloat","majorVersion","substring","isNaN","arrayOfBlobs","updateTimeStamp","timestamps","getMimeType","secondObject","clearRecordedDataCB","getArrayOfBlobs","allStates","recorderHints","canRecordMimeType","ondataavailable","recordingCallback","getNativeBlob","onstart","onpause","onresume","onstop","onerror","manuallyStopped","timeslice","start","getAllStates","checkForInactiveTracks","looper","active","ended","isMediaStreamActive","jsAudioNode","leftchannel","rightchannel","recording","recordingLength","desiredSampRate","mergeLeftRightBuffers","mergeAudioBuffers","cb","interleaved","leftBuffers","rightBuffers","internalInterleavedLength","interpolateArray","newSampleRate","oldSampleRate","fitCount","newData","springFactor","Number","tmp","before","toFixed","after","ceil","atPoint","linearInterpolate","mergeBuffers","channelBuffer","rLength","Float64Array","offset","lng","set","writeUTFBytes","string","setUint8","charCodeAt","leftChannel","rightChannel","inputIndex","index","interleave","interleavedLength","ArrayBuffer","DataView","setUint32","setUint16","setInt16","noWorker","workerURL","terminate","resetVariables","isAudioProcessStarted","isPaused","byteLength","context","audioInput","createMediaStreamSource","legalBufferValues","JSON","stringify","createJavaScriptNode","createScriptProcessor","connect","intervalsBasedBuffers","left","right","onaudioprocess","disconnect","onAudioProcessStarted","inputBuffer","getChannelData","chLeft","Float32Array","chRight","createMediaStreamDestination","destination","htmlElement","html2canvas","isCanvasSupportsStreamCapturing","item","globalCanvas","mediaStreamRecorder","isRecording","_isChrome","webkitRTCPeerConnection","chrome","chromeVersion","matchArray","match","useWhammyRecorder","HTMLCanvasElement","CanvasRenderingContext2D","canvasMediaStream","webkitCaptureStream","mdStream","whammy","frames","drawCanvasFrame","getWebPImages","nodeName","framesLength","frame","idx","framesRemaining","onEncodingCallback","webp","compile","isPausedRecording","newCanvas","grabMouse","showMousePointer","onrendered","Whammy","Video","drawFrames","paused","isStopDrawing","dropBlackFrames","_frames","_framesToCheck","_pixTolerance","_frameTolerance","localCanvas","o","context2d","resultFrames","checkUntilNotBlack","endCheckFrame","sampleColor","maxColorDifference","sqrt","pixTolerance","frameTolerance","doNotCheckNext","functionToLoop","loop","f","matchPixCount","endPixCheck","maxPixCount","finishImage","Image","imageData","getImageData","pix","currentColor","r","g","b","src","concat","cloneNode","onloadedmetadata","muted","_this","WhammyVideo","whammyInWebWorker","getClusterData","clusterTimecode","clusterCounter","clusterFrames","map","block","flags","keyframe","invisible","lacing","discardable","trackNum","timecode","String","fromCharCode","join","makeSimpleBlock","numToBuffer","num","parts","Uint8Array","reverse","bitsToBuffer","bits","substr","generateEBML","json","ebml","len","zeroes","sizeToString","padded","getStrLength","unpadded","parseRIFF","chunks","webm","info","checkFrames","frameNumber","clusterDuration","cluster","riff","VP8","RIFF","WEBP","frameStart","c","parseWebP","atob","add","init","indexedDB","open","db","dbName","request","onError","onsuccess","setVersion","createObjectStore","putInDB","onupgradeneeded","dataBase","dataStoreName","transaction","getFromStore","portionName","objectStore","get","put","GIFEncoder","script","isHTMLObject","isLoadedMetaData","offsetWidth","offsetHeight","gifEncoder","setRepeat","setDelay","setQuality","onGifRecordingStarted","now","lastAnimationFrame","drawVideoFrame","time","clearedRecordedData","undefined","lastFrameTime","onGifPreview","addFrame","bin","autoplay","playsInline","MultiStreamsMixer","arrayOfMediaStreams","elementClass","videos","isStopDrawingFrames","opacity","position","zIndex","top","className","useGainNode","drawVideosToCanvas","videosLength","fullcanvas","remaining","x","y","onRender","getVideo","volume","resetVideoStreams","streams","startDrawingFrames","appendStreams","audioSource","audioContext","audioDestination","releaseStreams","gainNode","audioSources","source","clearRect","getMixedStream","mixedVideoStream","capturedStream","videoStream","getMixedVideoStream","mixedAudioStream","createGain","gain","value","audioTracksLength","getMixedAudioStream","mixer","tracks","previewStream","addStreams","getMixer","finished","cameraStream","controller","cvs","first","onplaying","ctx","frameTimeout","cameraTimer","setInterval","clearInterval","onVideoProcessStarted","_controlledReadableStream","enqueue","fetch","then","arrayBuffer","addEventListener","timebaseDen","realtime","pipeTo","WritableStream","write","arrayOfBuffers","RecordRTCPromisesHandler","recordRTC","Promise","resolve","reject"],"sourceRoot":""}