diff --git a/main/inc/lib/javascript/record_audio/record_audio.js b/main/inc/lib/javascript/record_audio/record_audio.js index 04c74138e9..f5680916e5 100644 --- a/main/inc/lib/javascript/record_audio/record_audio.js +++ b/main/inc/lib/javascript/record_audio/record_audio.js @@ -1,6 +1,8 @@ /* For licensing terms, see /license.txt */ window.RecordAudio = (function () { + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + function startTimer() { $("#timer").show(); var timerData = { @@ -120,13 +122,11 @@ window.RecordAudio = (function () { } } - navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia; - function successCallback(stream) { stopTimer(); startTimer(); recordRTC = RecordRTC(stream, { - numberOfAudioChannels: 1, + recorderType: isSafari ? RecordRTC.StereoAudioRecorder : RecordRTC.MediaStreamRecorder, type: 'audio' }); recordRTC.startRecording(); @@ -143,16 +143,18 @@ window.RecordAudio = (function () { function errorCallback(error) { stopTimer(); - alert(error.message); + alert(error); } - if (navigator.getUserMedia) { + if(!!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia)) { + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia(mediaConstraints, successCallback, errorCallback); - } else if (navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia(mediaConstraints) - .then(successCallback) - .error(errorCallback); + return; } + + navigator.mediaDevices.getUserMedia(mediaConstraints) + .then(successCallback) + .catch(errorCallback); }); btnPause.on('click', function () { diff --git a/main/inc/lib/javascript/rtc/RecordRTC.js b/main/inc/lib/javascript/rtc/RecordRTC.js old mode 100755 new mode 100644 index d3c1dbce9e..e79f3d138b --- a/main/inc/lib/javascript/rtc/RecordRTC.js +++ b/main/inc/lib/javascript/rtc/RecordRTC.js @@ -1,6 +1,292 @@ -'use strict'; - -// Last time updated: 2016-04-16 3:50:29 PM UTC - -"use strict";function RecordRTC(mediaStream,config){function startRecording(){return config.disableLogs||console.debug("started recording "+config.type+" stream."),mediaRecorder?(mediaRecorder.clearRecordedData(),mediaRecorder.resume(),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(),config.disableLogs||console.debug("Initialized recorderType:",mediaRecorder.constructor.name,"for output-type:",config.type)}function stopRecording(callback){function _callback(){for(var item in mediaRecorder)self&&(self[item]=mediaRecorder[item]),recordRTC&&(recordRTC[item]=mediaRecorder[item]);var blob=mediaRecorder.blob;if(callback){var url=URL.createObjectURL(blob);callback(url)}blob&&!config.disableLogs&&console.debug(blob.type,"->",bytesToSize(blob.size)),config.autoWriteToDisk&&getDataURL(function(dataURL){var parameter={};parameter[config.type+"Blob"]=dataURL,DiskStorage.Store(parameter)})}if(!mediaRecorder)return console.warn(WARNING);var recordRTC=this;config.disableLogs||console.warn("Stopped recording "+config.type+" stream."),"gif"!==config.type?mediaRecorder.stop(_callback):(mediaRecorder.stop(),_callback())}function pauseRecording(){return mediaRecorder?(mediaRecorder.pause(),void(config.disableLogs||console.debug("Paused recording."))):console.warn(WARNING)}function resumeRecording(){return mediaRecorder?(mediaRecorder.resume(),void(config.disableLogs||console.debug("Resumed recording."))):console.warn(WARNING)}function readFile(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))}function getDataURL(callback,_mediaRecorder){function processInWebWorker(_function){var blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (e) {"+_function.name+"(e.data);}"],{type:"application/javascript"})),worker=new Worker(blob);return URL.revokeObjectURL(blob),worker}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 yet finished its job."),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(){setTimeout(function(){stopRecording(self.onRecordingStopped)},self.recordingDuration)}if(!mediaStream)throw"MediaStream is mandatory.";config=new RecordRTCConfiguration(mediaStream,config);var mediaRecorder,self=this,WARNING='It seems that "startRecording" is not invoked for '+config.type+" recorder.",returnObject={startRecording:startRecording,stopRecording:stopRecording,pauseRecording:pauseRecording,resumeRecording:resumeRecording,initRecorder:initRecorder,setRecordingDuration:function(milliseconds,callback){if("undefined"==typeof milliseconds)throw"milliseconds is required.";if("number"!=typeof milliseconds)throw"milliseconds must be a number.";return self.recordingDuration=milliseconds,self.onRecordingStopped=callback||function(){},{onRecordingStopped:function(callback){self.onRecordingStopped=callback}}},clearRecordedData:function(){return mediaRecorder?(mediaRecorder.clearRecordedData(),void(config.disableLogs||console.debug("Cleared old recorded data."))):console.warn(WARNING)},getBlob:function(){return mediaRecorder?mediaRecorder.blob:console.warn(WARNING)},getDataURL:getDataURL,toURL:function(){return mediaRecorder?URL.createObjectURL(mediaRecorder.blob):console.warn(WARNING)},save:function(fileName){return mediaRecorder?void invokeSaveAsDialog(mediaRecorder.blob,fileName):console.warn(WARNING)},getFromDisk:function(callback){return mediaRecorder?void RecordRTC.getFromDisk(config.type,callback):console.warn(WARNING)},setAdvertisementArray:function(arrayOfWebPImages){config.advertisement=[];for(var length=arrayOfWebPImages.length,i=0;length>i;i++)config.advertisement.push({duration:i,image:arrayOfWebPImages[i]})},blob:null,bufferSize:0,sampleRate:0,buffer:null,view:null};if(!this)return self=returnObject,returnObject;for(var prop in returnObject)this[prop]=returnObject[prop];return self=this,returnObject}function RecordRTCConfiguration(mediaStream,config){return config.recorderType&&!config.type&&(config.recorderType===WhammyRecorder||config.recorderType===CanvasRecorder?config.type="video":config.recorderType===GifRecorder?config.type="gif":config.recorderType===StereoAudioRecorder?config.type="audio":config.recorderType===MediaStreamRecorder&&(mediaStream.getAudioTracks().length&&mediaStream.getVideoTracks().length?config.type="video":mediaStream.getAudioTracks().length&&!mediaStream.getVideoTracks().length?config.type="audio":!mediaStream.getAudioTracks().length&&mediaStream.getVideoTracks().length&&(config.type="audio"))),"undefined"!=typeof MediaStreamRecorder&&"undefined"!=typeof MediaRecorder&&"requestData"in MediaRecorder.prototype&&(config.mimeType||(config.mimeType="video/webm"),config.type||(config.type=config.mimeType.split("/")[0]),!config.bitsPerSecond),config.type||(config.mimeType&&(config.type=config.mimeType.split("/")[0]),config.type||(config.type="audio")),config}function GetRecorderType(mediaStream,config){var recorder;return(isChrome||isEdge||isOpera)&&(recorder=StereoAudioRecorder),"undefined"!=typeof MediaRecorder&&"requestData"in MediaRecorder.prototype&&!isChrome&&(recorder=MediaStreamRecorder),"video"===config.type&&(isChrome||isOpera)&&(recorder=WhammyRecorder),"gif"===config.type&&(recorder=GifRecorder),"canvas"===config.type&&(recorder=CanvasRecorder),isMediaRecorderCompatible()&&isChrome&&recorder!==CanvasRecorder&&recorder!==GifRecorder&&"undefined"!=typeof MediaRecorder&&"requestData"in MediaRecorder.prototype&&mediaStream.getVideoTracks().length&&(recorder=MediaStreamRecorder),config.recorderType&&(recorder=config.recorderType),!config.disableLogs&&recorder&&recorder.name&&console.debug("Using recorderType:",recorder.name||recorder.constructor.name),recorder}function MRecordRTC(mediaStream){this.addStream=function(_mediaStream){_mediaStream&&(mediaStream=_mediaStream)},this.mediaType={audio:!0,video:!0},this.startRecording=function(){var recorderType,mediaType=this.mediaType,mimeType=this.mimeType||{audio:null,video:null,gif:null};if("function"!=typeof mediaType.audio&&isMediaRecorderCompatible()&&mediaStream.getAudioTracks&&!mediaStream.getAudioTracks().length&&(mediaType.audio=!1),"function"!=typeof mediaType.video&&isMediaRecorderCompatible()&&mediaStream.getVideoTracks&&!mediaStream.getVideoTracks().length&&(mediaType.video=!1),!mediaType.audio&&!mediaType.video)throw"MediaStream must have either audio or video tracks.";if(mediaType.audio&&(recorderType=null,"function"==typeof mediaType.audio&&(recorderType=mediaType.audio),this.audioRecorder=new RecordRTC(mediaStream,{type:"audio",bufferSize:this.bufferSize,sampleRate:this.sampleRate,numberOfAudioChannels:this.numberOfAudioChannels||2,disableLogs:this.disableLogs,recorderType:recorderType,mimeType:mimeType.audio}),mediaType.video||this.audioRecorder.startRecording()),mediaType.video){recorderType=null,"function"==typeof mediaType.video&&(recorderType=mediaType.video);var newStream=mediaStream;if(isMediaRecorderCompatible()&&mediaType.audio&&"function"==typeof mediaType.audio){var videoTrack=mediaStream.getVideoTracks()[0];navigator.mozGetUserMedia?(newStream=new MediaStream,newStream.addTrack(videoTrack),recorderType&&recorderType===WhammyRecorder&&(recorderType=MediaStreamRecorder)):newStream=new MediaStream([videoTrack])}this.videoRecorder=new RecordRTC(newStream,{type:"video",video:this.video,canvas:this.canvas,frameInterval:this.frameInterval||10,disableLogs:this.disableLogs,recorderType:recorderType,mimeType:mimeType.video}),mediaType.audio||this.videoRecorder.startRecording()}if(mediaType.audio&&mediaType.video){var self=this;isMediaRecorderCompatible()?(self.audioRecorder=null,self.videoRecorder.startRecording()):self.videoRecorder.initRecorder(function(){self.audioRecorder.initRecorder(function(){self.videoRecorder.startRecording(),self.audioRecorder.startRecording()})})}mediaType.gif&&(recorderType=null,"function"==typeof mediaType.gif&&(recorderType=mediaType.gif),this.gifRecorder=new RecordRTC(mediaStream,{type:"gif",frameRate:this.frameRate||200,quality:this.quality||10,disableLogs:this.disableLogs,recorderType:recorderType,mimeType:mimeType.gif}),this.gifRecorder.startRecording())},this.stopRecording=function(callback){callback=callback||function(){},this.audioRecorder&&this.audioRecorder.stopRecording(function(blobURL){callback(blobURL,"audio")}),this.videoRecorder&&this.videoRecorder.stopRecording(function(blobURL){callback(blobURL,"video")}),this.gifRecorder&&this.gifRecorder.stopRecording(function(blobURL){callback(blobURL,"gif")})},this.getBlob=function(callback){var output={};return this.audioRecorder&&(output.audio=this.audioRecorder.getBlob()),this.videoRecorder&&(output.video=this.videoRecorder.getBlob()),this.gifRecorder&&(output.gif=this.gifRecorder.getBlob()),callback&&callback(output),output},this.getDataURL=function(callback){function getDataURL(blob,callback00){if("undefined"!=typeof Worker){var webWorker=processInWebWorker(function(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))});webWorker.onmessage=function(event){callback00(event.data)},webWorker.postMessage(blob)}else{var reader=new FileReader;reader.readAsDataURL(blob),reader.onload=function(event){callback00(event.target.result)}}}function processInWebWorker(_function){var url,blob=URL.createObjectURL(new Blob([_function.toString(),"this.onmessage = function (e) {"+_function.name+"(e.data);}"],{type:"application/javascript"})),worker=new Worker(blob);if("undefined"!=typeof URL)url=URL;else{if("undefined"==typeof webkitURL)throw"Neither URL nor webkitURL detected.";url=webkitURL}return url.revokeObjectURL(blob),worker}this.getBlob(function(blob){getDataURL(blob.audio,function(_audioDataURL){getDataURL(blob.video,function(_videoDataURL){callback({audio:_audioDataURL,video:_videoDataURL})})})})},this.writeToDisk=function(){RecordRTC.writeToDisk({audio:this.audioRecorder,video:this.videoRecorder,gif:this.gifRecorder})},this.save=function(args){args=args||{audio:!0,video:!0,gif:!0},args.audio&&this.audioRecorder&&this.audioRecorder.save("string"==typeof args.audio?args.audio:""),args.video&&this.videoRecorder&&this.videoRecorder.save("string"==typeof args.video?args.video:""),args.gif&&this.gifRecorder&&this.gifRecorder.save("string"==typeof args.gif?args.gif:"")}}function bytesToSize(bytes){var k=1e3,sizes=["Bytes","KB","MB","GB","TB"];if(0===bytes)return"0 Bytes";var i=parseInt(Math.floor(Math.log(bytes)/Math.log(k)),10);return(bytes/Math.pow(k,i)).toPrecision(3)+" "+sizes[i]}function invokeSaveAsDialog(file,fileName){if(!file)throw"Blob object is required.";if(!file.type)try{file.type="video/webm"}catch(e){}var fileExtension=(file.type||"video/webm").split("/")[1];if(fileName&&-1!==fileName.indexOf(".")){var splitted=fileName.split(".");fileName=splitted[0],fileExtension=splitted[1]}var fileFullName=(fileName||Math.round(9999999999*Math.random())+888888888)+"."+fileExtension;if("undefined"!=typeof navigator.msSaveOrOpenBlob)return navigator.msSaveOrOpenBlob(file,fileFullName);if("undefined"!=typeof navigator.msSaveBlob)return navigator.msSaveBlob(file,fileFullName);var hyperlink=document.createElement("a");hyperlink.href=URL.createObjectURL(file),hyperlink.target="_blank",hyperlink.download=fileFullName,navigator.mozGetUserMedia&&(hyperlink.onclick=function(){(document.body||document.documentElement).removeChild(hyperlink)},(document.body||document.documentElement).appendChild(hyperlink));var evt=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!0});hyperlink.dispatchEvent(evt),navigator.mozGetUserMedia||URL.revokeObjectURL(hyperlink.href)}function isMediaRecorderCompatible(){var isOpera=!!window.opera||navigator.userAgent.indexOf(" OPR/")>=0,isChrome=!!window.chrome&&!isOpera,isFirefox="undefined"!=typeof window.InstallTrigger;if(isFirefox)return!0;if(!isChrome)return!1;var verOffset,ix,nAgt=(navigator.appVersion,navigator.userAgent),fullVersion=""+parseFloat(navigator.appVersion),majorVersion=parseInt(navigator.appVersion,10);return isChrome&&(verOffset=nAgt.indexOf("Chrome"),fullVersion=nAgt.substring(verOffset+7)),-1!==(ix=fullVersion.indexOf(";"))&&(fullVersion=fullVersion.substring(0,ix)),-1!==(ix=fullVersion.indexOf(" "))&&(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 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(config=config||{mimeType:"video/webm"},"audio"===config.type){if(mediaStream.getVideoTracks().length&&mediaStream.getAudioTracks().length){var stream;navigator.mozGetUserMedia?(stream=new MediaStream,stream.addTrack(mediaStream.getAudioTracks()[0])):stream=new MediaStream(mediaStream.getAudioTracks()),mediaStream=stream}config.mimeType&&-1!==config.mimeType.indexOf("audio")||(config.mimeType=isChrome?"audio/webm":"audio/ogg")}this.record=function(){self.blob=null;var recorderHints=config;config.disableLogs||console.log("Passing following config over MediaRecorder API.",recorderHints),mediaRecorder&&(mediaRecorder=null),isChrome&&!isMediaRecorderCompatible()&&(recorderHints="video/vp8"),mediaRecorder=new MediaRecorder(mediaStream,recorderHints),"canRecordMimeType"in mediaRecorder&&mediaRecorder.canRecordMimeType(config.mimeType)===!1&&(config.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",config.mimeType)),mediaRecorder.ignoreMutedMedia=config.ignoreMutedMedia||!1,mediaRecorder.ondataavailable=function(e){self.dontFireOnDataAvailableEvent||!e.data||!e.data.size||e.data.size<100||self.blob||(self.blob=config.getNativeBlob?e.data:new Blob([e.data],{type:config.mimeType||"video/webm"}),self.recordingCallback&&(self.recordingCallback(self.blob),self.recordingCallback=null))},mediaRecorder.onerror=function(error){config.disableLogs||("InvalidState"===error.name?console.error("The MediaRecorder is not in a state in which the proposed operation is allowed to be executed."):"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."):"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."):"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."):"GenericError"===error.name?console.error("The UA cannot provide the codec or recording option that has been requested.",error):console.error("MediaRecorder Error",error)),"inactive"!==mediaRecorder.state&&"stopped"!==mediaRecorder.state&&mediaRecorder.stop()},mediaRecorder.start(36e5),config.onAudioProcessStarted&&config.onAudioProcessStarted(),config.initCallback&&config.initCallback()},this.stop=function(callback){mediaRecorder&&(this.recordingCallback=callback||function(){},"recording"===mediaRecorder.state&&(mediaRecorder.requestData(),mediaRecorder.stop()))},this.pause=function(){mediaRecorder&&"recording"===mediaRecorder.state&&mediaRecorder.pause()},this.resume=function(){if(this.dontFireOnDataAvailableEvent){this.dontFireOnDataAvailableEvent=!1;var disableLogs=config.disableLogs;return config.disableLogs=!0,this.record(),void(config.disableLogs=disableLogs)}mediaRecorder&&"paused"===mediaRecorder.state&&mediaRecorder.resume()},this.clearRecordedData=function(){mediaRecorder&&(this.pause(),this.dontFireOnDataAvailableEvent=!0,this.stop())};var mediaRecorder,self=this;!function looper(){return mediaRecorder?isMediaStreamActive()===!1?(config.disableLogs||console.log("MediaStream seems stopped."),void self.stop()):void setTimeout(looper,1e3):void 0}()}function StereoAudioRecorder(mediaStream,config){function isMediaStreamActive(){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 mergeBuffers(channelBuffer,rLength){for(var result=new Float64Array(rLength),offset=0,lng=channelBuffer.length,i=0;lng>i;i++){var buffer=channelBuffer[i];result.set(buffer,offset),offset+=buffer.length}return result}function interleave(leftChannel,rightChannel){for(var length=leftChannel.length+rightChannel.length,result=new Float64Array(length),inputIndex=0,index=0;length>index;)result[index++]=leftChannel[inputIndex],result[index++]=rightChannel[inputIndex],inputIndex++;return result}function writeUTFBytes(view,offset,string){for(var lng=string.length,i=0;lng>i;i++)view.setUint8(offset+i,string.charCodeAt(i))}var numberOfAudioChannels=config.numberOfAudioChannels,leftBuffers=config.leftBuffers.slice(0),rightBuffers=config.rightBuffers.slice(0),sampleRate=config.sampleRate,internalInterleavedLength=config.internalInterleavedLength;2===numberOfAudioChannels&&(leftBuffers=mergeBuffers(leftBuffers,internalInterleavedLength),rightBuffers=mergeBuffers(rightBuffers,internalInterleavedLength)),1===numberOfAudioChannels&&(leftBuffers=mergeBuffers(leftBuffers,internalInterleavedLength));var interleaved;2===numberOfAudioChannels&&(interleaved=interleave(leftBuffers,rightBuffers)),1===numberOfAudioChannels&&(interleaved=leftBuffers);var interleavedLength=interleaved.length,resultingBufferLength=44+2*interleavedLength,buffer=new ArrayBuffer(resultingBufferLength),view=new DataView(buffer);writeUTFBytes(view,0,"RIFF"),view.setUint32(4,44+2*interleavedLength,!0),writeUTFBytes(view,8,"WAVE"),writeUTFBytes(view,12,"fmt "),view.setUint32(16,16,!0),view.setUint16(20,1,!0),view.setUint16(22,numberOfAudioChannels,!0),view.setUint32(24,sampleRate,!0),view.setUint32(28,2*sampleRate,!0),view.setUint16(32,2*numberOfAudioChannels,!0),view.setUint16(34,16,!0),writeUTFBytes(view,36,"data"),view.setUint32(40,2*interleavedLength,!0);for(var lng=interleavedLength,index=44,volume=1,i=0;lng>i;i++)view.setInt16(index,interleaved[i]*(32767*volume),!0),index+=2;return cb?cb({buffer:buffer,view:view}):void postMessage({buffer:buffer,view:view})}if(!isChrome)return void mergeAudioBuffers(config,function(data){callback(data.buffer,data.view)});var webWorker=processInWebWorker(mergeAudioBuffers);webWorker.onmessage=function(event){callback(event.data.buffer,event.data.view),URL.revokeObjectURL(webWorker.workerURL)},webWorker.postMessage(config)}function processInWebWorker(_function){var workerURL=URL.createObjectURL(new Blob([_function.toString(),";this.onmessage = function (e) {"+_function.name+"(e.data);}"],{type:"application/javascript"})),worker=new Worker(workerURL);return worker.workerURL=workerURL,worker}function onAudioProcessDataAvailable(e){if(!isPaused){if(isMediaStreamActive()===!1&&(config.disableLogs||console.log("MediaStream seems stopped."),jsAudioNode.disconnect(),recording=!1),!recording)return void audioInput.disconnect();isAudioProcessStarted||(isAudioProcessStarted=!0,config.onAudioProcessStarted&&config.onAudioProcessStarted(),config.initCallback&&config.initCallback());var left=e.inputBuffer.getChannelData(0);if(leftchannel.push(new Float32Array(left)),2===numberOfAudioChannels){var right=e.inputBuffer.getChannelData(1);rightchannel.push(new Float32Array(right))}recordingLength+=bufferSize}}if(!mediaStream.getAudioTracks().length)throw"Your stream has no audio tracks.";config=config||{};var jsAudioNode,self=this,leftchannel=[],rightchannel=[],recording=!1,recordingLength=0,numberOfAudioChannels=2;config.leftChannel===!0&&(numberOfAudioChannels=1),1===config.numberOfAudioChannels&&(numberOfAudioChannels=1),config.disableLogs||console.debug("StereoAudioRecorder is set to record number of channels: ",numberOfAudioChannels),this.record=function(){if(isMediaStreamActive()===!1)throw"Please make sure MediaStream is active.";leftchannel.length=rightchannel.length=0,recordingLength=0,audioInput&&audioInput.connect(jsAudioNode),isAudioProcessStarted=isPaused=!1,recording=!0},this.stop=function(callback){recording=!1,mergeLeftRightBuffers({sampleRate:sampleRate,numberOfAudioChannels:numberOfAudioChannels,internalInterleavedLength:recordingLength,leftBuffers:leftchannel,rightBuffers:1===numberOfAudioChannels?[]:rightchannel},function(buffer,view){self.blob=new Blob([view],{type:"audio/wav"}),self.buffer=new ArrayBuffer(view.buffer.byteLength),self.view=view,self.sampleRate=sampleRate,self.bufferSize=bufferSize,self.length=recordingLength,callback&&callback(),isAudioProcessStarted=!1})},Storage.AudioContextConstructor||(Storage.AudioContextConstructor=new Storage.AudioContext);var context=Storage.AudioContextConstructor,audioInput=context.createMediaStreamSource(mediaStream),legalBufferValues=[0,256,512,1024,2048,4096,8192,16384],bufferSize="undefined"==typeof config.bufferSize?4096:config.bufferSize;if(-1===legalBufferValues.indexOf(bufferSize)&&(config.disableLogs||console.warn("Legal values for buffer-size are "+JSON.stringify(legalBufferValues,null," "))),context.createJavaScriptNode)jsAudioNode=context.createJavaScriptNode(bufferSize,numberOfAudioChannels,numberOfAudioChannels);else{if(!context.createScriptProcessor)throw"WebAudio API has no support on this browser.";jsAudioNode=context.createScriptProcessor(bufferSize,numberOfAudioChannels,numberOfAudioChannels)}audioInput.connect(jsAudioNode),config.bufferSize||(bufferSize=jsAudioNode.bufferSize);var sampleRate="undefined"!=typeof config.sampleRate?config.sampleRate:context.sampleRate||44100;(22050>sampleRate||sampleRate>96e3)&&(config.disableLogs||console.warn("sample-rate must be under range 22050 and 96000.")),config.disableLogs||(console.log("sample-rate",sampleRate),console.log("buffer-size",bufferSize));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.info("Seems recording has been restarted."),void this.record())},this.clearRecordedData=function(){this.pause(),leftchannel.length=rightchannel.length=0,recordingLength=0};var isAudioProcessStarted=!1;jsAudioNode.onaudioprocess=onAudioProcessDataAvailable,jsAudioNode.connect(context.destination)}function CanvasRecorder(htmlElement,config){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&&"canvas"!==htmlElement.nodeName.toLowerCase())throw"Please link: //cdn.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)}),(window.webkitRTCPeerConnection||window.webkitGetUserMedia)&&(isCanvasSupportsStreamCapturing=!1);var globalCanvas,globalContext,mediaStreamRecorder;isCanvasSupportsStreamCapturing?(config.disableLogs||console.debug("Your browser supports both MediRecorder API and canvas.captureStream!"),globalCanvas=document.createElement("canvas"),globalCanvas.width=htmlElement.clientWidth||window.innerWidth,globalCanvas.height=htmlElement.clientHeight||window.innerHeight,globalCanvas.style="top: -9999999; left: -99999999; visibility:hidden; position:absoluted; display: none;",(document.body||document.documentElement).appendChild(globalCanvas),globalContext=globalCanvas.getContext("2d")):navigator.mozGetUserMedia&&(config.disableLogs||alert("Canvas recording is NOT supported in Firefox."));var isRecording;this.record=function(){if(isRecording=!0,isCanvasSupportsStreamCapturing){var canvasMediaStream;"captureStream"in globalCanvas?canvasMediaStream=globalCanvas.captureStream(25):"mozCaptureStream"in globalCanvas?canvasMediaStream=globalCanvas.captureStream(25):"webkitCaptureStream"in globalCanvas&&(canvasMediaStream=globalCanvas.captureStream(25));try{var mdStream=new MediaStream;mdStream.addTrack(canvasMediaStream.getVideoTracks()[0]),canvasMediaStream=mdStream}catch(e){}if(!canvasMediaStream)throw"captureStream API are NOT available.";mediaStreamRecorder=new MediaStreamRecorder(canvasMediaStream,{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;document.title=framesRemaining+"/"+framesLength+" frames remaining",config.onEncodingCallback&&config.onEncodingCallback(framesRemaining,framesLength);var webp=frame.image.toDataURL("image/webp",1);whammy.frames[idx].image=webp}),document.title="Generating WebM",callback()},this.stop=function(callback){isRecording=!1;var that=this;if(isCanvasSupportsStreamCapturing&&mediaStreamRecorder){return void mediaStreamRecorder.stop(function(){for(var prop in mediaStreamRecorder)self[prop]=mediaStreamRecorder[prop];callback&&callback(that.blob)})}this.getWebPImages(function(){whammy.compile(function(blob){document.title="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(){isPausedRecording=!0},this.resume=function(){isPausedRecording=!1,isRecording||this.record()},this.clearRecordedData=function(){this.pause(),whammy.frames=[]};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,loop=function(){return i++,i===length?void o.callback():void o.functionToLoop(loop,i)};loop()}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=-1===_framesToCheck,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&&1>=_pixTolerance?_pixTolerance:0,frameTolerance=_frameTolerance&&_frameTolerance>=0&&1>=_frameTolerance?_frameTolerance:0,doNotCheckNext=!1;asyncLoop({length:endCheckFrame,functionToLoop:function(loop,f){var matchPixCount,endPixCheck,maxPixCount,finishImage=function(){!doNotCheckNext&&maxPixCount*frameTolerance>=maxPixCount-matchPixCount||(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;endPixCheck>pix;pix+=4){var currentColor={r:imageData.data[pix],g:imageData.data[pix+1],b:imageData.data[pix+2]},colorDifference=Math.sqrt(Math.pow(currentColor.r-sampleColor.r,2)+Math.pow(currentColor.g-sampleColor.g,2)+Math.pow(currentColor.b-sampleColor.b,2));maxColorDifference*pixTolerance>=colorDifference&&matchPixCount++}finishImage()},image.src=_frames[f].image}},callback:function(){resultFrames=resultFrames.concat(_frames.slice(endCheckFrame)),resultFrames.length<=0&&resultFrames.push(_frames[_frames.length-1]),callback(resultFrames)}})}config=config||{},config.frameInterval||(config.frameInterval=10),config.disableLogs||console.log("Using frames-interval:",config.frameInterval),this.record=function(){config.width||(config.width=320),config.height||(config.height=240),config.video||(config.video={width:config.width,height:config.height}),config.canvas||(config.canvas={width:config.width,height:config.height}),canvas.width=config.canvas.width,canvas.height=config.canvas.height,context=canvas.getContext("2d"),config.video&&config.video instanceof HTMLVideoElement?(video=config.video.cloneNode(),config.initCallback&&config.initCallback()):(video=document.createElement("video"),"undefined"!=typeof video.srcObject?video.srcObject=mediaStream:video.src=URL.createObjectURL(mediaStream),video.onloadedmetadata=function(){config.initCallback&&config.initCallback()},video.width=config.video.width,video.height=config.video.height),video.muted=!0,video.play(),lastTime=(new Date).getTime(),whammy=new Whammy.Video,config.disableLogs||(console.log("canvas resolutions",canvas.width,"*",canvas.height),console.log("video width/height",video.width||canvas.width,"*",video.height||canvas.height)),drawFrames(config.frameInterval)};var isStopDrawing=!1;this.stop=function(callback){isStopDrawing=!0;var _this=this;setTimeout(function(){dropBlackFrames(whammy.frames,-1,null,null,function(frames){whammy.frames=frames,config.advertisement&&config.advertisement.length&&(whammy.frames=config.advertisement.concat(whammy.frames)),whammy.compile(function(blob){_this.blob=blob,_this.blob.forEach&&(_this.blob=new Blob([],{type:"video/webm"})),callback&&callback(_this.blob)})})},10)};var isPausedRecording=!1;this.pause=function(){isPausedRecording=!0},this.resume=function(){isPausedRecording=!1,isStopDrawing&&this.record(); -},this.clearRecordedData=function(){this.pause(),whammy.frames=[]};var video,lastTime,whammy,canvas=document.createElement("canvas"),context=canvas.getContext("2d")}function GifRecorder(mediaStream,config){if("undefined"==typeof GIFEncoder)throw"Please link: https://cdn.webrtc-experiment.com/gif-recorder.js";config=config||{};var isHTMLObject=mediaStream instanceof CanvasRenderingContext2D||mediaStream instanceof HTMLCanvasElement;this.record=function(){function drawVideoFrame(time){return isPausedRecording?setTimeout(function(){drawVideoFrame(time)},100):(lastAnimationFrame=requestAnimationFrame(drawVideoFrame),void 0===typeof lastFrameTime&&(lastFrameTime=time),void(90>time-lastFrameTime||(!isHTMLObject&&video.paused&&(video.play(),context.drawImage(video,0,0,canvas.width,canvas.height)),config.onGifPreview&&config.onGifPreview(canvas.toDataURL("image/png")),gifEncoder.addFrame(context),lastFrameTime=time)))}isHTMLObject||(config.width||(config.width=video.offsetWidth||320),this.height||(config.height=video.offsetHeight||240),config.video||(config.video={width:config.width,height:config.height}),config.canvas||(config.canvas={width:config.width,height:config.height}),canvas.width=config.canvas.width,canvas.height=config.canvas.height,video.width=config.video.width,video.height=config.video.height),gifEncoder=new GIFEncoder,gifEncoder.setRepeat(0),gifEncoder.setDelay(config.frameRate||200),gifEncoder.setQuality(config.quality||10),gifEncoder.start(),startTime=Date.now();lastAnimationFrame=requestAnimationFrame(drawVideoFrame),config.initCallback&&config.initCallback()},this.stop=function(){lastAnimationFrame&&cancelAnimationFrame(lastAnimationFrame),endTime=Date.now(),this.blob=new Blob([new Uint8Array(gifEncoder.stream().bin)],{type:"image/gif"}),gifEncoder.stream().bin=[]};var isPausedRecording=!1;this.pause=function(){isPausedRecording=!0},this.resume=function(){isPausedRecording=!1},this.clearRecordedData=function(){gifEncoder&&(this.pause(),gifEncoder.stream().bin=[])};var canvas=document.createElement("canvas"),context=canvas.getContext("2d");if(isHTMLObject&&(mediaStream instanceof CanvasRenderingContext2D?(context=mediaStream,canvas=context.canvas):mediaStream instanceof HTMLCanvasElement&&(context=mediaStream.getContext("2d"),canvas=mediaStream)),!isHTMLObject){var video=document.createElement("video");video.muted=!0,video.autoplay=!0,"undefined"!=typeof video.srcObject?video.srcObject=mediaStream:video.src=URL.createObjectURL(mediaStream),video.play()}var startTime,endTime,lastFrameTime,gifEncoder,lastAnimationFrame=null}if(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})})},"undefined"!=typeof module&&(module.exports=RecordRTC),"function"==typeof define&&define.amd&&define("RecordRTC",[],function(){return RecordRTC}),MRecordRTC.getFromDisk=RecordRTC.getFromDisk,MRecordRTC.writeToDisk=RecordRTC.writeToDisk,"undefined"!=typeof RecordRTC&&(RecordRTC.MRecordRTC=MRecordRTC),"undefined"==typeof window&&"undefined"!=typeof global){global.navigator={userAgent:""};var window=global}var requestAnimationFrame=window.requestAnimationFrame;"undefined"==typeof requestAnimationFrame&&("undefined"!=typeof webkitRequestAnimationFrame&&(requestAnimationFrame=webkitRequestAnimationFrame),"undefined"!=typeof mozRequestAnimationFrame&&(requestAnimationFrame=mozRequestAnimationFrame));var cancelAnimationFrame=window.cancelAnimationFrame;"undefined"==typeof cancelAnimationFrame&&("undefined"!=typeof webkitCancelAnimationFrame&&(cancelAnimationFrame=webkitCancelAnimationFrame),"undefined"!=typeof mozCancelAnimationFrame&&(cancelAnimationFrame=mozCancelAnimationFrame));var AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;if("undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"==typeof navigator)throw'Please make sure to define a global variable named as "navigator"';"undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia);var isEdge=!(-1===navigator.userAgent.indexOf("Edge")||!navigator.msSaveBlob&&!navigator.msSaveOrOpenBlob),isOpera=!!window.opera||-1!==navigator.userAgent.indexOf("OPR/"),isChrome=!isOpera&&!isEdge&&!!navigator.webkitGetUserMedia,MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&("getVideoTracks"in MediaStream.prototype||(MediaStream.prototype.getVideoTracks=function(){if(!this.getTracks)return[];var tracks=[];return this.getTracks.forEach(function(track){-1!==track.kind.toString().indexOf("video")&&tracks.push(track)}),tracks},MediaStream.prototype.getAudioTracks=function(){if(!this.getTracks)return[];var tracks=[];return this.getTracks.forEach(function(track){-1!==track.kind.toString().indexOf("audio")&&tracks.push(track)}),tracks}),"stop"in MediaStream.prototype||(MediaStream.prototype.stop=function(){this.getAudioTracks().forEach(function(track){track.stop&&track.stop()}),this.getVideoTracks().forEach(function(track){track.stop&&track.stop()})})),"undefined"!=typeof location&&0===location.href.indexOf("file:")&&console.error("Please load this HTML file on HTTP or HTTPS.");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 (e) {"+_function.name+"(e.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;frameNumberclusterDuration);var clusterCounter=0,cluster={id:524531317,data:getClusterData(clusterTimecode,clusterCounter,clusterFrames)};EBML[1].data.push(cluster),clusterTimecode+=clusterDuration}return generateEBML(EBML)}function getClusterData(clusterTimecode,clusterCounter,clusterFrames){return[{data:clusterTimecode,id:231}].concat(clusterFrames.map(function(webp){var block=makeSimpleBlock({discardable:0,frame:webp.data.slice(4),invisible:0,keyframe:1,lacing:0,trackNum:1,timecode:Math.round(clusterCounter)});return clusterCounter+=webp.duration,{data:block,id:163}}))}function checkFrames(frames){if(!frames[0])return void postMessage({error:"Something went wrong. Maybe WebP format is not supported in the current browser."});for(var width=frames[0].width,height=frames[0].height,duration=frames[0].duration,i=1;i0;)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=[];4>i;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",R(n.size)),e){var r;try{r=m.createObjectURL(n)}catch(e){}"function"==typeof e.call?e.call(o,r):e(r)}t.autoWriteToDisk&&c((function(e){var o={};o[t.type+"Blob"]=e,O.Store(o)}))}else"function"==typeof e.call?e.call(o,""):e("")}}function s(e){postMessage((new FileReaderSync).readAsDataURL(e))}function c(e,o){if(!e)throw"Pass a callback function over getDataURL.";var i=o?o.blob:(f||{}).blob;if(!i)return t.disableLogs||console.warn("Blob encoder did not finish its job yet."),void setTimeout((function(){c(e,o)}),1e3);if("undefined"==typeof Worker||navigator.mozGetUserMedia){var n=new FileReader;n.readAsDataURL(i),n.onload=function(t){e(t.target.result)}}else{var r=function(e){try{var t=m.createObjectURL(new Blob([e.toString(),"this.onmessage = function (eee) {"+e.name+"(eee.data);}"],{type:"application/javascript"})),o=new Worker(t);return m.revokeObjectURL(t),o}catch(e){}}(s);r.onmessage=function(t){e(t.data)},r.postMessage(i)}}function u(e){e=e||0,"paused"!==o.state?"stopped"!==o.state&&(e>=o.recordingDuration?n(o.onRecordingStopped):(e+=1e3,setTimeout((function(){u(e)}),1e3))):setTimeout((function(){u(e)}),1e3)}function l(e){o&&(o.state=e,"function"==typeof o.onStateChanged.call?o.onStateChanged.call(o,e):o.onStateChanged(e))}var f,h='It seems that recorder is destroyed or "startRecording" is not invoked for '+t.type+" recorder.";function g(){!0!==t.disableLogs&&console.warn(h)}var p={startRecording:function(n){return t.disableLogs||console.log("RecordRTC version: ",o.version),n&&(t=new a(e,n)),t.disableLogs||console.log("started recording "+t.type+" stream."),f?(f.clearRecordedData(),f.record(),l("recording"),o.recordingDuration&&u(),o):(i((function(){o.recordingDuration&&u()})),o)},stopRecording:n,pauseRecording:function(){f?"recording"===o.state?(l("paused"),f.pause(),t.disableLogs||console.log("Paused recording.")):t.disableLogs||console.warn("Unable to pause the recording. Recording state: ",o.state):g()},resumeRecording:function(){f?"paused"===o.state?(l("recording"),f.resume(),t.disableLogs||console.log("Resumed recording.")):t.disableLogs||console.warn("Unable to resume the recording. Recording state: ",o.state):g()},initRecorder:i,setRecordingDuration:function(e,t){if(void 0===e)throw"recordingDuration is required.";if("number"!=typeof e)throw"recordingDuration must be a number.";return o.recordingDuration=e,o.onRecordingStopped=t||function(){},{onRecordingStopped:function(e){o.onRecordingStopped=e}}},clearRecordedData:function(){f?(f.clearRecordedData(),t.disableLogs||console.log("Cleared old recorded data.")):g()},getBlob:function(){if(f)return f.blob;g()},getDataURL:c,toURL:function(){if(f)return m.createObjectURL(f.blob);g()},getInternalRecorder:function(){return f},save:function(e){f?S(f.blob,e):g()},getFromDisk:function(e){f?r.getFromDisk(t.type,e):g()},setAdvertisementArray:function(e){t.advertisement=[];for(var o=e.length,i=0;i-1&&"netscape"in window&&/ rv:/.test(navigator.userAgent),b=!p&&!g&&!!navigator.webkitGetUserMedia||T()||-1!==navigator.userAgent.toLowerCase().indexOf("chrome/"),w=/^((?!chrome|android).)*safari/i.test(navigator.userAgent);w&&!b&&-1!==navigator.userAgent.indexOf("CriOS")&&(w=!1,b=!0);var y=window.MediaStream;function R(e){if(0===e)return"0 Bytes";var t=parseInt(Math.floor(Math.log(e)/Math.log(1e3)),10);return(e/Math.pow(1e3,t)).toPrecision(3)+" "+["Bytes","KB","MB","GB","TB"][t]}function S(e,t){if(!e)throw"Blob object is required.";if(!e.type)try{e.type="video/webm"}catch(e){}var o=(e.type||"video/webm").split("/")[1];if(t&&-1!==t.indexOf(".")){var i=t.split(".");t=i[0],o=i[1]}var n=(t||Math.round(9999999999*Math.random())+888888888)+"."+o;if(void 0!==navigator.msSaveOrOpenBlob)return navigator.msSaveOrOpenBlob(e,n);if(void 0!==navigator.msSaveBlob)return navigator.msSaveBlob(e,n);var r=document.createElement("a");r.href=m.createObjectURL(e),r.download=n,r.style="display:none;opacity:0;color:transparent;",(document.body||document.documentElement).appendChild(r),"function"==typeof r.click?r.click():(r.target="_blank",r.dispatchEvent(new MouseEvent("click",{view:window,bubbles:!0,cancelable:!0}))),m.revokeObjectURL(r.href)}function T(){return"undefined"!=typeof window&&"object"==typeof window.process&&"renderer"===window.process.type||(!(void 0===i||"object"!=typeof i.versions||!i.versions.electron)||"object"==typeof navigator&&"string"==typeof navigator.userAgent&&navigator.userAgent.indexOf("Electron")>=0)}function k(e,t){return e&&e.getTracks?e.getTracks().filter((function(e){return e.kind===(t||"audio")})):[]}function C(e,t){"srcObject"in t?t.srcObject=e:"mozSrcObject"in t?t.mozSrcObject=e:t.srcObject=e}void 0===y&&"undefined"!=typeof webkitMediaStream&&(y=webkitMediaStream),void 0!==y&&void 0===y.prototype.stop&&(y.prototype.stop=function(){this.getTracks().forEach((function(e){e.stop()}))}),void 0!==r&&(r.invokeSaveAsDialog=S,r.getTracks=k,r.getSeekableBlob=function(e,t){if("undefined"==typeof EBML)throw new Error("Please link: https://www.webrtc-experiment.com/EBML.js");var o=new EBML.Reader,i=new EBML.Decoder,n=EBML.tools,r=new FileReader;r.onload=function(e){i.decode(this.result).forEach((function(e){o.read(e)})),o.stop();var r=n.makeMetadataSeekable(o.metadatas,o.duration,o.cues),a=this.result.slice(o.metadataSize),d=new Blob([r,a],{type:"video/webm"});t(d)},r.readAsArrayBuffer(e)},r.bytesToSize=R,r.isElectron=T); +/** + * Storage is a standalone object used by {@link RecordRTC} to store reusable objects e.g. "new AudioContext". + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @example + * Storage.AudioContext === webkitAudioContext + * @property {webkitAudioContext} AudioContext - Keeps a reference to AudioContext object. + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + */ +var L={};function M(){if(v||w||g)return!0;navigator.appVersion;var e,t,o=navigator.userAgent,i=""+parseFloat(navigator.appVersion),n=parseInt(navigator.appVersion,10);return(b||p)&&(e=o.indexOf("Chrome"),i=o.substring(e+7)),-1!==(t=i.indexOf(";"))&&(i=i.substring(0,t)),-1!==(t=i.indexOf(" "))&&(i=i.substring(0,t)),n=parseInt(""+i,10),isNaN(n)&&(i=""+parseFloat(navigator.appVersion),n=parseInt(navigator.appVersion,10)),n>=49} +/** + * MediaStreamRecorder is an abstraction layer for {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. It is used by {@link RecordRTC} to record MediaStream(s) in both Chrome and Firefox. + * @summary Runs top over {@link https://w3c.github.io/mediacapture-record/MediaRecorder.html|MediaRecorder API}. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://github.com/muaz-khan|Muaz Khan} + * @typedef MediaStreamRecorder + * @class + * @example + * var config = { + * mimeType: 'video/webm', // vp8, vp9, h264, mkv, opus/vorbis + * audioBitsPerSecond : 256 * 8 * 1024, + * videoBitsPerSecond : 256 * 8 * 1024, + * bitsPerSecond: 256 * 8 * 1024, // if this is provided, skip above two + * checkForInactiveTracks: true, + * timeSlice: 1000, // concatenate intervals based blobs + * ondataavailable: function() {} // get intervals based blobs + * } + * var recorder = new MediaStreamRecorder(mediaStream, config); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * + * // or + * var blob = recorder.blob; + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. + * @param {object} config - {disableLogs:true, initCallback: function, mimeType: "video/webm", timeSlice: 1000} + * @throws Will throw an error if first argument "MediaStream" is missing. Also throws error if "MediaRecorder API" are not supported by the browser. + */function A(e,t){var o=this;if(void 0===e)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("audio"===(t=t||{mimeType:"video/webm"}).type){var i;if(k(e,"video").length&&k(e,"audio").length)navigator.mozGetUserMedia?(i=new y).addTrack(k(e,"audio")[0]):i=new y(k(e,"audio")),e=i;t.mimeType&&-1!==t.mimeType.toString().toLowerCase().indexOf("audio")||(t.mimeType=b?"audio/webm":"audio/ogg"),t.mimeType&&"audio/ogg"!==t.mimeType.toString().toLowerCase()&&navigator.mozGetUserMedia&&(t.mimeType="audio/ogg")}var n,r=[];function a(){o.timestamps.push((new Date).getTime()),"function"==typeof t.onTimeStamp&&t.onTimeStamp(o.timestamps[o.timestamps.length-1],o.timestamps)}function d(e){return n&&n.mimeType?n.mimeType:e.mimeType||"video/webm"}function s(){r=[],n=null,o.timestamps=[]}this.getArrayOfBlobs=function(){return r},this.record=function(){o.blob=null,o.clearRecordedData(),o.timestamps=[],c=[],r=[];var i=t;t.disableLogs||console.log("Passing following config over MediaRecorder API.",i),n&&(n=null),b&&!M()&&(i="video/vp8"),"function"==typeof MediaRecorder.isTypeSupported&&i.mimeType&&(MediaRecorder.isTypeSupported(i.mimeType)||(t.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",i.mimeType),i.mimeType="audio"===t.type?"audio/webm":"video/webm"));try{n=new MediaRecorder(e,i),t.mimeType=i.mimeType}catch(t){n=new MediaRecorder(e)}i.mimeType&&!MediaRecorder.isTypeSupported&&"canRecordMimeType"in n&&!1===n.canRecordMimeType(i.mimeType)&&(t.disableLogs||console.warn("MediaRecorder API seems unable to record mimeType:",i.mimeType)),n.ondataavailable=function(e){if(e.data&&c.push("ondataavailable: "+R(e.data.size)),"number"!=typeof t.timeSlice)!e.data||!e.data.size||e.data.size<100||o.blob?o.recordingCallback&&(o.recordingCallback(new Blob([],{type:d(i)})),o.recordingCallback=null):(o.blob=t.getNativeBlob?e.data:new Blob([e.data],{type:d(i)}),o.recordingCallback&&(o.recordingCallback(o.blob),o.recordingCallback=null));else if(e.data&&e.data.size&&(r.push(e.data),a(),"function"==typeof t.ondataavailable)){var n=t.getNativeBlob?e.data:new Blob([e.data],{type:d(i)});t.ondataavailable(n)}},n.onstart=function(){c.push("started")},n.onpause=function(){c.push("paused")},n.onresume=function(){c.push("resumed")},n.onstop=function(){c.push("stopped")},n.onerror=function(e){e&&(e.name||(e.name="UnknownError"),c.push("error: "+e),t.disableLogs||(-1!==e.name.toString().toLowerCase().indexOf("invalidstate")?console.error("The MediaRecorder is not in a state in which the proposed operation is allowed to be executed.",e):-1!==e.name.toString().toLowerCase().indexOf("notsupported")?console.error("MIME type (",i.mimeType,") is not supported.",e):-1!==e.name.toString().toLowerCase().indexOf("security")?console.error("MediaRecorder security error",e):"OutOfMemory"===e.name?console.error("The UA has exhaused the available memory. User agents SHOULD provide as much additional information as possible in the message attribute.",e):"IllegalStreamModification"===e.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.",e):"OtherRecordingError"===e.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.",e):"GenericError"===e.name?console.error("The UA cannot provide the codec or recording option that has been requested.",e):console.error("MediaRecorder Error",e)),function(e){if(!o.manuallyStopped&&n&&"inactive"===n.state)return delete t.timeslice,void n.start(6e5);setTimeout(void 0,1e3)}(),"inactive"!==n.state&&"stopped"!==n.state&&n.stop())},"number"==typeof t.timeSlice?(a(),n.start(t.timeSlice)):n.start(36e5),t.initCallback&&t.initCallback()},this.timestamps=[],this.stop=function(e){e=e||function(){},o.manuallyStopped=!0,n&&(this.recordingCallback=e,"recording"===n.state&&n.stop(),"number"==typeof t.timeSlice&&setTimeout((function(){o.blob=new Blob(r,{type:d(t)}),o.recordingCallback(o.blob)}),100))},this.pause=function(){n&&"recording"===n.state&&n.pause()},this.resume=function(){n&&"paused"===n.state&&n.resume()},this.clearRecordedData=function(){n&&"recording"===n.state&&o.stop(s),s()},this.getInternalRecorder=function(){return n},this.blob=null,this.getState=function(){return n&&n.state||"inactive"};var c=[];this.getAllStates=function(){return c},void 0===t.checkForInactiveTracks&&(t.checkForInactiveTracks=!1);o=this;!function i(){if(n&&!1!==t.checkForInactiveTracks)return!1===function(){if("active"in e){if(!e.active)return!1}else if("ended"in e&&e.ended)return!1;return!0}()?(t.disableLogs||console.log("MediaStream seems stopped."),void o.stop()):void setTimeout(i,1e3)}(),this.name="MediaStreamRecorder",this.toString=function(){return this.name}} +/** + * StereoAudioRecorder is a standalone class used by {@link RecordRTC} to bring "stereo" audio-recording in chrome. + * @summary JavaScript standalone object for stereo audio recording. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef StereoAudioRecorder + * @class + * @example + * var recorder = new StereoAudioRecorder(MediaStream, { + * sampleRate: 44100, + * bufferSize: 4096 + * }); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. + * @param {object} config - {sampleRate: 44100, bufferSize: 4096, numberOfAudioChannels: 1, etc.} + */ +function D(e,t){if(!k(e,"audio").length)throw"Your stream has no audio tracks.";var o,i=this,n=[],a=[],d=!1,s=0,c=2,u=(t=t||{}).desiredSampRate;function l(){if(!1===t.checkForInactiveTracks)return!0;if("active"in e){if(!e.active)return!1}else if("ended"in e&&e.ended)return!1;return!0}function f(e,t){function o(e,t){var o,i=e.numberOfAudioChannels,n=e.leftBuffers.slice(0),r=e.rightBuffers.slice(0),a=e.sampleRate,d=e.internalInterleavedLength,s=e.desiredSampRate;function c(e,t,o){var i=Math.round(e.length*(t/o)),n=[],r=Number((e.length-1)/(i-1));n[0]=e[0];for(var a=1;a96e3)&&(t.disableLogs||console.log("sample-rate must be under range 22050 and 96000.")),t.disableLogs||t.desiredSampRate&&console.log("Desired sample-rate: "+t.desiredSampRate);var w=!1;function y(){n=[],a=[],s=0,S=!1,d=!1,w=!1,h=null,i.leftchannel=n,i.rightchannel=a,i.numberOfAudioChannels=c,i.desiredSampRate=u,i.sampleRate=b,i.recordingLength=s,T={left:[],right:[],recordingLength:0}}function R(){o&&(o.onaudioprocess=null,o.disconnect(),o=null),g&&(g.disconnect(),g=null),y()}this.pause=function(){w=!0},this.resume=function(){if(!1===l())throw"Please make sure MediaStream is active.";if(!d)return t.disableLogs||console.log("Seems recording has been restarted."),void this.record();w=!1},this.clearRecordedData=function(){t.checkForInactiveTracks=!1,d&&this.stop(R),R()},this.name="StereoAudioRecorder",this.toString=function(){return this.name};var S=!1;o.onaudioprocess=function(e){if(!w)if(!1===l()&&(t.disableLogs||console.log("MediaStream seems stopped."),o.disconnect(),d=!1),d){S||(S=!0,t.onAudioProcessStarted&&t.onAudioProcessStarted(),t.initCallback&&t.initCallback());var r=e.inputBuffer.getChannelData(0),u=new Float32Array(r);if(n.push(u),2===c){var f=e.inputBuffer.getChannelData(1),h=new Float32Array(f);a.push(h)}s+=v,i.recordingLength=s,void 0!==t.timeSlice&&(T.recordingLength+=v,T.left.push(u),2===c&&T.right.push(h))}else g&&(g.disconnect(),g=null)},h.createMediaStreamDestination?o.connect(h.createMediaStreamDestination()):o.connect(h.destination),this.leftchannel=n,this.rightchannel=a,this.numberOfAudioChannels=c,this.desiredSampRate=u,this.sampleRate=b,i.recordingLength=s;var T={left:[],right:[],recordingLength:0};function C(){d&&"function"==typeof t.ondataavailable&&void 0!==t.timeSlice&&(T.left.length?(f({desiredSampRate:u,sampleRate:b,numberOfAudioChannels:c,internalInterleavedLength:T.recordingLength,leftBuffers:T.left,rightBuffers:1===c?[]:T.right},(function(e,o){var i=new Blob([o],{type:"audio/wav"});t.ondataavailable(i),setTimeout(C,t.timeSlice)})),T={left:[],right:[],recordingLength:0}):setTimeout(C,t.timeSlice))}} +/** + * CanvasRecorder is a standalone class used by {@link RecordRTC} to bring HTML5-Canvas recording into video WebM. It uses HTML2Canvas library and runs top over {@link Whammy}. + * @summary HTML2Canvas recording into video WebM. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef CanvasRecorder + * @class + * @example + * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true, useWhammyRecorder: true }); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {HTMLElement} htmlElement - querySelector/getElementById/getElementsByTagName[0]/etc. + * @param {object} config - {disableLogs:true, initCallback: function} + */ +function x(e,t){if("undefined"==typeof html2canvas)throw"Please link: https://www.webrtc-experiment.com/screenshot.js";(t=t||{}).frameInterval||(t.frameInterval=10);var o=!1;["captureStream","mozCaptureStream","webkitCaptureStream"].forEach((function(e){e in document.createElement("canvas")&&(o=!0)}));var i,n,r,a=!(!window.webkitRTCPeerConnection&&!window.webkitGetUserMedia||!window.chrome),d=50,s=navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);if(a&&s&&s[2]&&(d=parseInt(s[2],10)),a&&d<52&&(o=!1),t.useWhammyRecorder&&(o=!1),o)if(t.disableLogs||console.log("Your browser supports both MediRecorder API and canvas.captureStream!"),e instanceof HTMLCanvasElement)i=e;else{if(!(e instanceof CanvasRenderingContext2D))throw"Please pass either HTMLCanvasElement or CanvasRenderingContext2D.";i=e.canvas}else navigator.mozGetUserMedia&&(t.disableLogs||console.error("Canvas recording is NOT supported in Firefox."));this.record=function(){if(r=!0,o&&!t.useWhammyRecorder){var e;"captureStream"in i?e=i.captureStream(25):"mozCaptureStream"in i?e=i.mozCaptureStream(25):"webkitCaptureStream"in i&&(e=i.webkitCaptureStream(25));try{var a=new y;a.addTrack(k(e,"video")[0]),e=a}catch(e){}if(!e)throw"captureStream API are NOT available.";(n=new A(e,{mimeType:t.mimeType||"video/webm"})).record()}else h.frames=[],f=(new Date).getTime(),l();t.initCallback&&t.initCallback()},this.getWebPImages=function(o){if("canvas"===e.nodeName.toLowerCase()){var i=h.frames.length;h.frames.forEach((function(e,o){var n=i-o;t.disableLogs||console.log(n+"/"+i+" frames remaining"),t.onEncodingCallback&&t.onEncodingCallback(n,i);var r=e.image.toDataURL("image/webp",1);h.frames[o].image=r})),t.disableLogs||console.log("Generating WebM"),o()}else o()},this.stop=function(e){r=!1;var i=this;o&&n?n.stop(e):this.getWebPImages((function(){h.compile((function(o){t.disableLogs||console.log("Recording finished!"),i.blob=o,i.blob.forEach&&(i.blob=new Blob([],{type:"video/webm"})),e&&e(i.blob),h.frames=[]}))}))};var c=!1;function u(){h.frames=[],r=!1,c=!1}function l(){if(c)return f=(new Date).getTime(),setTimeout(l,500);if("canvas"===e.nodeName.toLowerCase()){var o=(new Date).getTime()-f;return f=(new Date).getTime(),h.frames.push({image:(i=document.createElement("canvas"),n=i.getContext("2d"),i.width=e.width,i.height=e.height,n.drawImage(e,0,0),i),duration:o}),void(r&&setTimeout(l,t.frameInterval))}var i,n;html2canvas(e,{grabMouse:void 0===t.showMousePointer||t.showMousePointer,onrendered:function(e){var o=(new Date).getTime()-f;if(!o)return setTimeout(l,t.frameInterval);f=(new Date).getTime(),h.frames.push({image:e.toDataURL("image/webp",1),duration:o}),r&&setTimeout(l,t.frameInterval)}})}this.pause=function(){c=!0,n instanceof A&&n.pause()},this.resume=function(){c=!1,n instanceof A?n.resume():r||this.record()},this.clearRecordedData=function(){r&&this.stop(u),u()},this.name="CanvasRecorder",this.toString=function(){return this.name};var f=(new Date).getTime(),h=new B.Video(100)} +/** + * WhammyRecorder is a standalone class used by {@link RecordRTC} to bring video recording in Chrome. It runs top over {@link Whammy}. + * @summary Video recording feature in Chrome. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef WhammyRecorder + * @class + * @example + * var recorder = new WhammyRecorder(mediaStream); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. + * @param {object} config - {disableLogs: true, initCallback: function, video: HTMLVideoElement, etc.} + */ +function U(e,t){function o(e){e=void 0!==e?e:10;var t=(new Date).getTime()-s;return t?r?(s=(new Date).getTime(),setTimeout(o,100)):(s=(new Date).getTime(),d.paused&&d.play(),l.drawImage(d,0,0,u.width,u.height),c.frames.push({duration:t,image:u.toDataURL("image/webp")}),void(n||setTimeout(o,e,e))):setTimeout(o,e,e)}function i(e,t,o,i,n){var r=document.createElement("canvas");r.width=u.width,r.height=u.height;var a,d,s,c=r.getContext("2d"),l=[],f=-1===t,h=t&&t>0&&t<=e.length?t:e.length,m=0,g=0,p=0,v=Math.sqrt(Math.pow(255,2)+Math.pow(255,2)+Math.pow(255,2)),b=o&&o>=0&&o<=1?o:0,w=i&&i>=0&&i<=1?i:0,y=!1;d=-1,s=(a={length:h,functionToLoop:function(t,o){var i,n,r,a=function(){!y&&r-i<=r*w||(f&&(y=!0),l.push(e[o])),t()};if(y)a();else{var d=new Image;d.onload=function(){c.drawImage(d,0,0,u.width,u.height);var e=c.getImageData(0,0,u.width,u.height);i=0,n=e.data.length,r=e.data.length/4;for(var t=0;t127)throw"TrackNumber > 127 not supported";return[128|e.trackNum,e.timecode>>8,255&e.timecode,t].map((function(e){return String.fromCharCode(e)})).join("")+e.frame}({discardable:0,frame:e.data.slice(4),invisible:0,keyframe:1,lacing:0,trackNum:1,timecode:Math.round(t)});return t+=e.duration,{data:o,id:163}})))}function o(e){for(var t=[];e>0;)t.push(255&e),e>>=8;return new Uint8Array(t.reverse())}function i(e){return new Uint8Array(e.split("").map((function(e){return e.charCodeAt(0)})))}function n(e){var t=[];e=(e.length%8?new Array(9-e.length%8).join("0"):"")+e;for(var o=0;o1?2*o[0].width:o[0].width;var r=1;3!==e&&4!==e||(r=2),5!==e&&6!==e||(r=3),7!==e&&8!==e||(r=4),9!==e&&10!==e||(r=5),a.height=o[0].height*r}else a.width=s.width||360,a.height=s.height||240;t&&t instanceof HTMLVideoElement&&m(t),o.forEach((function(e,t){m(e,t)})),setTimeout(h,s.frameInterval)}}function m(e,t){if(!n){var o=0,i=0,r=e.width,a=e.height;1===t&&(o=e.width),2===t&&(i=e.height),3===t&&(o=e.width,i=e.height),4===t&&(i=2*e.height),5===t&&(o=e.width,i=2*e.height),6===t&&(i=3*e.height),7===t&&(o=e.width,i=3*e.height),void 0!==e.stream.left&&(o=e.stream.left),void 0!==e.stream.top&&(i=e.stream.top),void 0!==e.stream.width&&(r=e.stream.width),void 0!==e.stream.height&&(a=e.stream.height),d.drawImage(e,o,i,r,a),"function"==typeof e.stream.onRender&&e.stream.onRender(d,o,i,r,a,t)}}function g(e){var o=document.createElement("video");return function(e,t){"srcObject"in t?t.srcObject=e:"mozSrcObject"in t?t.mozSrcObject=e:t.srcObject=e}(e,o),o.className=t,o.muted=!0,o.volume=0,o.width=e.width||s.width||360,o.height=e.height||s.height||240,o.play(),o}function p(t){i=[],(t=t||e).forEach((function(e){if(e.getTracks().filter((function(e){return"video"===e.kind})).length){var t=g(e);t.stream=e,i.push(t)}}))}void 0!==c?f.AudioContext=c:"undefined"!=typeof webkitAudioContext&&(f.AudioContext=webkitAudioContext),this.startDrawingFrames=function(){h()},this.appendStreams=function(t){if(!t)throw"First parameter is required.";t instanceof Array||(t=[t]),t.forEach((function(t){var o=new l;if(t.getTracks().filter((function(e){return"video"===e.kind})).length){var n=g(t);n.stream=t,i.push(n),o.addTrack(t.getTracks().filter((function(e){return"video"===e.kind}))[0])}if(t.getTracks().filter((function(e){return"audio"===e.kind})).length){var r=s.audioContext.createMediaStreamSource(t);s.audioDestination=s.audioContext.createMediaStreamDestination(),r.connect(s.audioDestination),o.addTrack(s.audioDestination.stream.getTracks().filter((function(e){return"audio"===e.kind}))[0])}e.push(o)}))},this.releaseStreams=function(){i=[],n=!0,s.gainNode&&(s.gainNode.disconnect(),s.gainNode=null),s.audioSources.length&&(s.audioSources.forEach((function(e){e.disconnect()})),s.audioSources=[]),s.audioDestination&&(s.audioDestination.disconnect(),s.audioDestination=null),s.audioContext&&s.audioContext.close(),s.audioContext=null,d.clearRect(0,0,a.width,a.height),a.stream&&(a.stream.stop(),a.stream=null)},this.resetVideoStreams=function(e){!e||e instanceof Array||(e=[e]),p(e)},this.name="MultiStreamsMixer",this.toString=function(){return this.name},this.getMixedStream=function(){n=!1;var t=function(){var e;p(),"captureStream"in a?e=a.captureStream():"mozCaptureStream"in a?e=a.mozCaptureStream():s.disableLogs||console.error("Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features");var t=new l;return e.getTracks().filter((function(e){return"video"===e.kind})).forEach((function(e){t.addTrack(e)})),a.stream=t,t}(),o=function(){f.AudioContextConstructor||(f.AudioContextConstructor=new f.AudioContext);s.audioContext=f.AudioContextConstructor,s.audioSources=[],!0===s.useGainNode&&(s.gainNode=s.audioContext.createGain(),s.gainNode.connect(s.audioContext.destination),s.gainNode.gain.value=0);var t=0;if(e.forEach((function(e){if(e.getTracks().filter((function(e){return"audio"===e.kind})).length){t++;var o=s.audioContext.createMediaStreamSource(e);!0===s.useGainNode&&o.connect(s.gainNode),s.audioSources.push(o)}})),!t)return;return s.audioDestination=s.audioContext.createMediaStreamDestination(),s.audioSources.forEach((function(e){e.connect(s.audioDestination)})),s.audioDestination.stream}();return o&&o.getTracks().filter((function(e){return"audio"===e.kind})).forEach((function(e){t.addTrack(e)})),e.forEach((function(e){e.fullcanvas&&!0})),t}} +/** + * MultiStreamRecorder can record multiple videos in single container. + * @summary Multi-videos recorder. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef MultiStreamRecorder + * @class + * @example + * var options = { + * mimeType: 'video/webm' + * } + * var recorder = new MultiStreamRecorder(ArrayOfMediaStreams, options); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * + * // or + * var blob = recorder.blob; + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStreams} mediaStreams - Array of MediaStreams. + * @param {object} config - {disableLogs:true, frameInterval: 1, mimeType: "video/webm"} + */ +function F(e,t){e=e||[];var o,i,n=this;(t=t||{elementClass:"multi-streams-mixer",mimeType:"video/webm",video:{width:360,height:240}}).frameInterval||(t.frameInterval=10),t.video||(t.video={}),t.video.width||(t.video.width=360),t.video.height||(t.video.height=240),this.record=function(){var n;o=new I(e,t.elementClass||"multi-streams-mixer"),(n=[],e.forEach((function(e){k(e,"video").forEach((function(e){n.push(e)}))})),n).length&&(o.frameInterval=t.frameInterval||10,o.width=t.video.width||360,o.height=t.video.height||240,o.startDrawingFrames()),t.previewStream&&"function"==typeof t.previewStream&&t.previewStream(o.getMixedStream()),(i=new A(o.getMixedStream(),t)).record()},this.stop=function(e){i&&i.stop((function(t){n.blob=t,e(t),n.clearRecordedData()}))},this.pause=function(){i&&i.pause()},this.resume=function(){i&&i.resume()},this.clearRecordedData=function(){i&&(i.clearRecordedData(),i=null),o&&(o.releaseStreams(),o=null)},this.addStreams=function(n){if(!n)throw"First parameter is required.";n instanceof Array||(n=[n]),e.concat(n),i&&o&&(o.appendStreams(n),t.previewStream&&"function"==typeof t.previewStream&&t.previewStream(o.getMixedStream()))},this.resetVideoStreams=function(e){o&&(!e||e instanceof Array||(e=[e]),o.resetVideoStreams(e))},this.getMixer=function(){return o},this.name="MultiStreamRecorder",this.toString=function(){return this.name}} +/** + * WebAssemblyRecorder lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData from a CANVAS. With realtime mode you can also use webm-wasm for streaming webm videos. + * @summary Video recording feature in Chrome, Firefox and maybe Edge. + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef WebAssemblyRecorder + * @class + * @example + * var recorder = new WebAssemblyRecorder(mediaStream); + * recorder.record(); + * recorder.stop(function(blob) { + * video.src = URL.createObjectURL(blob); + * }); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. + * @param {object} config - {webAssemblyPath:'webm-wasm.wasm',workerPath: 'webm-worker.js', frameRate: 30, width: 1920, height: 1080, bitrate: 1024, realtime: true} + */ +function j(e,t){var o,i,n;function r(){return new ReadableStream({start:function(i){var n=document.createElement("canvas"),r=document.createElement("video"),a=!0;r.srcObject=e,r.muted=!0,r.height=t.height,r.width=t.width,r.volume=0,r.onplaying=function(){n.width=t.width,n.height=t.height;var e=n.getContext("2d"),d=1e3/t.frameRate,s=setInterval((function(){if(o&&(clearInterval(s),i.close()),a&&(a=!1,t.onVideoProcessStarted&&t.onVideoProcessStarted()),e.drawImage(r,0,0),"closed"!==i._controlledReadableStream.state)try{i.enqueue(e.getImageData(0,0,t.width,t.height))}catch(e){}}),d)},r.play()}})}"undefined"!=typeof ReadableStream&&"undefined"!=typeof WritableStream||console.error("Following polyfill is strongly recommended: https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js"),(t=t||{}).width=t.width||640,t.height=t.height||480,t.frameRate=t.frameRate||30,t.bitrate=t.bitrate||1200,t.realtime=t.realtime||!0,this.record=function(){a=[],n=!1,this.blob=null,function e(d,s){if(!t.workerPath&&!s)return o=!1,void fetch("https://unpkg.com/webm-wasm@latest/dist/webm-worker.js").then((function(t){t.arrayBuffer().then((function(t){e(d,t)}))}));if(!t.workerPath&&s instanceof ArrayBuffer){var c=new Blob([s],{type:"text/javascript"});t.workerPath=m.createObjectURL(c)}t.workerPath||console.error("workerPath parameter is missing."),(i=new Worker(t.workerPath)).postMessage(t.webAssemblyPath||"https://unpkg.com/webm-wasm@latest/dist/webm-wasm.wasm"),i.addEventListener("message",(function(e){"READY"===e.data?(i.postMessage({width:t.width,height:t.height,bitrate:t.bitrate||1200,timebaseDen:t.frameRate||30,realtime:t.realtime}),r().pipeTo(new WritableStream({write:function(e){o?console.error("Got image, but recorder is finished!"):i.postMessage(e.data.buffer,[e.data.buffer])}}))):e.data&&(n||a.push(e.data))}))}(e),"function"==typeof t.initCallback&&t.initCallback()},this.pause=function(){n=!0},this.resume=function(){n=!1};var a=[];this.stop=function(e){o=!0;var t=this;!function(e){i?(i.addEventListener("message",(function(t){null===t.data&&(i.terminate(),i=null,e&&e())})),i.postMessage(null)):e&&e()}((function(){t.blob=new Blob(a,{type:"video/webm"}),e(t.blob)}))},this.name="WebAssemblyRecorder",this.toString=function(){return this.name},this.clearRecordedData=function(){a=[],n=!1,this.blob=null},this.blob=null}void 0!==r&&(r.DiskStorage=O),void 0!==r&&(r.GifRecorder=E),void 0===r&&(e.exports=I,void 0===(n=function(){return I}.apply(t,[]))||(e.exports=n)),void 0!==r&&(r.MultiStreamRecorder=F),void 0!==r&&(r.RecordRTCPromisesHandler= +/** + * RecordRTCPromisesHandler adds promises support in {@link RecordRTC}. Try a {@link https://github.com/muaz-khan/RecordRTC/blob/master/simple-demos/RecordRTCPromisesHandler.html|demo here} + * @summary Promises for {@link RecordRTC} + * @license {@link https://github.com/muaz-khan/RecordRTC/blob/master/LICENSE|MIT} + * @author {@link https://MuazKhan.com|Muaz Khan} + * @typedef RecordRTCPromisesHandler + * @class + * @example + * var recorder = new RecordRTCPromisesHandler(mediaStream, options); + * recorder.startRecording() + * .then(successCB) + * .catch(errorCB); + * // Note: You can access all RecordRTC API using "recorder.recordRTC" e.g. + * recorder.recordRTC.onStateChanged = function(state) {}; + * recorder.recordRTC.setRecordingDuration(5000); + * @see {@link https://github.com/muaz-khan/RecordRTC|RecordRTC Source Code} + * @param {MediaStream} mediaStream - Single media-stream object, array of media-streams, html-canvas-element, etc. + * @param {object} config - {type:"video", recorderType: MediaStreamRecorder, disableLogs: true, numberOfAudioChannels: 1, bufferSize: 0, sampleRate: 0, video: HTMLVideoElement, etc.} + * @throws Will throw an error if "new" keyword is not used to initiate "RecordRTCPromisesHandler". Also throws error if first argument "MediaStream" is missing. + * @requires {@link RecordRTC} + */ +function(e,t){if(!this)throw'Use "new RecordRTCPromisesHandler()"';if(void 0===e)throw'First argument "MediaStream" is required.';var o=this;o.recordRTC=new r(e,t),this.startRecording=function(){return new Promise((function(e,t){try{o.recordRTC.startRecording(),e()}catch(e){t(e)}}))},this.stopRecording=function(){return new Promise((function(e,t){try{o.recordRTC.stopRecording((function(i){o.blob=o.recordRTC.getBlob(),o.blob&&o.blob.size?e(i):t("Empty blob.",o.blob)}))}catch(e){t(e)}}))},this.pauseRecording=function(){return new Promise((function(e,t){try{o.recordRTC.pauseRecording(),e()}catch(e){t(e)}}))},this.resumeRecording=function(){return new Promise((function(e,t){try{o.recordRTC.resumeRecording(),e()}catch(e){t(e)}}))},this.getDataURL=function(e){return new Promise((function(e,t){try{o.recordRTC.getDataURL((function(t){e(t)}))}catch(e){t(e)}}))},this.getBlob=function(){return new Promise((function(e,t){try{e(o.recordRTC.getBlob())}catch(e){t(e)}}))},this.getInternalRecorder=function(){return new Promise((function(e,t){try{e(o.recordRTC.getInternalRecorder())}catch(e){t(e)}}))},this.reset=function(){return new Promise((function(e,t){try{e(o.recordRTC.reset())}catch(e){t(e)}}))},this.destroy=function(){return new Promise((function(e,t){try{e(o.recordRTC.destroy())}catch(e){t(e)}}))},this.getState=function(){return new Promise((function(e,t){try{e(o.recordRTC.getState())}catch(e){t(e)}}))},this.blob=null,this.version="5.6.1"}),void 0!==r&&(r.WebAssemblyRecorder=j)}).call(this,o(1),o(2))},function(e,t){var o;o=function(){return this}();try{o=o||new Function("return this")()}catch(e){"object"==typeof window&&(o=window)}e.exports=o},function(e,t){var o,i,n=e.exports={};function r(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function d(e){if(o===setTimeout)return setTimeout(e,0);if((o===r||!o)&&setTimeout)return o=setTimeout,setTimeout(e,0);try{return o(e,0)}catch(t){try{return o.call(null,e,0)}catch(t){return o.call(this,e,0)}}}!function(){try{o="function"==typeof setTimeout?setTimeout:r}catch(e){o=r}try{i="function"==typeof clearTimeout?clearTimeout:a}catch(e){i=a}}();var s,c=[],u=!1,l=-1;function f(){u&&s&&(u=!1,s.length?c=s.concat(c):l=-1,c.length&&h())}function h(){if(!u){var e=d(f);u=!0;for(var t=c.length;t;){for(s=c,c=[];++l1)for(var o=1;o $(function() { + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + function startTimer() { $("#timer").show(); var timerData = { @@ -87,22 +89,11 @@ return false; } - navigator.getUserMedia = navigator.getUserMedia || - navigator.mozGetUserMedia || - navigator.webkitGetUserMedia; - - if (navigator.getUserMedia) { - navigator.getUserMedia(mediaConstraints, successCallback, errorCallback); - } else if (navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia(mediaConstraints) - .then(successCallback).error(errorCallback); - } - function successCallback(stream) { stopTimer(); startTimer(); recordRTC = RecordRTC(stream, { - numberOfAudioChannels: 1, + recorderType: isSafari ? RecordRTC.StereoAudioRecorder : RecordRTC.MediaStreamRecorder, type: 'audio' }); recordRTC.startRecording(); @@ -113,8 +104,18 @@ function errorCallback(error) { stopTimer(); - alert(error.message); + alert(error); } + + if(!!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia)) { + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; + navigator.getUserMedia(mediaConstraints, successCallback, errorCallback); + return; + } + + navigator.mediaDevices.getUserMedia(mediaConstraints) + .then(successCallback) + .catch(errorCallback); }); btnStop.on('click', function () { diff --git a/plugin/whispeakauth/assets/js/RecordAudio.js b/plugin/whispeakauth/assets/js/RecordAudio.js index e5724a9945..acaabf9998 100644 --- a/plugin/whispeakauth/assets/js/RecordAudio.js +++ b/plugin/whispeakauth/assets/js/RecordAudio.js @@ -2,7 +2,8 @@ window.RecordAudio = (function () { var timerInterval = 0, - $txtTimer = null; + $txtTimer = null, + isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); function startTimer() { stopTimer(); @@ -47,7 +48,6 @@ window.RecordAudio = (function () { } } - function useRecordRTC(rtcInfo) { $(rtcInfo.blockId).show(); @@ -123,8 +123,7 @@ window.RecordAudio = (function () { localStream = stream; recordRTC = RecordRTC(stream, { - recorderType: StereoAudioRecorder, - numberOfAudioChannels: 1, + recorderType: isSafari ? RecordRTC.StereoAudioRecorder : RecordRTC.MediaStreamRecorder, type: 'audio' }); recordRTC.startRecording(); @@ -139,22 +138,18 @@ window.RecordAudio = (function () { } function errorCallback(error) { - alert(error.message); + alert(error); } - if (navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia(mediaConstraints) - .then(successCallback) - .catch(errorCallback); - + if(!!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia)) { + navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; + navigator.getUserMedia(mediaConstraints, successCallback, errorCallback); return; } - navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia; - - if (navigator.getUserMedia) { - navigator.getUserMedia(mediaConstraints, successCallback, errorCallback); - } + navigator.mediaDevices.getUserMedia(mediaConstraints) + .then(successCallback) + .catch(errorCallback); }); btnStop.on('click', function () {