From 11036f735e655f85e9fc05e2c4d3d8e63b6db196 Mon Sep 17 00:00:00 2001 From: Maxime Robert Date: Thu, 3 Mar 2022 16:41:45 +0100 Subject: [PATCH] Add the possibility to push the video blobs in a writable stream --- README.md | 10 + RecordRTC.js | 246 ++++++++++++++---- RecordRTC.min.js | 8 +- dev/MediaStreamRecorder.js | 244 +++++++++++++---- simple-demos/index.html | 20 +- ...recording-to-file-stream-with-seeking.html | 174 +++++++++++++ 6 files changed, 582 insertions(+), 120 deletions(-) create mode 100644 simple-demos/screen-recording-to-file-stream-with-seeking.html diff --git a/README.md b/README.md index 9b67f2e5..683d62ff 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,16 @@ const recorder = RecordRTC(stream, { // returns blob via callback function ondataavailable: function(blob) {}, + // requires timeSlice above (or will default to 1000 otherwise) + // will write blobs to the WritableStream + // will disable ondataavailable and onTimeStamp + // will not keep blobs in memory. As a result, stopRecording will have empty blobs as parameter + writableStream: WritableStream, + + // callback called after the writableStream is closed + // useful, for example, to apply getSeekableBlob on the recorded video + onWritableStreamClosed: function() {}, + // auto stop recording if camera stops checkForInactiveTracks: false, diff --git a/RecordRTC.js b/RecordRTC.js index a71d5128..014e7570 100644 --- a/RecordRTC.js +++ b/RecordRTC.js @@ -1,6 +1,6 @@ 'use strict'; -// Last time updated: 2021-03-09 3:20:22 AM UTC +// Last time updated: 2022-03-03 3:04:56 PM UTC // ________________ // RecordRTC v5.6.2 @@ -2145,50 +2145,6 @@ function MediaStreamRecorder(mediaStream, config) { } } - // Dispatching OnDataAvailable Handler - mediaRecorder.ondataavailable = function(e) { - if (e.data) { - allStates.push('ondataavailable: ' + bytesToSize(e.data.size)); - } - - if (typeof config.timeSlice === 'number') { - if (e.data && e.data.size) { - arrayOfBlobs.push(e.data); - updateTimeStamp(); - - if (typeof config.ondataavailable === 'function') { - // intervals based blobs - var blob = config.getNativeBlob ? e.data : new Blob([e.data], { - type: getMimeType(recorderHints) - }); - config.ondataavailable(blob); - } - } - return; - } - - if (!e.data || !e.data.size || e.data.size < 100 || self.blob) { - // make sure that stopRecording always getting fired - // even if there is invalid data - if (self.recordingCallback) { - self.recordingCallback(new Blob([], { - type: getMimeType(recorderHints) - })); - self.recordingCallback = null; - } - return; - } - - self.blob = config.getNativeBlob ? e.data : new Blob([e.data], { - type: getMimeType(recorderHints) - }); - - if (self.recordingCallback) { - self.recordingCallback(self.blob); - self.recordingCallback = null; - } - }; - mediaRecorder.onstart = function() { allStates.push('started'); }; @@ -2203,6 +2159,16 @@ function MediaStreamRecorder(mediaStream, config) { mediaRecorder.onstop = function() { allStates.push('stopped'); + if (config.writableStream) { + Queue.enqueue(function() { + return config.writableStream.close() + .then(function() { + if (config.onWritableStreamClosed && typeof config.onWritableStreamClosed === 'function') { + config.onWritableStreamClosed(); + } + }); + }); + } }; mediaRecorder.onerror = function(error) { @@ -2257,18 +2223,72 @@ function MediaStreamRecorder(mediaStream, config) { } }; - if (typeof config.timeSlice === 'number') { - updateTimeStamp(); + if (config.writableStream) { + mediaRecorder.ondataavailable = function(e) { + Queue.enqueue(function() { + return config.writableStream.write(e.data); + }); + }; + config.timeSlice = config.timeSlice || 1000; mediaRecorder.start(config.timeSlice); } else { - // default is 60 minutes; enough? - // use config => {timeSlice: 1000} otherwise + // Dispatching OnDataAvailable Handler + mediaRecorder.ondataavailable = function(e) { + if (e.data) { + allStates.push('ondataavailable: ' + bytesToSize(e.data.size)); + } - mediaRecorder.start(3.6e+6); - } + if (typeof config.timeSlice === 'number') { + if (e.data && e.data.size) { + arrayOfBlobs.push(e.data); + updateTimeStamp(); + + if (typeof config.ondataavailable === 'function') { + // intervals based blobs + var blob = config.getNativeBlob ? e.data : new Blob([e.data], { + type: getMimeType(recorderHints) + }); + config.ondataavailable(blob); + } + } + return; + } - if (config.initCallback) { - config.initCallback(); // old code + if (!e.data || !e.data.size || e.data.size < 100 || self.blob) { + // make sure that stopRecording always getting fired + // even if there is invalid data + if (self.recordingCallback) { + self.recordingCallback(new Blob([], { + type: getMimeType(recorderHints) + })); + self.recordingCallback = null; + } + return; + } + + self.blob = config.getNativeBlob ? e.data : new Blob([e.data], { + type: getMimeType(recorderHints) + }); + + if (self.recordingCallback) { + self.recordingCallback(self.blob); + self.recordingCallback = null; + } + }; + + if (typeof config.timeSlice === 'number') { + updateTimeStamp(); + mediaRecorder.start(config.timeSlice); + } else { + // default is 60 minutes; enough? + // use config => {timeSlice: 1000} otherwise + + mediaRecorder.start(3.6e+6); + } + + if (config.initCallback) { + config.initCallback(); // old code + } } }; @@ -2460,8 +2480,8 @@ function MediaStreamRecorder(mediaStream, config) { return allStates; }; - // if any Track within the MediaStream is muted or not enabled at any time, - // the browser will only record black frames + // if any Track within the MediaStream is muted or not enabled at any time, + // the browser will only record black frames // or silence since that is the content produced by the Track // so we need to stopRecording as soon as any single track ends. if (typeof config.checkForInactiveTracks === 'undefined') { @@ -2499,6 +2519,122 @@ if (typeof RecordRTC !== 'undefined') { RecordRTC.MediaStreamRecorder = MediaStreamRecorder; } +/** + * From https://medium.com/@karenmarkosyan/how-to-manage-promises-into-dynamic-queue-with-vanilla-javascript-9d0d1f8d4df5 (+ Babel to convert to ES5) + * Allows resolving promises in the order they are added to the queue. + */ +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError('Cannot call a class as a function'); + } +} + +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ('value' in descriptor) { + descriptor.writable = true; + } + Object.defineProperty(target, descriptor.key, descriptor); + } +} + +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) { + _defineProperties(Constructor.prototype, protoProps); + } + if (staticProps) { + _defineProperties(Constructor, staticProps); + } + Object.defineProperty(Constructor, 'prototype', { + writable: false + }); + return Constructor; +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; +} +var Queue = /*#__PURE__*/ (function() { + function Queue() { + _classCallCheck(this, Queue); + } + + _createClass(Queue, null, [{ + key: 'enqueue', + value: function enqueue(promise) { + var _this = this; + + return new Promise(function(resolve, reject) { + _this.queue.push({ + promise: promise, + resolve: resolve, + reject: reject + }); + + _this.dequeue(); + }); + } + }, + { + key: 'dequeue', + value: function dequeue() { + var _this2 = this; + + if (this.workingOnPromise) { + return false; + } + + var item = this.queue.shift(); + + if (!item) { + return false; + } + + try { + this.workingOnPromise = true; + item + .promise() + .then(function(value) { + _this2.workingOnPromise = false; + item.resolve(value); + + _this2.dequeue(); + }) + .catch(function(err) { + _this2.workingOnPromise = false; + item.reject(err); + + _this2.dequeue(); + }); + } catch (err) { + this.workingOnPromise = false; + item.reject(err); + this.dequeue(); + } + + return true; + } + } + ]); + + return Queue; +})(); +_defineProperty(Queue, 'queue', []); +_defineProperty(Queue, 'workingOnPromise', false); + // source code from: http://typedarray.org/wp-content/projects/WebAudioRecorder/script.js // https://github.com/mattdiamond/Recorderjs#license-mit // ______________________ diff --git a/RecordRTC.min.js b/RecordRTC.min.js index c2ad3169..aeba3859 100644 --- a/RecordRTC.min.js +++ b/RecordRTC.min.js @@ -1,6 +1,6 @@ 'use strict'; -// Last time updated: 2021-03-09 3:20:23 AM UTC +// Last time updated: 2022-03-03 3:04:58 PM UTC // ________________ // RecordRTC v5.6.2 @@ -12,6 +12,6 @@ // MIT License - www.WebRTC-Experiment.com/licence // -------------------------------------------------- -"use strict";function RecordRTC(mediaStream,config){function startRecording(config2){return config.disableLogs||console.log("RecordRTC version: ",self.version),config2&&(config=new RecordRTCConfiguration(mediaStream,config2)),config.disableLogs||console.log("started recording "+config.type+" stream."),mediaRecorder?(mediaRecorder.clearRecordedData(),mediaRecorder.record(),setState("recording"),self.recordingDuration&&handleRecordingDuration(),self):(initRecorder(function(){self.recordingDuration&&handleRecordingDuration()}),self)}function initRecorder(initCallback){initCallback&&(config.initCallback=function(){initCallback(),initCallback=config.initCallback=null});var Recorder=new GetRecorderType(mediaStream,config);mediaRecorder=new Recorder(mediaStream,config),mediaRecorder.record(),setState("recording"),config.disableLogs||console.log("Initialized recorderType:",mediaRecorder.constructor.name,"for output-type:",config.type)}function stopRecording(callback){function _callback(__blob){if(!mediaRecorder)return void("function"==typeof callback.call?callback.call(self,""):callback(""));Object.keys(mediaRecorder).forEach(function(key){"function"!=typeof mediaRecorder[key]&&(self[key]=mediaRecorder[key])});var blob=mediaRecorder.blob;if(!blob){if(!__blob)throw"Recording failed.";mediaRecorder.blob=blob=__blob}if(blob&&!config.disableLogs&&console.log(blob.type,"->",bytesToSize(blob.size)),callback){var url;try{url=URL.createObjectURL(blob)}catch(e){}"function"==typeof callback.call?callback.call(self,url):callback(url)}config.autoWriteToDisk&&getDataURL(function(dataURL){var parameter={};parameter[config.type+"Blob"]=dataURL,DiskStorage.Store(parameter)})}return callback=callback||function(){},mediaRecorder?"paused"===self.state?(self.resumeRecording(),void setTimeout(function(){stopRecording(callback)},1)):("recording"===self.state||config.disableLogs||console.warn('Recording state should be: "recording", however current state is: ',self.state),config.disableLogs||console.log("Stopped recording "+config.type+" stream."),"gif"!==config.type?mediaRecorder.stop(_callback):(mediaRecorder.stop(),_callback()),void setState("stopped")):void warningLog()}function pauseRecording(){return mediaRecorder?"recording"!==self.state?void(config.disableLogs||console.warn("Unable to pause the recording. Recording state: ",self.state)):(setState("paused"),mediaRecorder.pause(),void(config.disableLogs||console.log("Paused recording."))):void warningLog()}function resumeRecording(){return mediaRecorder?"paused"!==self.state?void(config.disableLogs||console.warn("Unable to resume the recording. Recording state: ",self.state)):(setState("recording"),mediaRecorder.resume(),void(config.disableLogs||console.log("Resumed recording."))):void warningLog()}function readFile(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))}function getDataURL(callback,_mediaRecorder){function processInWebWorker(_function){try{var blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (eee) {"+_function.name+"(eee.data);}"],{type:"application/javascript"})),worker=new Worker(blob);return URL.revokeObjectURL(blob),worker}catch(e){}}if(!callback)throw"Pass a callback function over getDataURL.";var blob=_mediaRecorder?_mediaRecorder.blob:(mediaRecorder||{}).blob;if(!blob)return config.disableLogs||console.warn("Blob encoder did not finish its job yet."),void setTimeout(function(){getDataURL(callback,_mediaRecorder)},1e3);if("undefined"==typeof Worker||navigator.mozGetUserMedia){var reader=new FileReader;reader.readAsDataURL(blob),reader.onload=function(event){callback(event.target.result)}}else{var webWorker=processInWebWorker(readFile);webWorker.onmessage=function(event){callback(event.data)},webWorker.postMessage(blob)}}function handleRecordingDuration(counter){if(counter=counter||0,"paused"===self.state)return void setTimeout(function(){handleRecordingDuration(counter)},1e3);if("stopped"!==self.state){if(counter>=self.recordingDuration)return void stopRecording(self.onRecordingStopped);counter+=1e3,setTimeout(function(){handleRecordingDuration(counter)},1e3)}}function setState(state){self&&(self.state=state,"function"==typeof self.onStateChanged.call?self.onStateChanged.call(self,state):self.onStateChanged(state))}function warningLog(){config.disableLogs!==!0&&console.warn(WARNING)}if(!mediaStream)throw"First parameter is required.";config=config||{type:"video"},config=new RecordRTCConfiguration(mediaStream,config);var mediaRecorder,self=this,WARNING='It seems that recorder is destroyed or "startRecording" is not invoked for '+config.type+" recorder.",returnObject={startRecording:startRecording,stopRecording:stopRecording,pauseRecording:pauseRecording,resumeRecording:resumeRecording,initRecorder:initRecorder,setRecordingDuration:function(recordingDuration,callback){if("undefined"==typeof recordingDuration)throw"recordingDuration is required.";if("number"!=typeof recordingDuration)throw"recordingDuration must be a number.";return self.recordingDuration=recordingDuration,self.onRecordingStopped=callback||function(){},{onRecordingStopped:function(callback){self.onRecordingStopped=callback}}},clearRecordedData:function(){return mediaRecorder?(mediaRecorder.clearRecordedData(),void(config.disableLogs||console.log("Cleared old recorded data."))):void warningLog()},getBlob:function(){return mediaRecorder?mediaRecorder.blob:void warningLog()},getDataURL:getDataURL,toURL:function(){return mediaRecorder?URL.createObjectURL(mediaRecorder.blob):void warningLog()},getInternalRecorder:function(){return mediaRecorder},save:function(fileName){return mediaRecorder?void invokeSaveAsDialog(mediaRecorder.blob,fileName):void warningLog()},getFromDisk:function(callback){return mediaRecorder?void RecordRTC.getFromDisk(config.type,callback):void warningLog()},setAdvertisementArray:function(arrayOfWebPImages){config.advertisement=[];for(var length=arrayOfWebPImages.length,i=0;i=0)}function getTracks(stream,kind){return stream&&stream.getTracks?stream.getTracks().filter(function(t){return t.kind===(kind||"audio")}):[]}function setSrcObject(stream,element){"srcObject"in element?element.srcObject=stream:"mozSrcObject"in element?element.mozSrcObject=stream:element.srcObject=stream}function getSeekableBlob(inputBlob,callback){if("undefined"==typeof EBML)throw new Error("Please link: https://www.webrtc-experiment.com/EBML.js");var reader=new EBML.Reader,decoder=new EBML.Decoder,tools=EBML.tools,fileReader=new FileReader;fileReader.onload=function(e){var ebmlElms=decoder.decode(this.result);ebmlElms.forEach(function(element){reader.read(element)}),reader.stop();var refinedMetadataBuf=tools.makeMetadataSeekable(reader.metadatas,reader.duration,reader.cues),body=this.result.slice(reader.metadataSize),newBlob=new Blob([refinedMetadataBuf,body],{type:"video/webm"});callback(newBlob)},fileReader.readAsArrayBuffer(inputBlob)}function isMediaRecorderCompatible(){if(isFirefox||isSafari||isEdge)return!0;var verOffset,ix,nAgt=(navigator.appVersion,navigator.userAgent),fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10);return(isChrome||isOpera)&&(verOffset=nAgt.indexOf("Chrome"),fullVersion=nAgt.substring(verOffset+7)),(ix=fullVersion.indexOf(";"))!==-1&&(fullVersion=fullVersion.substring(0,ix)),(ix=fullVersion.indexOf(" "))!==-1&&(fullVersion=fullVersion.substring(0,ix)),majorVersion=parseInt(""+fullVersion,10),isNaN(majorVersion)&&(fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10)),majorVersion>=49}function MediaStreamRecorder(mediaStream,config){function updateTimeStamp(){self.timestamps.push((new Date).getTime()),"function"==typeof config.onTimeStamp&&config.onTimeStamp(self.timestamps[self.timestamps.length-1],self.timestamps)}function getMimeType(secondObject){return mediaRecorder&&mediaRecorder.mimeType?mediaRecorder.mimeType:secondObject.mimeType||"video/webm"}function clearRecordedDataCB(){arrayOfBlobs=[],mediaRecorder=null,self.timestamps=[]}function isMediaStreamActive(){if("active"in mediaStream){if(!mediaStream.active)return!1}else if("ended"in mediaStream&&mediaStream.ended)return!1;return!0}var self=this;if("undefined"==typeof mediaStream)throw'First argument "MediaStream" is required.';if("undefined"==typeof MediaRecorder)throw"Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.";if(config=config||{mimeType:"video/webm"},"audio"===config.type){if(getTracks(mediaStream,"video").length&&getTracks(mediaStream,"audio").length){var stream;navigator.mozGetUserMedia?(stream=new MediaStream,stream.addTrack(getTracks(mediaStream,"audio")[0])):stream=new MediaStream(getTracks(mediaStream,"audio")),mediaStream=stream}config.mimeType&&config.mimeType.toString().toLowerCase().indexOf("audio")!==-1||(config.mimeType=isChrome?"audio/webm":"audio/ogg"),config.mimeType&&"audio/ogg"!==config.mimeType.toString().toLowerCase()&&navigator.mozGetUserMedia&&(config.mimeType="audio/ogg")}var arrayOfBlobs=[];this.getArrayOfBlobs=function(){return arrayOfBlobs},this.record=function(){self.blob=null,self.clearRecordedData(),self.timestamps=[],allStates=[],arrayOfBlobs=[];var recorderHints=config;config.disableLogs||console.log("Passing following config over MediaRecorder API.",recorderHints),mediaRecorder&&(mediaRecorder=null),isChrome&&!isMediaRecorderCompatible()&&(recorderHints="video/vp8"),"function"==typeof MediaRecorder.isTypeSupported&&recorderHints.mimeType&&(MediaRecorder.isTypeSupported(recorderHints.mimeType)||(config.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",recorderHints.mimeType),recorderHints.mimeType="audio"===config.type?"audio/webm":"video/webm"));try{mediaRecorder=new MediaRecorder(mediaStream,recorderHints),config.mimeType=recorderHints.mimeType}catch(e){mediaRecorder=new MediaRecorder(mediaStream)}recorderHints.mimeType&&!MediaRecorder.isTypeSupported&&"canRecordMimeType"in mediaRecorder&&mediaRecorder.canRecordMimeType(recorderHints.mimeType)===!1&&(config.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",recorderHints.mimeType)),mediaRecorder.ondataavailable=function(e){if(e.data&&allStates.push("ondataavailable: "+bytesToSize(e.data.size)),"number"!=typeof config.timeSlice){if(!e.data||!e.data.size||e.data.size<100||self.blob)return void(self.recordingCallback&&(self.recordingCallback(new Blob([],{type:getMimeType(recorderHints)})),self.recordingCallback=null));self.blob=config.getNativeBlob?e.data:new Blob([e.data],{type:getMimeType(recorderHints)}),self.recordingCallback&&(self.recordingCallback(self.blob),self.recordingCallback=null)}else if(e.data&&e.data.size&&(arrayOfBlobs.push(e.data),updateTimeStamp(),"function"==typeof config.ondataavailable)){var blob=config.getNativeBlob?e.data:new Blob([e.data],{type:getMimeType(recorderHints)});config.ondataavailable(blob)}},mediaRecorder.onstart=function(){allStates.push("started")},mediaRecorder.onpause=function(){allStates.push("paused")},mediaRecorder.onresume=function(){allStates.push("resumed")},mediaRecorder.onstop=function(){allStates.push("stopped")},mediaRecorder.onerror=function(error){error&&(error.name||(error.name="UnknownError"),allStates.push("error: "+error),config.disableLogs||(error.name.toString().toLowerCase().indexOf("invalidstate")!==-1?console.error("The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.",error):error.name.toString().toLowerCase().indexOf("notsupported")!==-1?console.error("MIME type (",recorderHints.mimeType,") is not supported.",error):error.name.toString().toLowerCase().indexOf("security")!==-1?console.error("MediaRecorder security error",error):"OutOfMemory"===error.name?console.error("The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.",error):"IllegalStreamModification"===error.name?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):"OtherRecordingError"===error.name?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):"GenericError"===error.name?console.error("The UA cannot provide the codec or recording option that has been requested.",error):console.error("MediaRecorder Error",error)),function(looper){return!self.manuallyStopped&&mediaRecorder&&"inactive"===mediaRecorder.state?(delete config.timeslice,void mediaRecorder.start(6e5)):void setTimeout(looper,1e3)}(),"inactive"!==mediaRecorder.state&&"stopped"!==mediaRecorder.state&&mediaRecorder.stop())},"number"==typeof config.timeSlice?(updateTimeStamp(),mediaRecorder.start(config.timeSlice)):mediaRecorder.start(36e5),config.initCallback&&config.initCallback()},this.timestamps=[],this.stop=function(callback){callback=callback||function(){},self.manuallyStopped=!0,mediaRecorder&&(this.recordingCallback=callback,"recording"===mediaRecorder.state&&mediaRecorder.stop(),"number"==typeof config.timeSlice&&setTimeout(function(){self.blob=new Blob(arrayOfBlobs,{type:getMimeType(config)}),self.recordingCallback(self.blob)},100))},this.pause=function(){mediaRecorder&&"recording"===mediaRecorder.state&&mediaRecorder.pause()},this.resume=function(){mediaRecorder&&"paused"===mediaRecorder.state&&mediaRecorder.resume()},this.clearRecordedData=function(){mediaRecorder&&"recording"===mediaRecorder.state&&self.stop(clearRecordedDataCB),clearRecordedDataCB()};var mediaRecorder;this.getInternalRecorder=function(){return mediaRecorder},this.blob=null,this.getState=function(){return mediaRecorder?mediaRecorder.state||"inactive":"inactive"};var allStates=[];this.getAllStates=function(){return allStates},"undefined"==typeof config.checkForInactiveTracks&&(config.checkForInactiveTracks=!1);var self=this;!function looper(){if(mediaRecorder&&config.checkForInactiveTracks!==!1)return isMediaStreamActive()===!1?(config.disableLogs||console.log("MediaStream seems stopped."),void self.stop()):void setTimeout(looper,1e3)}(),this.name="MediaStreamRecorder",this.toString=function(){return this.name}}function StereoAudioRecorder(mediaStream,config){function isMediaStreamActive(){if(config.checkForInactiveTracks===!1)return!0;if("active"in mediaStream){if(!mediaStream.active)return!1}else if("ended"in mediaStream&&mediaStream.ended)return!1;return!0}function mergeLeftRightBuffers(config,callback){function mergeAudioBuffers(config,cb){function interpolateArray(data,newSampleRate,oldSampleRate){var fitCount=Math.round(data.length*(newSampleRate/oldSampleRate)),newData=[],springFactor=Number((data.length-1)/(fitCount-1));newData[0]=data[0];for(var i=1;i96e3)&&(config.disableLogs||console.log("sample-rate must be under range 22050 and 96000.")),config.disableLogs||config.desiredSampRate&&console.log("Desired sample-rate: "+config.desiredSampRate);var isPaused=!1;this.pause=function(){isPaused=!0},this.resume=function(){if(isMediaStreamActive()===!1)throw"Please make sure MediaStream is active.";return recording?void(isPaused=!1):(config.disableLogs||console.log("Seems recording has been restarted."),void this.record())},this.clearRecordedData=function(){config.checkForInactiveTracks=!1,recording&&this.stop(clearRecordedDataCB),clearRecordedDataCB()},this.name="StereoAudioRecorder",this.toString=function(){return this.name};var isAudioProcessStarted=!1;jsAudioNode.onaudioprocess=onAudioProcessDataAvailable,context.createMediaStreamDestination?jsAudioNode.connect(context.createMediaStreamDestination()):jsAudioNode.connect(context.destination),this.leftchannel=leftchannel,this.rightchannel=rightchannel,this.numberOfAudioChannels=numberOfAudioChannels,this.desiredSampRate=desiredSampRate,this.sampleRate=sampleRate,self.recordingLength=recordingLength;var intervalsBasedBuffers={left:[],right:[],recordingLength:0}}function CanvasRecorder(htmlElement,config){function clearRecordedDataCB(){whammy.frames=[],isRecording=!1,isPausedRecording=!1}function cloneCanvas(){var newCanvas=document.createElement("canvas"),context=newCanvas.getContext("2d");return newCanvas.width=htmlElement.width,newCanvas.height=htmlElement.height,context.drawImage(htmlElement,0,0),newCanvas}function drawCanvasFrame(){if(isPausedRecording)return lastTime=(new Date).getTime(),setTimeout(drawCanvasFrame,500);if("canvas"===htmlElement.nodeName.toLowerCase()){var duration=(new Date).getTime()-lastTime;return lastTime=(new Date).getTime(),whammy.frames.push({image:cloneCanvas(),duration:duration}),void(isRecording&&setTimeout(drawCanvasFrame,config.frameInterval))}html2canvas(htmlElement,{grabMouse:"undefined"==typeof config.showMousePointer||config.showMousePointer,onrendered:function(canvas){var duration=(new Date).getTime()-lastTime;return duration?(lastTime=(new Date).getTime(),whammy.frames.push({image:canvas.toDataURL("image/webp",1),duration:duration}),void(isRecording&&setTimeout(drawCanvasFrame,config.frameInterval))):setTimeout(drawCanvasFrame,config.frameInterval)}})}if("undefined"==typeof html2canvas)throw"Please link: https://www.webrtc-experiment.com/screenshot.js";config=config||{},config.frameInterval||(config.frameInterval=10);var isCanvasSupportsStreamCapturing=!1;["captureStream","mozCaptureStream","webkitCaptureStream"].forEach(function(item){item in document.createElement("canvas")&&(isCanvasSupportsStreamCapturing=!0)});var _isChrome=!(!window.webkitRTCPeerConnection&&!window.webkitGetUserMedia||!window.chrome),chromeVersion=50,matchArray=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);_isChrome&&matchArray&&matchArray[2]&&(chromeVersion=parseInt(matchArray[2],10)),_isChrome&&chromeVersion<52&&(isCanvasSupportsStreamCapturing=!1),config.useWhammyRecorder&&(isCanvasSupportsStreamCapturing=!1);var globalCanvas,mediaStreamRecorder;if(isCanvasSupportsStreamCapturing)if(config.disableLogs||console.log("Your browser supports both MediRecorder API and canvas.captureStream!"),htmlElement instanceof HTMLCanvasElement)globalCanvas=htmlElement;else{if(!(htmlElement instanceof CanvasRenderingContext2D))throw"Please pass either HTMLCanvasElement or CanvasRenderingContext2D.";globalCanvas=htmlElement.canvas}else navigator.mozGetUserMedia&&(config.disableLogs||console.error("Canvas recording is NOT supported in Firefox."));var isRecording;this.record=function(){if(isRecording=!0,isCanvasSupportsStreamCapturing&&!config.useWhammyRecorder){var canvasMediaStream;"captureStream"in globalCanvas?canvasMediaStream=globalCanvas.captureStream(25):"mozCaptureStream"in globalCanvas?canvasMediaStream=globalCanvas.mozCaptureStream(25):"webkitCaptureStream"in globalCanvas&&(canvasMediaStream=globalCanvas.webkitCaptureStream(25));try{var mdStream=new MediaStream;mdStream.addTrack(getTracks(canvasMediaStream,"video")[0]),canvasMediaStream=mdStream}catch(e){}if(!canvasMediaStream)throw"captureStream API are NOT available.";mediaStreamRecorder=new MediaStreamRecorder(canvasMediaStream,{mimeType:config.mimeType||"video/webm"}),mediaStreamRecorder.record()}else whammy.frames=[],lastTime=(new Date).getTime(),drawCanvasFrame();config.initCallback&&config.initCallback()},this.getWebPImages=function(callback){if("canvas"!==htmlElement.nodeName.toLowerCase())return void callback();var framesLength=whammy.frames.length;whammy.frames.forEach(function(frame,idx){var framesRemaining=framesLength-idx;config.disableLogs||console.log(framesRemaining+"/"+framesLength+" frames remaining"),config.onEncodingCallback&&config.onEncodingCallback(framesRemaining,framesLength);var webp=frame.image.toDataURL("image/webp",1);whammy.frames[idx].image=webp}),config.disableLogs||console.log("Generating WebM"),callback()},this.stop=function(callback){isRecording=!1;var that=this;return isCanvasSupportsStreamCapturing&&mediaStreamRecorder?void mediaStreamRecorder.stop(callback):void this.getWebPImages(function(){whammy.compile(function(blob){config.disableLogs||console.log("Recording finished!"),that.blob=blob,that.blob.forEach&&(that.blob=new Blob([],{type:"video/webm"})),callback&&callback(that.blob),whammy.frames=[]})})};var isPausedRecording=!1;this.pause=function(){if(isPausedRecording=!0,mediaStreamRecorder instanceof MediaStreamRecorder)return void mediaStreamRecorder.pause()},this.resume=function(){return isPausedRecording=!1,mediaStreamRecorder instanceof MediaStreamRecorder?void mediaStreamRecorder.resume():void(isRecording||this.record())},this.clearRecordedData=function(){isRecording&&this.stop(clearRecordedDataCB),clearRecordedDataCB()},this.name="CanvasRecorder",this.toString=function(){return this.name};var lastTime=(new Date).getTime(),whammy=new Whammy.Video(100)}function WhammyRecorder(mediaStream,config){function drawFrames(frameInterval){frameInterval="undefined"!=typeof frameInterval?frameInterval:10;var duration=(new Date).getTime()-lastTime;return duration?isPausedRecording?(lastTime=(new Date).getTime(),setTimeout(drawFrames,100)):(lastTime=(new Date).getTime(),video.paused&&video.play(),context.drawImage(video,0,0,canvas.width,canvas.height),whammy.frames.push({duration:duration,image:canvas.toDataURL("image/webp")}),void(isStopDrawing||setTimeout(drawFrames,frameInterval,frameInterval))):setTimeout(drawFrames,frameInterval,frameInterval)}function asyncLoop(o){var i=-1,length=o.length;!function loop(){return i++,i===length?void o.callback():void setTimeout(function(){o.functionToLoop(loop,i)},1)}()}function dropBlackFrames(_frames,_framesToCheck,_pixTolerance,_frameTolerance,callback){var localCanvas=document.createElement("canvas");localCanvas.width=canvas.width,localCanvas.height=canvas.height;var context2d=localCanvas.getContext("2d"),resultFrames=[],checkUntilNotBlack=_framesToCheck===-1,endCheckFrame=_framesToCheck&&_framesToCheck>0&&_framesToCheck<=_frames.length?_framesToCheck:_frames.length,sampleColor={r:0,g:0,b:0},maxColorDifference=Math.sqrt(Math.pow(255,2)+Math.pow(255,2)+Math.pow(255,2)),pixTolerance=_pixTolerance&&_pixTolerance>=0&&_pixTolerance<=1?_pixTolerance:0,frameTolerance=_frameTolerance&&_frameTolerance>=0&&_frameTolerance<=1?_frameTolerance:0,doNotCheckNext=!1;asyncLoop({length:endCheckFrame,functionToLoop:function(loop,f){var matchPixCount,endPixCheck,maxPixCount,finishImage=function(){!doNotCheckNext&&maxPixCount-matchPixCount<=maxPixCount*frameTolerance||(checkUntilNotBlack&&(doNotCheckNext=!0),resultFrames.push(_frames[f])),loop()};if(doNotCheckNext)finishImage();else{var image=new Image;image.onload=function(){context2d.drawImage(image,0,0,canvas.width,canvas.height);var imageData=context2d.getImageData(0,0,canvas.width,canvas.height);matchPixCount=0,endPixCheck=imageData.data.length,maxPixCount=imageData.data.length/4;for(var pix=0;pix1?2*remaining[0].width:remaining[0].width;var height=1;3!==videosLength&&4!==videosLength||(height=2),5!==videosLength&&6!==videosLength||(height=3),7!==videosLength&&8!==videosLength||(height=4),9!==videosLength&&10!==videosLength||(height=5),canvas.height=remaining[0].height*height}else canvas.width=self.width||360,canvas.height=self.height||240;fullcanvas&&fullcanvas instanceof HTMLVideoElement&&drawImage(fullcanvas),remaining.forEach(function(video,idx){drawImage(video,idx)}),setTimeout(drawVideosToCanvas,self.frameInterval)}}function drawImage(video,idx){if(!isStopDrawingFrames){var x=0,y=0,width=video.width,height=video.height;1===idx&&(x=video.width),2===idx&&(y=video.height),3===idx&&(x=video.width,y=video.height),4===idx&&(y=2*video.height),5===idx&&(x=video.width,y=2*video.height),6===idx&&(y=3*video.height),7===idx&&(x=video.width,y=3*video.height),"undefined"!=typeof video.stream.left&&(x=video.stream.left),"undefined"!=typeof video.stream.top&&(y=video.stream.top),"undefined"!=typeof video.stream.width&&(width=video.stream.width),"undefined"!=typeof video.stream.height&&(height=video.stream.height),context.drawImage(video,x,y,width,height),"function"==typeof video.stream.onRender&&video.stream.onRender(context,x,y,width,height,idx)}}function getMixedStream(){isStopDrawingFrames=!1;var mixedVideoStream=getMixedVideoStream(),mixedAudioStream=getMixedAudioStream();mixedAudioStream&&mixedAudioStream.getTracks().filter(function(t){return"audio"===t.kind}).forEach(function(track){mixedVideoStream.addTrack(track)});var fullcanvas;return arrayOfMediaStreams.forEach(function(stream){stream.fullcanvas&&(fullcanvas=!0)}),mixedVideoStream}function getMixedVideoStream(){resetVideoStreams();var capturedStream;"captureStream"in canvas?capturedStream=canvas.captureStream():"mozCaptureStream"in canvas?capturedStream=canvas.mozCaptureStream():self.disableLogs||console.error("Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features");var videoStream=new MediaStream;return capturedStream.getTracks().filter(function(t){return"video"===t.kind}).forEach(function(track){videoStream.addTrack(track)}),canvas.stream=videoStream,videoStream}function getMixedAudioStream(){Storage.AudioContextConstructor||(Storage.AudioContextConstructor=new Storage.AudioContext),self.audioContext=Storage.AudioContextConstructor,self.audioSources=[],self.useGainNode===!0&&(self.gainNode=self.audioContext.createGain(),self.gainNode.connect(self.audioContext.destination),self.gainNode.gain.value=0);var audioTracksLength=0;if(arrayOfMediaStreams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length){audioTracksLength++;var audioSource=self.audioContext.createMediaStreamSource(stream);self.useGainNode===!0&&audioSource.connect(self.gainNode),self.audioSources.push(audioSource)}}),audioTracksLength)return self.audioDestination=self.audioContext.createMediaStreamDestination(),self.audioSources.forEach(function(audioSource){audioSource.connect(self.audioDestination)}),self.audioDestination.stream}function getVideo(stream){var video=document.createElement("video");return setSrcObject(stream,video),video.className=elementClass,video.muted=!0,video.volume=0,video.width=stream.width||self.width||360,video.height=stream.height||self.height||240,video.play(),video}function resetVideoStreams(streams){videos=[],streams=streams||arrayOfMediaStreams,streams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video)}})}var browserFakeUserAgent="Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";!function(that){"undefined"==typeof RecordRTC&&that&&"undefined"==typeof window&&"undefined"!=typeof global&&(global.navigator={userAgent:browserFakeUserAgent,getUserMedia:function(){}},global.console||(global.console={}),"undefined"!=typeof global.console.log&&"undefined"!=typeof global.console.error||(global.console.error=global.console.log=global.console.log||function(){console.log(arguments)}),"undefined"==typeof document&&(that.document={documentElement:{appendChild:function(){return""}}},document.createElement=document.captureStream=document.mozCaptureStream=function(){var obj={getContext:function(){return obj},play:function(){},pause:function(){},drawImage:function(){},toDataURL:function(){return""},style:{}};return obj},that.HTMLVideoElement=function(){}),"undefined"==typeof location&&(that.location={protocol:"file:",href:"",hash:""}),"undefined"==typeof screen&&(that.screen={width:0,height:0}),"undefined"==typeof URL&&(that.URL={createObjectURL:function(){return""},revokeObjectURL:function(){return""}}),that.window=global)}("undefined"!=typeof global?global:null),elementClass=elementClass||"multi-streams-mixer";var videos=[],isStopDrawingFrames=!1,canvas=document.createElement("canvas"),context=canvas.getContext("2d");canvas.style.opacity=0,canvas.style.position="absolute",canvas.style.zIndex=-1,canvas.style.top="-1000em",canvas.style.left="-1000em",canvas.className=elementClass,(document.body||document.documentElement).appendChild(canvas),this.disableLogs=!1,this.frameInterval=10,this.width=360,this.height=240,this.useGainNode=!0;var self=this,AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;"undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"!=typeof navigator&&"undefined"==typeof navigator.getUserMedia&&("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia));var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&"undefined"==typeof MediaStream.prototype.stop&&(MediaStream.prototype.stop=function(){this.getTracks().forEach(function(track){track.stop()})});var Storage={};"undefined"!=typeof AudioContext?Storage.AudioContext=AudioContext:"undefined"!=typeof webkitAudioContext&&(Storage.AudioContext=webkitAudioContext),this.startDrawingFrames=function(){drawVideosToCanvas()},this.appendStreams=function(streams){if(!streams)throw"First parameter is required.";streams instanceof Array||(streams=[streams]),streams.forEach(function(stream){var newStream=new MediaStream;if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video),newStream.addTrack(stream.getTracks().filter(function(t){return"video"===t.kind})[0])}if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length){var audioSource=self.audioContext.createMediaStreamSource(stream);self.audioDestination=self.audioContext.createMediaStreamDestination(),audioSource.connect(self.audioDestination),newStream.addTrack(self.audioDestination.stream.getTracks().filter(function(t){return"audio"===t.kind})[0])}arrayOfMediaStreams.push(newStream)})},this.releaseStreams=function(){videos=[],isStopDrawingFrames=!0,self.gainNode&&(self.gainNode.disconnect(),self.gainNode=null),self.audioSources.length&&(self.audioSources.forEach(function(source){source.disconnect()}),self.audioSources=[]),self.audioDestination&&(self.audioDestination.disconnect(),self.audioDestination=null),self.audioContext&&self.audioContext.close(),self.audioContext=null,context.clearRect(0,0,canvas.width,canvas.height),canvas.stream&&(canvas.stream.stop(),canvas.stream=null)},this.resetVideoStreams=function(streams){!streams||streams instanceof Array||(streams=[streams]),resetVideoStreams(streams)},this.name="MultiStreamsMixer",this.toString=function(){return this.name},this.getMixedStream=getMixedStream}function MultiStreamRecorder(arrayOfMediaStreams,options){function getAllVideoTracks(){var tracks=[];return arrayOfMediaStreams.forEach(function(stream){getTracks(stream,"video").forEach(function(track){tracks.push(track)})}),tracks}arrayOfMediaStreams=arrayOfMediaStreams||[];var mixer,mediaRecorder,self=this;options=options||{elementClass:"multi-streams-mixer",mimeType:"video/webm",video:{width:360,height:240}},options.frameInterval||(options.frameInterval=10),options.video||(options.video={}),options.video.width||(options.video.width=360),options.video.height||(options.video.height=240),this.record=function(){mixer=new MultiStreamsMixer(arrayOfMediaStreams,options.elementClass||"multi-streams-mixer"),getAllVideoTracks().length&&(mixer.frameInterval=options.frameInterval||10,mixer.width=options.video.width||360,mixer.height=options.video.height||240,mixer.startDrawingFrames()),options.previewStream&&"function"==typeof options.previewStream&&options.previewStream(mixer.getMixedStream()),mediaRecorder=new MediaStreamRecorder(mixer.getMixedStream(),options),mediaRecorder.record()},this.stop=function(callback){mediaRecorder&&mediaRecorder.stop(function(blob){self.blob=blob,callback(blob),self.clearRecordedData()})},this.pause=function(){mediaRecorder&&mediaRecorder.pause()},this.resume=function(){mediaRecorder&&mediaRecorder.resume()},this.clearRecordedData=function(){mediaRecorder&&(mediaRecorder.clearRecordedData(),mediaRecorder=null),mixer&&(mixer.releaseStreams(),mixer=null)},this.addStreams=function(streams){if(!streams)throw"First parameter is required.";streams instanceof Array||(streams=[streams]),arrayOfMediaStreams.concat(streams),mediaRecorder&&mixer&&(mixer.appendStreams(streams),options.previewStream&&"function"==typeof options.previewStream&&options.previewStream(mixer.getMixedStream()))},this.resetVideoStreams=function(streams){mixer&&(!streams||streams instanceof Array||(streams=[streams]),mixer.resetVideoStreams(streams))},this.getMixer=function(){return mixer},this.name="MultiStreamRecorder",this.toString=function(){return this.name}}function RecordRTCPromisesHandler(mediaStream,options){if(!this)throw'Use "new RecordRTCPromisesHandler()"';if("undefined"==typeof mediaStream)throw'First argument "MediaStream" is required.';var self=this;self.recordRTC=new RecordRTC(mediaStream,options),this.startRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.startRecording(),resolve()}catch(e){reject(e)}})},this.stopRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.stopRecording(function(url){return self.blob=self.recordRTC.getBlob(),self.blob&&self.blob.size?void resolve(url):void reject("Empty blob.",self.blob)})}catch(e){reject(e)}})},this.pauseRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.pauseRecording(),resolve()}catch(e){reject(e)}})},this.resumeRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.resumeRecording(),resolve()}catch(e){reject(e)}})},this.getDataURL=function(callback){return new Promise(function(resolve,reject){try{self.recordRTC.getDataURL(function(dataURL){resolve(dataURL)})}catch(e){reject(e)}})},this.getBlob=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getBlob())}catch(e){reject(e)}})},this.getInternalRecorder=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getInternalRecorder())}catch(e){reject(e)}})},this.reset=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.reset())}catch(e){reject(e)}})},this.destroy=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.destroy())}catch(e){reject(e)}})},this.getState=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getState())}catch(e){reject(e)}})},this.blob=null,this.version="5.6.2"}function WebAssemblyRecorder(stream,config){function cameraStream(){return new ReadableStream({start:function(controller){var cvs=document.createElement("canvas"),video=document.createElement("video"),first=!0;video.srcObject=stream,video.muted=!0,video.height=config.height,video.width=config.width,video.volume=0,video.onplaying=function(){cvs.width=config.width,cvs.height=config.height;var ctx=cvs.getContext("2d"),frameTimeout=1e3/config.frameRate,cameraTimer=setInterval(function(){if(finished&&(clearInterval(cameraTimer),controller.close()),first&&(first=!1,config.onVideoProcessStarted&&config.onVideoProcessStarted()),ctx.drawImage(video,0,0),"closed"!==controller._controlledReadableStream.state)try{controller.enqueue(ctx.getImageData(0,0,config.width,config.height))}catch(e){}},frameTimeout)},video.play()}})}function startRecording(stream,buffer){if(!config.workerPath&&!buffer)return finished=!1,void fetch("https://unpkg.com/webm-wasm@latest/dist/webm-worker.js").then(function(r){r.arrayBuffer().then(function(buffer){startRecording(stream,buffer)})});if(!config.workerPath&&buffer instanceof ArrayBuffer){var blob=new Blob([buffer],{type:"text/javascript"});config.workerPath=URL.createObjectURL(blob)}config.workerPath||console.error("workerPath parameter is missing."),worker=new Worker(config.workerPath),worker.postMessage(config.webAssemblyPath||"https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm"),worker.addEventListener("message",function(event){"READY"===event.data?(worker.postMessage({width:config.width,height:config.height,bitrate:config.bitrate||1200,timebaseDen:config.frameRate||30,realtime:config.realtime}),cameraStream().pipeTo(new WritableStream({write:function(image){return finished?void console.error("Got image, but recorder is finished!"):void worker.postMessage(image.data.buffer,[image.data.buffer])}}))):event.data&&(isPaused||arrayOfBuffers.push(event.data))})}function terminate(callback){return worker?(worker.addEventListener("message",function(event){null===event.data&&(worker.terminate(),worker=null,callback&&callback())}),void worker.postMessage(null)):void(callback&&callback())}"undefined"!=typeof ReadableStream&&"undefined"!=typeof WritableStream||console.error("Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js"),config=config||{},config.width=config.width||640,config.height=config.height||480,config.frameRate=config.frameRate||30,config.bitrate=config.bitrate||1200,config.realtime=config.realtime||!0;var finished,worker;this.record=function(){arrayOfBuffers=[],isPaused=!1,this.blob=null,startRecording(stream),"function"==typeof config.initCallback&&config.initCallback()};var isPaused;this.pause=function(){isPaused=!0},this.resume=function(){isPaused=!1};var arrayOfBuffers=[];this.stop=function(callback){finished=!0;var recorder=this;terminate(function(){recorder.blob=new Blob(arrayOfBuffers,{type:"video/webm"}),callback(recorder.blob)})},this.name="WebAssemblyRecorder",this.toString=function(){return this.name},this.clearRecordedData=function(){arrayOfBuffers=[],isPaused=!1,this.blob=null},this.blob=null}RecordRTC.version="5.6.2","undefined"!=typeof module&&(module.exports=RecordRTC),"function"==typeof define&&define.amd&&define("RecordRTC",[],function(){ -return RecordRTC}),RecordRTC.getFromDisk=function(type,callback){if(!callback)throw"callback is mandatory.";console.log("Getting recorded "+("all"===type?"blobs":type+" blob ")+" from disk!"),DiskStorage.Fetch(function(dataURL,_type){"all"!==type&&_type===type+"Blob"&&callback&&callback(dataURL),"all"===type&&callback&&callback(dataURL,_type.replace("Blob",""))})},RecordRTC.writeToDisk=function(options){console.log("Writing recorded blob(s) to disk!"),options=options||{},options.audio&&options.video&&options.gif?options.audio.getDataURL(function(audioDataURL){options.video.getDataURL(function(videoDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({audioBlob:audioDataURL,videoBlob:videoDataURL,gifBlob:gifDataURL})})})}):options.audio&&options.video?options.audio.getDataURL(function(audioDataURL){options.video.getDataURL(function(videoDataURL){DiskStorage.Store({audioBlob:audioDataURL,videoBlob:videoDataURL})})}):options.audio&&options.gif?options.audio.getDataURL(function(audioDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({audioBlob:audioDataURL,gifBlob:gifDataURL})})}):options.video&&options.gif?options.video.getDataURL(function(videoDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({videoBlob:videoDataURL,gifBlob:gifDataURL})})}):options.audio?options.audio.getDataURL(function(audioDataURL){DiskStorage.Store({audioBlob:audioDataURL})}):options.video?options.video.getDataURL(function(videoDataURL){DiskStorage.Store({videoBlob:videoDataURL})}):options.gif&&options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({gifBlob:gifDataURL})})},MRecordRTC.getFromDisk=RecordRTC.getFromDisk,MRecordRTC.writeToDisk=RecordRTC.writeToDisk,"undefined"!=typeof RecordRTC&&(RecordRTC.MRecordRTC=MRecordRTC);var browserFakeUserAgent="Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";!function(that){that&&"undefined"==typeof window&&"undefined"!=typeof global&&(global.navigator={userAgent:browserFakeUserAgent,getUserMedia:function(){}},global.console||(global.console={}),"undefined"!=typeof global.console.log&&"undefined"!=typeof global.console.error||(global.console.error=global.console.log=global.console.log||function(){console.log(arguments)}),"undefined"==typeof document&&(that.document={documentElement:{appendChild:function(){return""}}},document.createElement=document.captureStream=document.mozCaptureStream=function(){var obj={getContext:function(){return obj},play:function(){},pause:function(){},drawImage:function(){},toDataURL:function(){return""},style:{}};return obj},that.HTMLVideoElement=function(){}),"undefined"==typeof location&&(that.location={protocol:"file:",href:"",hash:""}),"undefined"==typeof screen&&(that.screen={width:0,height:0}),"undefined"==typeof URL&&(that.URL={createObjectURL:function(){return""},revokeObjectURL:function(){return""}}),that.window=global)}("undefined"!=typeof global?global:null);var requestAnimationFrame=window.requestAnimationFrame;if("undefined"==typeof requestAnimationFrame)if("undefined"!=typeof webkitRequestAnimationFrame)requestAnimationFrame=webkitRequestAnimationFrame;else if("undefined"!=typeof mozRequestAnimationFrame)requestAnimationFrame=mozRequestAnimationFrame;else if("undefined"!=typeof msRequestAnimationFrame)requestAnimationFrame=msRequestAnimationFrame;else if("undefined"==typeof requestAnimationFrame){var lastTime=0;requestAnimationFrame=function(callback,element){var currTime=(new Date).getTime(),timeToCall=Math.max(0,16-(currTime-lastTime)),id=setTimeout(function(){callback(currTime+timeToCall)},timeToCall);return lastTime=currTime+timeToCall,id}}var cancelAnimationFrame=window.cancelAnimationFrame;"undefined"==typeof cancelAnimationFrame&&("undefined"!=typeof webkitCancelAnimationFrame?cancelAnimationFrame=webkitCancelAnimationFrame:"undefined"!=typeof mozCancelAnimationFrame?cancelAnimationFrame=mozCancelAnimationFrame:"undefined"!=typeof msCancelAnimationFrame?cancelAnimationFrame=msCancelAnimationFrame:"undefined"==typeof cancelAnimationFrame&&(cancelAnimationFrame=function(id){clearTimeout(id)}));var AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;"undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"!=typeof navigator&&"undefined"==typeof navigator.getUserMedia&&("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia));var isEdge=!(navigator.userAgent.indexOf("Edge")===-1||!navigator.msSaveBlob&&!navigator.msSaveOrOpenBlob),isOpera=!!window.opera||navigator.userAgent.indexOf("OPR/")!==-1,isFirefox=navigator.userAgent.toLowerCase().indexOf("firefox")>-1&&"netscape"in window&&/ rv:/.test(navigator.userAgent),isChrome=!isOpera&&!isEdge&&!!navigator.webkitGetUserMedia||isElectron()||navigator.userAgent.toLowerCase().indexOf("chrome/")!==-1,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);isSafari&&!isChrome&&navigator.userAgent.indexOf("CriOS")!==-1&&(isSafari=!1,isChrome=!0);var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&"undefined"==typeof MediaStream.prototype.stop&&(MediaStream.prototype.stop=function(){this.getTracks().forEach(function(track){track.stop()})}),"undefined"!=typeof RecordRTC&&(RecordRTC.invokeSaveAsDialog=invokeSaveAsDialog,RecordRTC.getTracks=getTracks,RecordRTC.getSeekableBlob=getSeekableBlob,RecordRTC.bytesToSize=bytesToSize,RecordRTC.isElectron=isElectron);var Storage={};"undefined"!=typeof AudioContext?Storage.AudioContext=AudioContext:"undefined"!=typeof webkitAudioContext&&(Storage.AudioContext=webkitAudioContext),"undefined"!=typeof RecordRTC&&(RecordRTC.Storage=Storage),"undefined"!=typeof RecordRTC&&(RecordRTC.MediaStreamRecorder=MediaStreamRecorder),"undefined"!=typeof RecordRTC&&(RecordRTC.StereoAudioRecorder=StereoAudioRecorder),"undefined"!=typeof RecordRTC&&(RecordRTC.CanvasRecorder=CanvasRecorder),"undefined"!=typeof RecordRTC&&(RecordRTC.WhammyRecorder=WhammyRecorder);var Whammy=function(){function WhammyVideo(duration){this.frames=[],this.duration=duration||1,this.quality=.8}function processInWebWorker(_function){var blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (eee) {"+_function.name+"(eee.data);}"],{type:"application/javascript"})),worker=new Worker(blob);return URL.revokeObjectURL(blob),worker}function whammyInWebWorker(frames){function ArrayToWebM(frames){var info=checkFrames(frames);if(!info)return[];for(var clusterMaxDuration=3e4,EBML=[{id:440786851,data:[{data:1,id:17030},{data:1,id:17143},{data:4,id:17138},{data:8,id:17139},{data:"webm",id:17026},{data:2,id:17031},{data:2,id:17029}]},{id:408125543,data:[{id:357149030,data:[{data:1e6,id:2807729},{data:"whammy",id:19840},{data:"whammy",id:22337},{data:doubleToString(info.duration),id:17545}]},{id:374648427,data:[{id:174,data:[{data:1,id:215},{data:1,id:29637},{data:0,id:156},{data:"und",id:2274716},{data:"V_VP8",id:134},{data:"VP8",id:2459272},{data:1,id:131},{id:224,data:[{data:info.width,id:176},{data:info.height,id:186}]}]}]}]}],frameNumber=0,clusterTimecode=0;frameNumber0;)parts.push(255&num),num>>=8;return new Uint8Array(parts.reverse())}function strToBuffer(str){return new Uint8Array(str.split("").map(function(e){return e.charCodeAt(0)}))}function bitsToBuffer(bits){var data=[],pad=bits.length%8?new Array(9-bits.length%8).join("0"):"";bits=pad+bits;for(var i=0;i127)throw"TrackNumber > 127 not supported";var out=[128|data.trackNum,data.timecode>>8,255&data.timecode,flags].map(function(e){return String.fromCharCode(e)}).join("")+data.frame;return out}function parseWebP(riff){for(var VP8=riff.RIFF[0].WEBP[0],frameStart=VP8.indexOf("*"),i=0,c=[];i<4;i++)c[i]=VP8.charCodeAt(frameStart+3+i);var width,height,tmp;return tmp=c[1]<<8|c[0],width=16383&tmp,tmp=c[3]<<8|c[2],height=16383&tmp,{width:width,height:height,data:VP8,riff:riff}}function getStrLength(string,offset){return parseInt(string.substr(offset+4,4).split("").map(function(i){var unpadded=i.charCodeAt(0).toString(2);return new Array(8-unpadded.length+1).join("0")+unpadded}).join(""),2)}function parseRIFF(string){for(var offset=0,chunks={};offset",bytesToSize(blob.size)),callback){var url;try{url=URL.createObjectURL(blob)}catch(e){}"function"==typeof callback.call?callback.call(self,url):callback(url)}config.autoWriteToDisk&&getDataURL(function(dataURL){var parameter={};parameter[config.type+"Blob"]=dataURL,DiskStorage.Store(parameter)})}return callback=callback||function(){},mediaRecorder?"paused"===self.state?(self.resumeRecording(),void setTimeout(function(){stopRecording(callback)},1)):("recording"===self.state||config.disableLogs||console.warn('Recording state should be: "recording", however current state is: ',self.state),config.disableLogs||console.log("Stopped recording "+config.type+" stream."),"gif"!==config.type?mediaRecorder.stop(_callback):(mediaRecorder.stop(),_callback()),void setState("stopped")):void warningLog()}function pauseRecording(){return mediaRecorder?"recording"!==self.state?void(config.disableLogs||console.warn("Unable to pause the recording. Recording state: ",self.state)):(setState("paused"),mediaRecorder.pause(),void(config.disableLogs||console.log("Paused recording."))):void warningLog()}function resumeRecording(){return mediaRecorder?"paused"!==self.state?void(config.disableLogs||console.warn("Unable to resume the recording. Recording state: ",self.state)):(setState("recording"),mediaRecorder.resume(),void(config.disableLogs||console.log("Resumed recording."))):void warningLog()}function readFile(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))}function getDataURL(callback,_mediaRecorder){function processInWebWorker(_function){try{var blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (eee) {"+_function.name+"(eee.data);}"],{type:"application/javascript"})),worker=new Worker(blob);return URL.revokeObjectURL(blob),worker}catch(e){}}if(!callback)throw"Pass a callback function over getDataURL.";var blob=_mediaRecorder?_mediaRecorder.blob:(mediaRecorder||{}).blob;if(!blob)return config.disableLogs||console.warn("Blob encoder did not finish its job yet."),void setTimeout(function(){getDataURL(callback,_mediaRecorder)},1e3);if("undefined"==typeof Worker||navigator.mozGetUserMedia){var reader=new FileReader;reader.readAsDataURL(blob),reader.onload=function(event){callback(event.target.result)}}else{var webWorker=processInWebWorker(readFile);webWorker.onmessage=function(event){callback(event.data)},webWorker.postMessage(blob)}}function handleRecordingDuration(counter){if(counter=counter||0,"paused"===self.state)return void setTimeout(function(){handleRecordingDuration(counter)},1e3);if("stopped"!==self.state){if(counter>=self.recordingDuration)return void stopRecording(self.onRecordingStopped);counter+=1e3,setTimeout(function(){handleRecordingDuration(counter)},1e3)}}function setState(state){self&&(self.state=state,"function"==typeof self.onStateChanged.call?self.onStateChanged.call(self,state):self.onStateChanged(state))}function warningLog(){config.disableLogs!==!0&&console.warn(WARNING)}if(!mediaStream)throw"First parameter is required.";config=config||{type:"video"},config=new RecordRTCConfiguration(mediaStream,config);var mediaRecorder,self=this,WARNING='It seems that recorder is destroyed or "startRecording" is not invoked for '+config.type+" recorder.",returnObject={startRecording:startRecording,stopRecording:stopRecording,pauseRecording:pauseRecording,resumeRecording:resumeRecording,initRecorder:initRecorder,setRecordingDuration:function(recordingDuration,callback){if("undefined"==typeof recordingDuration)throw"recordingDuration is required.";if("number"!=typeof recordingDuration)throw"recordingDuration must be a number.";return self.recordingDuration=recordingDuration,self.onRecordingStopped=callback||function(){},{onRecordingStopped:function(callback){self.onRecordingStopped=callback}}},clearRecordedData:function(){return mediaRecorder?(mediaRecorder.clearRecordedData(),void(config.disableLogs||console.log("Cleared old recorded data."))):void warningLog()},getBlob:function(){return mediaRecorder?mediaRecorder.blob:void warningLog()},getDataURL:getDataURL,toURL:function(){return mediaRecorder?URL.createObjectURL(mediaRecorder.blob):void warningLog()},getInternalRecorder:function(){return mediaRecorder},save:function(fileName){return mediaRecorder?void invokeSaveAsDialog(mediaRecorder.blob,fileName):void warningLog()},getFromDisk:function(callback){return mediaRecorder?void RecordRTC.getFromDisk(config.type,callback):void warningLog()},setAdvertisementArray:function(arrayOfWebPImages){config.advertisement=[];for(var length=arrayOfWebPImages.length,i=0;i=0)}function getTracks(stream,kind){return stream&&stream.getTracks?stream.getTracks().filter(function(t){return t.kind===(kind||"audio")}):[]}function setSrcObject(stream,element){"srcObject"in element?element.srcObject=stream:"mozSrcObject"in element?element.mozSrcObject=stream:element.srcObject=stream}function getSeekableBlob(inputBlob,callback){if("undefined"==typeof EBML)throw new Error("Please link: https://www.webrtc-experiment.com/EBML.js");var reader=new EBML.Reader,decoder=new EBML.Decoder,tools=EBML.tools,fileReader=new FileReader;fileReader.onload=function(e){var ebmlElms=decoder.decode(this.result);ebmlElms.forEach(function(element){reader.read(element)}),reader.stop();var refinedMetadataBuf=tools.makeMetadataSeekable(reader.metadatas,reader.duration,reader.cues),body=this.result.slice(reader.metadataSize),newBlob=new Blob([refinedMetadataBuf,body],{type:"video/webm"});callback(newBlob)},fileReader.readAsArrayBuffer(inputBlob)}function isMediaRecorderCompatible(){if(isFirefox||isSafari||isEdge)return!0;var verOffset,ix,nAgt=(navigator.appVersion,navigator.userAgent),fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10);return(isChrome||isOpera)&&(verOffset=nAgt.indexOf("Chrome"),fullVersion=nAgt.substring(verOffset+7)),(ix=fullVersion.indexOf(";"))!==-1&&(fullVersion=fullVersion.substring(0,ix)),(ix=fullVersion.indexOf(" "))!==-1&&(fullVersion=fullVersion.substring(0,ix)),majorVersion=parseInt(""+fullVersion,10),isNaN(majorVersion)&&(fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10)),majorVersion>=49}function MediaStreamRecorder(mediaStream,config){function updateTimeStamp(){self.timestamps.push((new Date).getTime()),"function"==typeof config.onTimeStamp&&config.onTimeStamp(self.timestamps[self.timestamps.length-1],self.timestamps)}function getMimeType(secondObject){return mediaRecorder&&mediaRecorder.mimeType?mediaRecorder.mimeType:secondObject.mimeType||"video/webm"}function clearRecordedDataCB(){arrayOfBlobs=[],mediaRecorder=null,self.timestamps=[]}function isMediaStreamActive(){if("active"in mediaStream){if(!mediaStream.active)return!1}else if("ended"in mediaStream&&mediaStream.ended)return!1;return!0}var self=this;if("undefined"==typeof mediaStream)throw'First argument "MediaStream" is required.';if("undefined"==typeof MediaRecorder)throw"Your browser does not support the Media Recorder API. Please try other modules e.g. WhammyRecorder or StereoAudioRecorder.";if(config=config||{mimeType:"video/webm"},"audio"===config.type){if(getTracks(mediaStream,"video").length&&getTracks(mediaStream,"audio").length){var stream;navigator.mozGetUserMedia?(stream=new MediaStream,stream.addTrack(getTracks(mediaStream,"audio")[0])):stream=new MediaStream(getTracks(mediaStream,"audio")),mediaStream=stream}config.mimeType&&config.mimeType.toString().toLowerCase().indexOf("audio")!==-1||(config.mimeType=isChrome?"audio/webm":"audio/ogg"),config.mimeType&&"audio/ogg"!==config.mimeType.toString().toLowerCase()&&navigator.mozGetUserMedia&&(config.mimeType="audio/ogg")}var arrayOfBlobs=[];this.getArrayOfBlobs=function(){return arrayOfBlobs},this.record=function(){self.blob=null,self.clearRecordedData(),self.timestamps=[],allStates=[],arrayOfBlobs=[];var recorderHints=config;config.disableLogs||console.log("Passing following config over MediaRecorder API.",recorderHints),mediaRecorder&&(mediaRecorder=null),isChrome&&!isMediaRecorderCompatible()&&(recorderHints="video/vp8"),"function"==typeof MediaRecorder.isTypeSupported&&recorderHints.mimeType&&(MediaRecorder.isTypeSupported(recorderHints.mimeType)||(config.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",recorderHints.mimeType),recorderHints.mimeType="audio"===config.type?"audio/webm":"video/webm"));try{mediaRecorder=new MediaRecorder(mediaStream,recorderHints),config.mimeType=recorderHints.mimeType}catch(e){mediaRecorder=new MediaRecorder(mediaStream)}recorderHints.mimeType&&!MediaRecorder.isTypeSupported&&"canRecordMimeType"in mediaRecorder&&mediaRecorder.canRecordMimeType(recorderHints.mimeType)===!1&&(config.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",recorderHints.mimeType)),mediaRecorder.onstart=function(){allStates.push("started")},mediaRecorder.onpause=function(){allStates.push("paused")},mediaRecorder.onresume=function(){allStates.push("resumed")},mediaRecorder.onstop=function(){allStates.push("stopped"),config.writableStream&&Queue.enqueue(function(){return config.writableStream.close().then(function(){config.onWritableStreamClosed&&"function"==typeof config.onWritableStreamClosed&&config.onWritableStreamClosed()})})},mediaRecorder.onerror=function(error){error&&(error.name||(error.name="UnknownError"),allStates.push("error: "+error),config.disableLogs||(error.name.toString().toLowerCase().indexOf("invalidstate")!==-1?console.error("The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.",error):error.name.toString().toLowerCase().indexOf("notsupported")!==-1?console.error("MIME type (",recorderHints.mimeType,") is not supported.",error):error.name.toString().toLowerCase().indexOf("security")!==-1?console.error("MediaRecorder security error",error):"OutOfMemory"===error.name?console.error("The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.",error):"IllegalStreamModification"===error.name?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):"OtherRecordingError"===error.name?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):"GenericError"===error.name?console.error("The UA cannot provide the codec or recording option that has been requested.",error):console.error("MediaRecorder Error",error)),function(looper){return!self.manuallyStopped&&mediaRecorder&&"inactive"===mediaRecorder.state?(delete config.timeslice,void mediaRecorder.start(6e5)):void setTimeout(looper,1e3)}(),"inactive"!==mediaRecorder.state&&"stopped"!==mediaRecorder.state&&mediaRecorder.stop())},config.writableStream?(mediaRecorder.ondataavailable=function(e){Queue.enqueue(function(){return config.writableStream.write(e.data)})},config.timeSlice=config.timeSlice||1e3,mediaRecorder.start(config.timeSlice)):(mediaRecorder.ondataavailable=function(e){if(e.data&&allStates.push("ondataavailable: "+bytesToSize(e.data.size)),"number"!=typeof config.timeSlice){if(!e.data||!e.data.size||e.data.size<100||self.blob)return void(self.recordingCallback&&(self.recordingCallback(new Blob([],{type:getMimeType(recorderHints)})),self.recordingCallback=null));self.blob=config.getNativeBlob?e.data:new Blob([e.data],{type:getMimeType(recorderHints)}),self.recordingCallback&&(self.recordingCallback(self.blob),self.recordingCallback=null)}else if(e.data&&e.data.size&&(arrayOfBlobs.push(e.data),updateTimeStamp(),"function"==typeof config.ondataavailable)){var blob=config.getNativeBlob?e.data:new Blob([e.data],{type:getMimeType(recorderHints)});config.ondataavailable(blob)}},"number"==typeof config.timeSlice?(updateTimeStamp(),mediaRecorder.start(config.timeSlice)):mediaRecorder.start(36e5),config.initCallback&&config.initCallback())},this.timestamps=[],this.stop=function(callback){callback=callback||function(){},self.manuallyStopped=!0,mediaRecorder&&(this.recordingCallback=callback,"recording"===mediaRecorder.state&&mediaRecorder.stop(),"number"==typeof config.timeSlice&&setTimeout(function(){self.blob=new Blob(arrayOfBlobs,{type:getMimeType(config)}),self.recordingCallback(self.blob)},100))},this.pause=function(){mediaRecorder&&"recording"===mediaRecorder.state&&mediaRecorder.pause()},this.resume=function(){mediaRecorder&&"paused"===mediaRecorder.state&&mediaRecorder.resume()},this.clearRecordedData=function(){mediaRecorder&&"recording"===mediaRecorder.state&&self.stop(clearRecordedDataCB),clearRecordedDataCB()};var mediaRecorder;this.getInternalRecorder=function(){return mediaRecorder},this.blob=null,this.getState=function(){return mediaRecorder?mediaRecorder.state||"inactive":"inactive"};var allStates=[];this.getAllStates=function(){return allStates},"undefined"==typeof config.checkForInactiveTracks&&(config.checkForInactiveTracks=!1);var self=this;!function looper(){if(mediaRecorder&&config.checkForInactiveTracks!==!1)return isMediaStreamActive()===!1?(config.disableLogs||console.log("MediaStream seems stopped."),void self.stop()):void setTimeout(looper,1e3)}(),this.name="MediaStreamRecorder",this.toString=function(){return this.name}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}function _defineProperties(target,props){for(var i=0;i96e3)&&(config.disableLogs||console.log("sample-rate must be under range 22050 and 96000.")),config.disableLogs||config.desiredSampRate&&console.log("Desired sample-rate: "+config.desiredSampRate);var isPaused=!1;this.pause=function(){isPaused=!0},this.resume=function(){if(isMediaStreamActive()===!1)throw"Please make sure MediaStream is active.";return recording?void(isPaused=!1):(config.disableLogs||console.log("Seems recording has been restarted."),void this.record())},this.clearRecordedData=function(){config.checkForInactiveTracks=!1,recording&&this.stop(clearRecordedDataCB),clearRecordedDataCB()},this.name="StereoAudioRecorder",this.toString=function(){return this.name};var isAudioProcessStarted=!1;jsAudioNode.onaudioprocess=onAudioProcessDataAvailable,context.createMediaStreamDestination?jsAudioNode.connect(context.createMediaStreamDestination()):jsAudioNode.connect(context.destination),this.leftchannel=leftchannel,this.rightchannel=rightchannel,this.numberOfAudioChannels=numberOfAudioChannels,this.desiredSampRate=desiredSampRate,this.sampleRate=sampleRate,self.recordingLength=recordingLength;var intervalsBasedBuffers={left:[],right:[],recordingLength:0}}function CanvasRecorder(htmlElement,config){function clearRecordedDataCB(){whammy.frames=[],isRecording=!1,isPausedRecording=!1}function cloneCanvas(){var newCanvas=document.createElement("canvas"),context=newCanvas.getContext("2d");return newCanvas.width=htmlElement.width,newCanvas.height=htmlElement.height,context.drawImage(htmlElement,0,0),newCanvas}function drawCanvasFrame(){if(isPausedRecording)return lastTime=(new Date).getTime(),setTimeout(drawCanvasFrame,500);if("canvas"===htmlElement.nodeName.toLowerCase()){var duration=(new Date).getTime()-lastTime;return lastTime=(new Date).getTime(),whammy.frames.push({image:cloneCanvas(),duration:duration}),void(isRecording&&setTimeout(drawCanvasFrame,config.frameInterval))}html2canvas(htmlElement,{grabMouse:"undefined"==typeof config.showMousePointer||config.showMousePointer,onrendered:function(canvas){var duration=(new Date).getTime()-lastTime;return duration?(lastTime=(new Date).getTime(),whammy.frames.push({image:canvas.toDataURL("image/webp",1),duration:duration}),void(isRecording&&setTimeout(drawCanvasFrame,config.frameInterval))):setTimeout(drawCanvasFrame,config.frameInterval)}})}if("undefined"==typeof html2canvas)throw"Please link: https://www.webrtc-experiment.com/screenshot.js";config=config||{},config.frameInterval||(config.frameInterval=10);var isCanvasSupportsStreamCapturing=!1;["captureStream","mozCaptureStream","webkitCaptureStream"].forEach(function(item){item in document.createElement("canvas")&&(isCanvasSupportsStreamCapturing=!0)});var _isChrome=!(!window.webkitRTCPeerConnection&&!window.webkitGetUserMedia||!window.chrome),chromeVersion=50,matchArray=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);_isChrome&&matchArray&&matchArray[2]&&(chromeVersion=parseInt(matchArray[2],10)),_isChrome&&chromeVersion<52&&(isCanvasSupportsStreamCapturing=!1),config.useWhammyRecorder&&(isCanvasSupportsStreamCapturing=!1);var globalCanvas,mediaStreamRecorder;if(isCanvasSupportsStreamCapturing)if(config.disableLogs||console.log("Your browser supports both MediRecorder API and canvas.captureStream!"),htmlElement instanceof HTMLCanvasElement)globalCanvas=htmlElement;else{if(!(htmlElement instanceof CanvasRenderingContext2D))throw"Please pass either HTMLCanvasElement or CanvasRenderingContext2D.";globalCanvas=htmlElement.canvas}else navigator.mozGetUserMedia&&(config.disableLogs||console.error("Canvas recording is NOT supported in Firefox."));var isRecording;this.record=function(){if(isRecording=!0,isCanvasSupportsStreamCapturing&&!config.useWhammyRecorder){var canvasMediaStream;"captureStream"in globalCanvas?canvasMediaStream=globalCanvas.captureStream(25):"mozCaptureStream"in globalCanvas?canvasMediaStream=globalCanvas.mozCaptureStream(25):"webkitCaptureStream"in globalCanvas&&(canvasMediaStream=globalCanvas.webkitCaptureStream(25));try{var mdStream=new MediaStream;mdStream.addTrack(getTracks(canvasMediaStream,"video")[0]),canvasMediaStream=mdStream}catch(e){}if(!canvasMediaStream)throw"captureStream API are NOT available.";mediaStreamRecorder=new MediaStreamRecorder(canvasMediaStream,{mimeType:config.mimeType||"video/webm"}),mediaStreamRecorder.record()}else whammy.frames=[],lastTime=(new Date).getTime(),drawCanvasFrame();config.initCallback&&config.initCallback()},this.getWebPImages=function(callback){if("canvas"!==htmlElement.nodeName.toLowerCase())return void callback();var framesLength=whammy.frames.length;whammy.frames.forEach(function(frame,idx){var framesRemaining=framesLength-idx;config.disableLogs||console.log(framesRemaining+"/"+framesLength+" frames remaining"),config.onEncodingCallback&&config.onEncodingCallback(framesRemaining,framesLength);var webp=frame.image.toDataURL("image/webp",1);whammy.frames[idx].image=webp}),config.disableLogs||console.log("Generating WebM"),callback()},this.stop=function(callback){isRecording=!1;var that=this;return isCanvasSupportsStreamCapturing&&mediaStreamRecorder?void mediaStreamRecorder.stop(callback):void this.getWebPImages(function(){whammy.compile(function(blob){config.disableLogs||console.log("Recording finished!"),that.blob=blob,that.blob.forEach&&(that.blob=new Blob([],{type:"video/webm"})),callback&&callback(that.blob),whammy.frames=[]})})};var isPausedRecording=!1;this.pause=function(){if(isPausedRecording=!0,mediaStreamRecorder instanceof MediaStreamRecorder)return void mediaStreamRecorder.pause()},this.resume=function(){return isPausedRecording=!1,mediaStreamRecorder instanceof MediaStreamRecorder?void mediaStreamRecorder.resume():void(isRecording||this.record())},this.clearRecordedData=function(){isRecording&&this.stop(clearRecordedDataCB),clearRecordedDataCB()},this.name="CanvasRecorder",this.toString=function(){return this.name};var lastTime=(new Date).getTime(),whammy=new Whammy.Video(100)}function WhammyRecorder(mediaStream,config){function drawFrames(frameInterval){frameInterval="undefined"!=typeof frameInterval?frameInterval:10;var duration=(new Date).getTime()-lastTime;return duration?isPausedRecording?(lastTime=(new Date).getTime(),setTimeout(drawFrames,100)):(lastTime=(new Date).getTime(),video.paused&&video.play(),context.drawImage(video,0,0,canvas.width,canvas.height),whammy.frames.push({duration:duration,image:canvas.toDataURL("image/webp")}),void(isStopDrawing||setTimeout(drawFrames,frameInterval,frameInterval))):setTimeout(drawFrames,frameInterval,frameInterval)}function asyncLoop(o){var i=-1,length=o.length;!function loop(){return i++,i===length?void o.callback():void setTimeout(function(){o.functionToLoop(loop,i)},1)}()}function dropBlackFrames(_frames,_framesToCheck,_pixTolerance,_frameTolerance,callback){var localCanvas=document.createElement("canvas");localCanvas.width=canvas.width,localCanvas.height=canvas.height;var context2d=localCanvas.getContext("2d"),resultFrames=[],checkUntilNotBlack=_framesToCheck===-1,endCheckFrame=_framesToCheck&&_framesToCheck>0&&_framesToCheck<=_frames.length?_framesToCheck:_frames.length,sampleColor={r:0,g:0,b:0},maxColorDifference=Math.sqrt(Math.pow(255,2)+Math.pow(255,2)+Math.pow(255,2)),pixTolerance=_pixTolerance&&_pixTolerance>=0&&_pixTolerance<=1?_pixTolerance:0,frameTolerance=_frameTolerance&&_frameTolerance>=0&&_frameTolerance<=1?_frameTolerance:0,doNotCheckNext=!1;asyncLoop({length:endCheckFrame,functionToLoop:function(loop,f){var matchPixCount,endPixCheck,maxPixCount,finishImage=function(){!doNotCheckNext&&maxPixCount-matchPixCount<=maxPixCount*frameTolerance||(checkUntilNotBlack&&(doNotCheckNext=!0),resultFrames.push(_frames[f])),loop()};if(doNotCheckNext)finishImage();else{var image=new Image;image.onload=function(){context2d.drawImage(image,0,0,canvas.width,canvas.height);var imageData=context2d.getImageData(0,0,canvas.width,canvas.height);matchPixCount=0,endPixCheck=imageData.data.length,maxPixCount=imageData.data.length/4;for(var pix=0;pix1?2*remaining[0].width:remaining[0].width;var height=1;3!==videosLength&&4!==videosLength||(height=2),5!==videosLength&&6!==videosLength||(height=3),7!==videosLength&&8!==videosLength||(height=4),9!==videosLength&&10!==videosLength||(height=5),canvas.height=remaining[0].height*height}else canvas.width=self.width||360,canvas.height=self.height||240;fullcanvas&&fullcanvas instanceof HTMLVideoElement&&drawImage(fullcanvas),remaining.forEach(function(video,idx){drawImage(video,idx)}),setTimeout(drawVideosToCanvas,self.frameInterval)}}function drawImage(video,idx){if(!isStopDrawingFrames){var x=0,y=0,width=video.width,height=video.height;1===idx&&(x=video.width),2===idx&&(y=video.height),3===idx&&(x=video.width,y=video.height),4===idx&&(y=2*video.height),5===idx&&(x=video.width,y=2*video.height),6===idx&&(y=3*video.height),7===idx&&(x=video.width,y=3*video.height),"undefined"!=typeof video.stream.left&&(x=video.stream.left),"undefined"!=typeof video.stream.top&&(y=video.stream.top),"undefined"!=typeof video.stream.width&&(width=video.stream.width),"undefined"!=typeof video.stream.height&&(height=video.stream.height),context.drawImage(video,x,y,width,height),"function"==typeof video.stream.onRender&&video.stream.onRender(context,x,y,width,height,idx)}}function getMixedStream(){isStopDrawingFrames=!1;var mixedVideoStream=getMixedVideoStream(),mixedAudioStream=getMixedAudioStream();mixedAudioStream&&mixedAudioStream.getTracks().filter(function(t){return"audio"===t.kind}).forEach(function(track){mixedVideoStream.addTrack(track)});var fullcanvas;return arrayOfMediaStreams.forEach(function(stream){stream.fullcanvas&&(fullcanvas=!0)}),mixedVideoStream}function getMixedVideoStream(){resetVideoStreams();var capturedStream;"captureStream"in canvas?capturedStream=canvas.captureStream():"mozCaptureStream"in canvas?capturedStream=canvas.mozCaptureStream():self.disableLogs||console.error("Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features");var videoStream=new MediaStream;return capturedStream.getTracks().filter(function(t){return"video"===t.kind}).forEach(function(track){videoStream.addTrack(track)}),canvas.stream=videoStream,videoStream}function getMixedAudioStream(){Storage.AudioContextConstructor||(Storage.AudioContextConstructor=new Storage.AudioContext),self.audioContext=Storage.AudioContextConstructor,self.audioSources=[],self.useGainNode===!0&&(self.gainNode=self.audioContext.createGain(),self.gainNode.connect(self.audioContext.destination),self.gainNode.gain.value=0);var audioTracksLength=0;if(arrayOfMediaStreams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length){audioTracksLength++;var audioSource=self.audioContext.createMediaStreamSource(stream);self.useGainNode===!0&&audioSource.connect(self.gainNode),self.audioSources.push(audioSource)}}),audioTracksLength)return self.audioDestination=self.audioContext.createMediaStreamDestination(),self.audioSources.forEach(function(audioSource){audioSource.connect(self.audioDestination)}),self.audioDestination.stream}function getVideo(stream){var video=document.createElement("video");return setSrcObject(stream,video),video.className=elementClass,video.muted=!0,video.volume=0,video.width=stream.width||self.width||360,video.height=stream.height||self.height||240,video.play(),video}function resetVideoStreams(streams){videos=[],streams=streams||arrayOfMediaStreams,streams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video)}})}var browserFakeUserAgent="Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";!function(that){"undefined"==typeof RecordRTC&&that&&"undefined"==typeof window&&"undefined"!=typeof global&&(global.navigator={userAgent:browserFakeUserAgent,getUserMedia:function(){}},global.console||(global.console={}),"undefined"!=typeof global.console.log&&"undefined"!=typeof global.console.error||(global.console.error=global.console.log=global.console.log||function(){console.log(arguments)}),"undefined"==typeof document&&(that.document={documentElement:{appendChild:function(){return""}}},document.createElement=document.captureStream=document.mozCaptureStream=function(){var obj={getContext:function(){return obj},play:function(){},pause:function(){},drawImage:function(){},toDataURL:function(){return""},style:{}};return obj},that.HTMLVideoElement=function(){}),"undefined"==typeof location&&(that.location={protocol:"file:",href:"",hash:""}),"undefined"==typeof screen&&(that.screen={width:0,height:0}),"undefined"==typeof URL&&(that.URL={createObjectURL:function(){return""},revokeObjectURL:function(){return""}}),that.window=global)}("undefined"!=typeof global?global:null),elementClass=elementClass||"multi-streams-mixer";var videos=[],isStopDrawingFrames=!1,canvas=document.createElement("canvas"),context=canvas.getContext("2d");canvas.style.opacity=0,canvas.style.position="absolute",canvas.style.zIndex=-1,canvas.style.top="-1000em",canvas.style.left="-1000em",canvas.className=elementClass,(document.body||document.documentElement).appendChild(canvas),this.disableLogs=!1,this.frameInterval=10,this.width=360,this.height=240,this.useGainNode=!0;var self=this,AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;"undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"!=typeof navigator&&"undefined"==typeof navigator.getUserMedia&&("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia));var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&"undefined"==typeof MediaStream.prototype.stop&&(MediaStream.prototype.stop=function(){this.getTracks().forEach(function(track){track.stop()})});var Storage={};"undefined"!=typeof AudioContext?Storage.AudioContext=AudioContext:"undefined"!=typeof webkitAudioContext&&(Storage.AudioContext=webkitAudioContext),this.startDrawingFrames=function(){drawVideosToCanvas()},this.appendStreams=function(streams){if(!streams)throw"First parameter is required.";streams instanceof Array||(streams=[streams]),streams.forEach(function(stream){var newStream=new MediaStream;if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video),newStream.addTrack(stream.getTracks().filter(function(t){return"video"===t.kind})[0])}if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length){var audioSource=self.audioContext.createMediaStreamSource(stream);self.audioDestination=self.audioContext.createMediaStreamDestination(),audioSource.connect(self.audioDestination),newStream.addTrack(self.audioDestination.stream.getTracks().filter(function(t){return"audio"===t.kind})[0])}arrayOfMediaStreams.push(newStream)})},this.releaseStreams=function(){videos=[],isStopDrawingFrames=!0,self.gainNode&&(self.gainNode.disconnect(),self.gainNode=null),self.audioSources.length&&(self.audioSources.forEach(function(source){source.disconnect()}),self.audioSources=[]),self.audioDestination&&(self.audioDestination.disconnect(),self.audioDestination=null),self.audioContext&&self.audioContext.close(),self.audioContext=null,context.clearRect(0,0,canvas.width,canvas.height),canvas.stream&&(canvas.stream.stop(),canvas.stream=null)},this.resetVideoStreams=function(streams){!streams||streams instanceof Array||(streams=[streams]),resetVideoStreams(streams)},this.name="MultiStreamsMixer",this.toString=function(){return this.name},this.getMixedStream=getMixedStream}function MultiStreamRecorder(arrayOfMediaStreams,options){function getAllVideoTracks(){var tracks=[];return arrayOfMediaStreams.forEach(function(stream){getTracks(stream,"video").forEach(function(track){tracks.push(track)})}),tracks}arrayOfMediaStreams=arrayOfMediaStreams||[];var mixer,mediaRecorder,self=this;options=options||{elementClass:"multi-streams-mixer",mimeType:"video/webm",video:{width:360,height:240}},options.frameInterval||(options.frameInterval=10),options.video||(options.video={}),options.video.width||(options.video.width=360),options.video.height||(options.video.height=240),this.record=function(){mixer=new MultiStreamsMixer(arrayOfMediaStreams,options.elementClass||"multi-streams-mixer"),getAllVideoTracks().length&&(mixer.frameInterval=options.frameInterval||10,mixer.width=options.video.width||360,mixer.height=options.video.height||240,mixer.startDrawingFrames()),options.previewStream&&"function"==typeof options.previewStream&&options.previewStream(mixer.getMixedStream()),mediaRecorder=new MediaStreamRecorder(mixer.getMixedStream(),options),mediaRecorder.record()},this.stop=function(callback){mediaRecorder&&mediaRecorder.stop(function(blob){self.blob=blob,callback(blob),self.clearRecordedData()})},this.pause=function(){mediaRecorder&&mediaRecorder.pause()},this.resume=function(){mediaRecorder&&mediaRecorder.resume()},this.clearRecordedData=function(){mediaRecorder&&(mediaRecorder.clearRecordedData(),mediaRecorder=null),mixer&&(mixer.releaseStreams(),mixer=null)},this.addStreams=function(streams){if(!streams)throw"First parameter is required.";streams instanceof Array||(streams=[streams]),arrayOfMediaStreams.concat(streams),mediaRecorder&&mixer&&(mixer.appendStreams(streams),options.previewStream&&"function"==typeof options.previewStream&&options.previewStream(mixer.getMixedStream()))},this.resetVideoStreams=function(streams){mixer&&(!streams||streams instanceof Array||(streams=[streams]),mixer.resetVideoStreams(streams))},this.getMixer=function(){return mixer},this.name="MultiStreamRecorder",this.toString=function(){return this.name}}function RecordRTCPromisesHandler(mediaStream,options){if(!this)throw'Use "new RecordRTCPromisesHandler()"';if("undefined"==typeof mediaStream)throw'First argument "MediaStream" is required.';var self=this;self.recordRTC=new RecordRTC(mediaStream,options),this.startRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.startRecording(),resolve()}catch(e){reject(e)}})},this.stopRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.stopRecording(function(url){return self.blob=self.recordRTC.getBlob(),self.blob&&self.blob.size?void resolve(url):void reject("Empty blob.",self.blob)})}catch(e){reject(e)}})},this.pauseRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.pauseRecording(),resolve()}catch(e){reject(e)}})},this.resumeRecording=function(){return new Promise(function(resolve,reject){try{self.recordRTC.resumeRecording(),resolve()}catch(e){reject(e)}})},this.getDataURL=function(callback){return new Promise(function(resolve,reject){try{self.recordRTC.getDataURL(function(dataURL){resolve(dataURL)})}catch(e){reject(e)}})},this.getBlob=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getBlob())}catch(e){reject(e)}})},this.getInternalRecorder=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getInternalRecorder())}catch(e){reject(e)}})},this.reset=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.reset())}catch(e){reject(e)}})},this.destroy=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.destroy())}catch(e){reject(e)}})},this.getState=function(){return new Promise(function(resolve,reject){try{resolve(self.recordRTC.getState())}catch(e){reject(e)}})},this.blob=null,this.version="5.6.2"}function WebAssemblyRecorder(stream,config){function cameraStream(){return new ReadableStream({start:function(controller){var cvs=document.createElement("canvas"),video=document.createElement("video"),first=!0;video.srcObject=stream,video.muted=!0,video.height=config.height,video.width=config.width,video.volume=0,video.onplaying=function(){cvs.width=config.width,cvs.height=config.height;var ctx=cvs.getContext("2d"),frameTimeout=1e3/config.frameRate,cameraTimer=setInterval(function(){if(finished&&(clearInterval(cameraTimer),controller.close()),first&&(first=!1,config.onVideoProcessStarted&&config.onVideoProcessStarted()),ctx.drawImage(video,0,0),"closed"!==controller._controlledReadableStream.state)try{controller.enqueue(ctx.getImageData(0,0,config.width,config.height))}catch(e){}},frameTimeout)},video.play()}})}function startRecording(stream,buffer){if(!config.workerPath&&!buffer)return finished=!1,void fetch("https://unpkg.com/webm-wasm@latest/dist/webm-worker.js").then(function(r){r.arrayBuffer().then(function(buffer){startRecording(stream,buffer)})});if(!config.workerPath&&buffer instanceof ArrayBuffer){var blob=new Blob([buffer],{type:"text/javascript"});config.workerPath=URL.createObjectURL(blob)}config.workerPath||console.error("workerPath parameter is missing."),worker=new Worker(config.workerPath),worker.postMessage(config.webAssemblyPath||"https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm"),worker.addEventListener("message",function(event){"READY"===event.data?(worker.postMessage({width:config.width,height:config.height,bitrate:config.bitrate||1200,timebaseDen:config.frameRate||30,realtime:config.realtime}),cameraStream().pipeTo(new WritableStream({write:function(image){return finished?void console.error("Got image, but recorder is finished!"):void worker.postMessage(image.data.buffer,[image.data.buffer])}}))):event.data&&(isPaused||arrayOfBuffers.push(event.data))})}function terminate(callback){return worker?(worker.addEventListener("message",function(event){null===event.data&&(worker.terminate(),worker=null, +callback&&callback())}),void worker.postMessage(null)):void(callback&&callback())}"undefined"!=typeof ReadableStream&&"undefined"!=typeof WritableStream||console.error("Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js"),config=config||{},config.width=config.width||640,config.height=config.height||480,config.frameRate=config.frameRate||30,config.bitrate=config.bitrate||1200,config.realtime=config.realtime||!0;var finished,worker;this.record=function(){arrayOfBuffers=[],isPaused=!1,this.blob=null,startRecording(stream),"function"==typeof config.initCallback&&config.initCallback()};var isPaused;this.pause=function(){isPaused=!0},this.resume=function(){isPaused=!1};var arrayOfBuffers=[];this.stop=function(callback){finished=!0;var recorder=this;terminate(function(){recorder.blob=new Blob(arrayOfBuffers,{type:"video/webm"}),callback(recorder.blob)})},this.name="WebAssemblyRecorder",this.toString=function(){return this.name},this.clearRecordedData=function(){arrayOfBuffers=[],isPaused=!1,this.blob=null},this.blob=null}RecordRTC.version="5.6.2","undefined"!=typeof module&&(module.exports=RecordRTC),"function"==typeof define&&define.amd&&define("RecordRTC",[],function(){return RecordRTC}),RecordRTC.getFromDisk=function(type,callback){if(!callback)throw"callback is mandatory.";console.log("Getting recorded "+("all"===type?"blobs":type+" blob ")+" from disk!"),DiskStorage.Fetch(function(dataURL,_type){"all"!==type&&_type===type+"Blob"&&callback&&callback(dataURL),"all"===type&&callback&&callback(dataURL,_type.replace("Blob",""))})},RecordRTC.writeToDisk=function(options){console.log("Writing recorded blob(s) to disk!"),options=options||{},options.audio&&options.video&&options.gif?options.audio.getDataURL(function(audioDataURL){options.video.getDataURL(function(videoDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({audioBlob:audioDataURL,videoBlob:videoDataURL,gifBlob:gifDataURL})})})}):options.audio&&options.video?options.audio.getDataURL(function(audioDataURL){options.video.getDataURL(function(videoDataURL){DiskStorage.Store({audioBlob:audioDataURL,videoBlob:videoDataURL})})}):options.audio&&options.gif?options.audio.getDataURL(function(audioDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({audioBlob:audioDataURL,gifBlob:gifDataURL})})}):options.video&&options.gif?options.video.getDataURL(function(videoDataURL){options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({videoBlob:videoDataURL,gifBlob:gifDataURL})})}):options.audio?options.audio.getDataURL(function(audioDataURL){DiskStorage.Store({audioBlob:audioDataURL})}):options.video?options.video.getDataURL(function(videoDataURL){DiskStorage.Store({videoBlob:videoDataURL})}):options.gif&&options.gif.getDataURL(function(gifDataURL){DiskStorage.Store({gifBlob:gifDataURL})})},MRecordRTC.getFromDisk=RecordRTC.getFromDisk,MRecordRTC.writeToDisk=RecordRTC.writeToDisk,"undefined"!=typeof RecordRTC&&(RecordRTC.MRecordRTC=MRecordRTC);var browserFakeUserAgent="Fake/5.0 (FakeOS) AppleWebKit/123 (KHTML, like Gecko) Fake/12.3.4567.89 Fake/123.45";!function(that){that&&"undefined"==typeof window&&"undefined"!=typeof global&&(global.navigator={userAgent:browserFakeUserAgent,getUserMedia:function(){}},global.console||(global.console={}),"undefined"!=typeof global.console.log&&"undefined"!=typeof global.console.error||(global.console.error=global.console.log=global.console.log||function(){console.log(arguments)}),"undefined"==typeof document&&(that.document={documentElement:{appendChild:function(){return""}}},document.createElement=document.captureStream=document.mozCaptureStream=function(){var obj={getContext:function(){return obj},play:function(){},pause:function(){},drawImage:function(){},toDataURL:function(){return""},style:{}};return obj},that.HTMLVideoElement=function(){}),"undefined"==typeof location&&(that.location={protocol:"file:",href:"",hash:""}),"undefined"==typeof screen&&(that.screen={width:0,height:0}),"undefined"==typeof URL&&(that.URL={createObjectURL:function(){return""},revokeObjectURL:function(){return""}}),that.window=global)}("undefined"!=typeof global?global:null);var requestAnimationFrame=window.requestAnimationFrame;if("undefined"==typeof requestAnimationFrame)if("undefined"!=typeof webkitRequestAnimationFrame)requestAnimationFrame=webkitRequestAnimationFrame;else if("undefined"!=typeof mozRequestAnimationFrame)requestAnimationFrame=mozRequestAnimationFrame;else if("undefined"!=typeof msRequestAnimationFrame)requestAnimationFrame=msRequestAnimationFrame;else if("undefined"==typeof requestAnimationFrame){var lastTime=0;requestAnimationFrame=function(callback,element){var currTime=(new Date).getTime(),timeToCall=Math.max(0,16-(currTime-lastTime)),id=setTimeout(function(){callback(currTime+timeToCall)},timeToCall);return lastTime=currTime+timeToCall,id}}var cancelAnimationFrame=window.cancelAnimationFrame;"undefined"==typeof cancelAnimationFrame&&("undefined"!=typeof webkitCancelAnimationFrame?cancelAnimationFrame=webkitCancelAnimationFrame:"undefined"!=typeof mozCancelAnimationFrame?cancelAnimationFrame=mozCancelAnimationFrame:"undefined"!=typeof msCancelAnimationFrame?cancelAnimationFrame=msCancelAnimationFrame:"undefined"==typeof cancelAnimationFrame&&(cancelAnimationFrame=function(id){clearTimeout(id)}));var AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;"undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"!=typeof navigator&&"undefined"==typeof navigator.getUserMedia&&("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia));var isEdge=!(navigator.userAgent.indexOf("Edge")===-1||!navigator.msSaveBlob&&!navigator.msSaveOrOpenBlob),isOpera=!!window.opera||navigator.userAgent.indexOf("OPR/")!==-1,isFirefox=navigator.userAgent.toLowerCase().indexOf("firefox")>-1&&"netscape"in window&&/ rv:/.test(navigator.userAgent),isChrome=!isOpera&&!isEdge&&!!navigator.webkitGetUserMedia||isElectron()||navigator.userAgent.toLowerCase().indexOf("chrome/")!==-1,isSafari=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);isSafari&&!isChrome&&navigator.userAgent.indexOf("CriOS")!==-1&&(isSafari=!1,isChrome=!0);var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&"undefined"==typeof MediaStream.prototype.stop&&(MediaStream.prototype.stop=function(){this.getTracks().forEach(function(track){track.stop()})}),"undefined"!=typeof RecordRTC&&(RecordRTC.invokeSaveAsDialog=invokeSaveAsDialog,RecordRTC.getTracks=getTracks,RecordRTC.getSeekableBlob=getSeekableBlob,RecordRTC.bytesToSize=bytesToSize,RecordRTC.isElectron=isElectron);var Storage={};"undefined"!=typeof AudioContext?Storage.AudioContext=AudioContext:"undefined"!=typeof webkitAudioContext&&(Storage.AudioContext=webkitAudioContext),"undefined"!=typeof RecordRTC&&(RecordRTC.Storage=Storage),"undefined"!=typeof RecordRTC&&(RecordRTC.MediaStreamRecorder=MediaStreamRecorder);var Queue=function(){function Queue(){_classCallCheck(this,Queue)}return _createClass(Queue,null,[{key:"enqueue",value:function(promise){var _this=this;return new Promise(function(resolve,reject){_this.queue.push({promise:promise,resolve:resolve,reject:reject}),_this.dequeue()})}},{key:"dequeue",value:function(){var _this2=this;if(this.workingOnPromise)return!1;var item=this.queue.shift();if(!item)return!1;try{this.workingOnPromise=!0,item.promise().then(function(value){_this2.workingOnPromise=!1,item.resolve(value),_this2.dequeue()})["catch"](function(err){_this2.workingOnPromise=!1,item.reject(err),_this2.dequeue()})}catch(err){this.workingOnPromise=!1,item.reject(err),this.dequeue()}return!0}}]),Queue}();_defineProperty(Queue,"queue",[]),_defineProperty(Queue,"workingOnPromise",!1),"undefined"!=typeof RecordRTC&&(RecordRTC.StereoAudioRecorder=StereoAudioRecorder),"undefined"!=typeof RecordRTC&&(RecordRTC.CanvasRecorder=CanvasRecorder),"undefined"!=typeof RecordRTC&&(RecordRTC.WhammyRecorder=WhammyRecorder);var Whammy=function(){function WhammyVideo(duration){this.frames=[],this.duration=duration||1,this.quality=.8}function processInWebWorker(_function){var blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (eee) {"+_function.name+"(eee.data);}"],{type:"application/javascript"})),worker=new Worker(blob);return URL.revokeObjectURL(blob),worker}function whammyInWebWorker(frames){function ArrayToWebM(frames){var info=checkFrames(frames);if(!info)return[];for(var clusterMaxDuration=3e4,EBML=[{id:440786851,data:[{data:1,id:17030},{data:1,id:17143},{data:4,id:17138},{data:8,id:17139},{data:"webm",id:17026},{data:2,id:17031},{data:2,id:17029}]},{id:408125543,data:[{id:357149030,data:[{data:1e6,id:2807729},{data:"whammy",id:19840},{data:"whammy",id:22337},{data:doubleToString(info.duration),id:17545}]},{id:374648427,data:[{id:174,data:[{data:1,id:215},{data:1,id:29637},{data:0,id:156},{data:"und",id:2274716},{data:"V_VP8",id:134},{data:"VP8",id:2459272},{data:1,id:131},{id:224,data:[{data:info.width,id:176},{data:info.height,id:186}]}]}]}]}],frameNumber=0,clusterTimecode=0;frameNumber0;)parts.push(255&num),num>>=8;return new Uint8Array(parts.reverse())}function strToBuffer(str){return new Uint8Array(str.split("").map(function(e){return e.charCodeAt(0)}))}function bitsToBuffer(bits){var data=[],pad=bits.length%8?new Array(9-bits.length%8).join("0"):"";bits=pad+bits;for(var i=0;i127)throw"TrackNumber > 127 not supported";var out=[128|data.trackNum,data.timecode>>8,255&data.timecode,flags].map(function(e){return String.fromCharCode(e)}).join("")+data.frame;return out}function parseWebP(riff){for(var VP8=riff.RIFF[0].WEBP[0],frameStart=VP8.indexOf("*"),i=0,c=[];i<4;i++)c[i]=VP8.charCodeAt(frameStart+3+i);var width,height,tmp;return tmp=c[1]<<8|c[0],width=16383&tmp,tmp=c[3]<<8|c[2],height=16383&tmp,{width:width,height:height,data:VP8,riff:riff}}function getStrLength(string,offset){return parseInt(string.substr(offset+4,4).split("").map(function(i){var unpadded=i.charCodeAt(0).toString(2);return new Array(8-unpadded.length+1).join("0")+unpadded}).join(""),2)}function parseRIFF(string){for(var offset=0,chunks={};offset {timeSlice: 1000} otherwise + // Dispatching OnDataAvailable Handler + mediaRecorder.ondataavailable = function(e) { + if (e.data) { + allStates.push('ondataavailable: ' + bytesToSize(e.data.size)); + } - mediaRecorder.start(3.6e+6); - } + if (typeof config.timeSlice === 'number') { + if (e.data && e.data.size) { + arrayOfBlobs.push(e.data); + updateTimeStamp(); + + if (typeof config.ondataavailable === 'function') { + // intervals based blobs + var blob = config.getNativeBlob ? e.data : new Blob([e.data], { + type: getMimeType(recorderHints) + }); + config.ondataavailable(blob); + } + } + return; + } + + if (!e.data || !e.data.size || e.data.size < 100 || self.blob) { + // make sure that stopRecording always getting fired + // even if there is invalid data + if (self.recordingCallback) { + self.recordingCallback(new Blob([], { + type: getMimeType(recorderHints) + })); + self.recordingCallback = null; + } + return; + } + + self.blob = config.getNativeBlob ? e.data : new Blob([e.data], { + type: getMimeType(recorderHints) + }); + + if (self.recordingCallback) { + self.recordingCallback(self.blob); + self.recordingCallback = null; + } + }; + + if (typeof config.timeSlice === 'number') { + updateTimeStamp(); + mediaRecorder.start(config.timeSlice); + } else { + // default is 60 minutes; enough? + // use config => {timeSlice: 1000} otherwise - if (config.initCallback) { - config.initCallback(); // old code + mediaRecorder.start(3.6e+6); + } + + if (config.initCallback) { + config.initCallback(); // old code + } } }; @@ -459,8 +479,8 @@ function MediaStreamRecorder(mediaStream, config) { return allStates; }; - // if any Track within the MediaStream is muted or not enabled at any time, - // the browser will only record black frames + // if any Track within the MediaStream is muted or not enabled at any time, + // the browser will only record black frames // or silence since that is the content produced by the Track // so we need to stopRecording as soon as any single track ends. if (typeof config.checkForInactiveTracks === 'undefined') { @@ -497,3 +517,119 @@ function MediaStreamRecorder(mediaStream, config) { if (typeof RecordRTC !== 'undefined') { RecordRTC.MediaStreamRecorder = MediaStreamRecorder; } + +/** + * From https://medium.com/@karenmarkosyan/how-to-manage-promises-into-dynamic-queue-with-vanilla-javascript-9d0d1f8d4df5 (+ Babel to convert to ES5) + * Allows resolving promises in the order they are added to the queue. + */ +function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError('Cannot call a class as a function'); + } +} + +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ('value' in descriptor) { + descriptor.writable = true; + } + Object.defineProperty(target, descriptor.key, descriptor); + } +} + +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) { + _defineProperties(Constructor.prototype, protoProps); + } + if (staticProps) { + _defineProperties(Constructor, staticProps); + } + Object.defineProperty(Constructor, 'prototype', { + writable: false + }); + return Constructor; +} + +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; +} +var Queue = /*#__PURE__*/ (function() { + function Queue() { + _classCallCheck(this, Queue); + } + + _createClass(Queue, null, [{ + key: 'enqueue', + value: function enqueue(promise) { + var _this = this; + + return new Promise(function(resolve, reject) { + _this.queue.push({ + promise: promise, + resolve: resolve, + reject: reject + }); + + _this.dequeue(); + }); + } + }, + { + key: 'dequeue', + value: function dequeue() { + var _this2 = this; + + if (this.workingOnPromise) { + return false; + } + + var item = this.queue.shift(); + + if (!item) { + return false; + } + + try { + this.workingOnPromise = true; + item + .promise() + .then(function(value) { + _this2.workingOnPromise = false; + item.resolve(value); + + _this2.dequeue(); + }) + .catch(function(err) { + _this2.workingOnPromise = false; + item.reject(err); + + _this2.dequeue(); + }); + } catch (err) { + this.workingOnPromise = false; + item.reject(err); + this.dequeue(); + } + + return true; + } + } + ]); + + return Queue; +})(); +_defineProperty(Queue, 'queue', []); +_defineProperty(Queue, 'workingOnPromise', false); diff --git a/simple-demos/index.html b/simple-demos/index.html index 9fb17846..ede12897 100644 --- a/simple-demos/index.html +++ b/simple-demos/index.html @@ -15,12 +15,12 @@ - + + +Screen Recording | RecordRTC +

Screen Recording using RecordRTC

+ +
+ + + + +
+ + + + + + + +

+ +
+ +
+