diff --git a/README.md b/README.md index d1a224ef..caebd1ea 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ var options = { frameRate: 200, quality: 10 }; -var recordRTC = RecordRTC(mediaStream, options); +var recordRTC = RecordRTC(mediaStream || canvas || context, options); recordRTC.startRecording(); recordRTC.stopRecording(function(gifURL) { mediaElement.src = gifURL; @@ -264,12 +264,10 @@ It is a function that can be used to initiate recorder however skip getting reco ```javascript var audioRecorder = RecordRTC(mediaStream, { - type: 'audio', recorderType: StereoAudioRecorder }); var videoRecorder = RecordRTC(mediaStream, { - type: 'video', recorderType: WhammyRecorder }); @@ -308,7 +306,6 @@ navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) { var recordRTC = RecordRTC(stream, { - type: 'video', recorderType: WhammyRecorder }); @@ -334,11 +331,12 @@ recorder.clearRecordedData(); ## `recorderType` +If you're using `recorderType` then you don't need to use `type`. Second one will be redundant i.e. skipped. + You can force any Recorder by passing this object over RecordRTC constructor: ```javascript var audioRecorder = RecordRTC(mediaStream, { - type: 'audio', recorderType: StereoAudioRecorder }) ``` @@ -349,6 +347,35 @@ This feature brings remote audio recording support in Firefox, and local audio r You can even force `WhammyRecorder` on Firefox however webp format isn't yet supported in standard Firefox builds. It simply means that, you're skipping MediaRecorder API in Firefox. +## `type` + +If you are NOT using `recorderType` parameter then `type` parameter can be used to ask RecordRTC choose best recorder-type for recording. + +```javascript +// if it is Firefox, then RecordRTC will be using MediaStreamRecorder.js +// if it is Chrome or Opera, then RecordRTC will be using WhammyRecorder.js +var recordVideo = RecordRTC(mediaStream, { + type: 'video' +}); + +// if it is Firefox, then RecordRTC will be using MediaStreamRecorder.js +// if it is Chrome or Opera or Edge, then RecordRTC will be using StereoAudioRecorder.js +var recordVideo = RecordRTC(mediaStream, { + type: 'audio' +}); +``` + +## `frameInterval` + +Set minimum interval (in milliseconds) between each time we push a frame to Whammy recorder. + +```javascript +var whammyRecorder = RecordRTC(videoStream, { + recorderType: WhammyRecorder, + frameInterval: 1 // setTimeout interval +}); +``` + ## `disableLogs` You can disable all the RecordRTC logs by passing this Boolean: @@ -365,7 +392,6 @@ You can force [StereoAudioRecorder](http://RecordRTC.org/StereoAudioRecorder.htm ```javascript var audioRecorder = RecordRTC(audioStream, { - type: 'audio', recorderType: StereoAudioRecorder, numberOfAudioChannels: 1 // or leftChannel:true }); diff --git a/RecordRTC.js b/RecordRTC.js index 08f78017..d58f5e77 100644 --- a/RecordRTC.js +++ b/RecordRTC.js @@ -9,6 +9,8 @@ // updates? /* +-. GifRecorder.js can now record HTMLCanvasElement|CanvasRenderingContext2D as well. +-. added: frameInterval:20 for WhammyRecorder.js -. chrome issue audio plus 720p-video recording can be fixed by setting bufferSize:16384 -. fixed Firefox save-as dialog i.e. recordRTC.save('filen-name') -. "indexedDB" bug fixed for Firefox. @@ -90,6 +92,26 @@ function RecordRTC(mediaStream, config) { throw 'MediaStream is mandatory.'; } + if (config.recorderType && !config.type) { + if (config.recorderType === WhammyRecorder || config.recorderType === CanvasRecorder) { + config.type = 'video'; + } else if (config.recorderType === GifRecorder) { + config.type = 'gif'; + } else if (config.recorderType === StereoAudioRecorder) { + config.type = 'audio'; + } else if (config.recorderType === MediaStreamRecorder) { + if (mediaStream.getAudioTracks().length && mediaStream.getVideoTracks().length) { + config.type = 'video'; + } else if (mediaStream.getAudioTracks().length && !mediaStream.getVideoTracks().length) { + config.type = 'audio'; + } else if (!mediaStream.getAudioTracks().length && mediaStream.getVideoTracks().length) { + config.type = 'audio'; + } else { + // config.type = 'UnKnown'; + } + } + } + // consider default type=audio if (!config.type) { config.type = 'audio'; @@ -131,18 +153,18 @@ function RecordRTC(mediaStream, config) { // StereoAudioRecorder can work with all three: Edge, Firefox and Chrome // todo: detect if it is Edge, then auto use: StereoAudioRecorder - if (typeof StereoAudioRecorder !== 'undefined' && isChrome) { + if (typeof StereoAudioRecorder !== 'undefined' && (isChrome || isEdge || isOpera)) { // Media Stream Recording API has not been implemented in chrome yet; // That's why using WebAudio API to record stereo audio in WAV format Recorder = StereoAudioRecorder; } - if (typeof MediaStreamRecorder !== 'undefined' && !isChrome) { + if (typeof MediaStreamRecorder !== 'undefined' && typeof MediaRecorder !== 'undefined' && 'requestData' in MediaRecorder.prototype) { Recorder = MediaStreamRecorder; } // video recorder (in WebM format) - if (config.type === 'video' && isChrome) { + if (config.type === 'video' && (isChrome || isOpera)) { if (typeof WhammyRecorder !== 'undefined') { Recorder = WhammyRecorder; } else { @@ -1082,7 +1104,9 @@ if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') { var URL = webkitURL; } -var isChrome = true; +var isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveBlob || !!navigator.msSaveOrOpenBlob); +var isOpera = !!window.opera || navigator.userAgent.indexOf('OPR/') !== -1; +var isChrome = !isOpera && !isEdge && !!navigator.webkitGetUserMedia; if (typeof navigator !== 'undefined') { if (typeof navigator.webkitGetUserMedia !== 'undefined') { @@ -1092,8 +1116,6 @@ if (typeof navigator !== 'undefined') { if (typeof navigator.mozGetUserMedia !== 'undefined') { navigator.getUserMedia = navigator.mozGetUserMedia; } - - isChrome = typeof navigator.webkitGetUserMedia !== 'undefined'; } else { /*global navigator:true */ var navigator = { @@ -1945,7 +1967,7 @@ function StereoAudioRecorder(mediaStream, config) { * @typedef CanvasRecorder * @class * @example - * var recorder = new CanvasRecorder(htmlElement); + * var recorder = new CanvasRecorder(htmlElement, { disableLogs: true }); * recorder.record(); * recorder.stop(function(blob) { * video.src = URL.createObjectURL(blob); @@ -2091,7 +2113,7 @@ function CanvasRecorder(htmlElement, config) { }); if (isRecording) { - requestAnimationFrame(drawCanvasFrame); + setTimeout(drawCanvasFrame, 0); } } }); @@ -2123,6 +2145,14 @@ function WhammyRecorder(mediaStream, config) { config = config || {}; + if (!config.frameInterval) { + config.frameInterval = 10; + } + + if (!config.disableLogs) { + console.log('Using frames-interval:', config.frameInterval); + } + /** * This method records video. * @method @@ -3042,17 +3072,17 @@ var DiskStorage = { // GifRecorder.js /** - * GifRecorder is standalone calss used by {@link RecordRTC} to record video as animated gif image. + * GifRecorder is standalone calss used by {@link RecordRTC} to record video or canvas into animated gif. * @typedef GifRecorder * @class * @example - * var recorder = new GifRecorder(mediaStream); + * var recorder = new GifRecorder(mediaStream || canvas || context, { width: 1280, height: 720, frameRate: 200, quality: 10 }); * recorder.record(); * recorder.stop(function(blob) { * img.src = URL.createObjectURL(blob); * }); - * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. - * @param {object} config - {disableLogs:true, initcallback: function, width: 320, height: 240, frameRate: 200, quality: 10} + * @param {MediaStream} mediaStream - MediaStream object or HTMLCanvasElement or CanvasRenderingContext2D. + * @param {object} config - {disableLogs:true, initCallback: function, width: 320, height: 240, frameRate: 200, quality: 10} */ function GifRecorder(mediaStream, config) { @@ -3062,6 +3092,8 @@ function GifRecorder(mediaStream, config) { config = config || {}; + var isHTMLObject = mediaStream instanceof CanvasRenderingContext2D || mediaStream instanceof HTMLCanvasElement; + /** * This method records MediaStream. * @method @@ -3070,33 +3102,35 @@ function GifRecorder(mediaStream, config) { * recorder.record(); */ this.record = function() { - if (!config.width) { - config.width = video.offsetWidth || 320; - } + if (!isHTMLObject) { + if (!config.width) { + config.width = video.offsetWidth || 320; + } - if (!this.height) { - config.height = video.offsetHeight || 240; - } + if (!this.height) { + config.height = video.offsetHeight || 240; + } - if (!config.video) { - config.video = { - width: config.width, - height: config.height - }; - } + if (!config.video) { + config.video = { + width: config.width, + height: config.height + }; + } - if (!config.canvas) { - config.canvas = { - width: config.width, - height: config.height - }; - } + if (!config.canvas) { + config.canvas = { + width: config.width, + height: config.height + }; + } - canvas.width = config.canvas.width; - canvas.height = config.canvas.height; + canvas.width = config.canvas.width; + canvas.height = config.canvas.height; - video.width = config.video.width; - video.height = config.video.height; + video.width = config.video.width; + video.height = config.video.height; + } // external library to record as GIF images gifEncoder = new GIFEncoder(); @@ -3147,7 +3181,7 @@ function GifRecorder(mediaStream, config) { return; } - if (video.paused) { + if (!isHTMLObject && video.paused) { // via: https://github.com/muaz-khan/WebRTC-Experiment/pull/316 // Tweak for Android Chrome video.play(); @@ -3259,17 +3293,27 @@ function GifRecorder(mediaStream, config) { var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); - var video = document.createElement('video'); - video.muted = true; - video.autoplay = true; - - if (typeof video.srcObject !== 'undefined') { - video.srcObject = mediaStream; - } else { - video.src = URL.createObjectURL(mediaStream); + if (isHTMLObject) { + if (mediaStream instanceof CanvasRenderingContext2D) { + context = mediaStream; + } else if (mediaStream instanceof HTMLCanvasElement) { + context = mediaStream.getContext('2d'); + } } - video.play(); + if (!isHTMLObject) { + var video = document.createElement('video'); + video.muted = true; + video.autoplay = true; + + if (typeof video.srcObject !== 'undefined') { + video.srcObject = mediaStream; + } else { + video.src = URL.createObjectURL(mediaStream); + } + + video.play(); + } var lastAnimationFrame = null; var startTime, endTime, lastFrameTime; diff --git a/RecordRTC.min.js b/RecordRTC.min.js index 48760d8c..a982a7b2 100644 --- a/RecordRTC.min.js +++ b/RecordRTC.min.js @@ -1,2 +1,2 @@ -"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){config.disableLogs||console.debug("initializing "+config.type+" stream recorder.");var Recorder;if("undefined"!=typeof StereoAudioRecorder&&isChrome&&(Recorder=StereoAudioRecorder),"undefined"==typeof MediaStreamRecorder||isChrome||(Recorder=MediaStreamRecorder),"video"===config.type&&isChrome){if("undefined"==typeof WhammyRecorder)throw"WhammyRecorder.js seems NOT linked.";Recorder=WhammyRecorder}if("gif"===config.type){if("undefined"==typeof GifRecorder)throw"GifRecorder.js seems NOT linked.";Recorder=GifRecorder}if("canvas"===config.type){if("undefined"==typeof CanvasRecorder)throw"CanvasRecorder.js seems NOT linked.";Recorder=CanvasRecorder}config.recorderType&&(Recorder=config.recorderType),initCallback&&(config.initCallback=function(){initCallback(),initCallback=config.initCallback=null}),mediaRecorder=new Recorder(mediaStream,config),mediaRecorder.record()}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?void(mediaRecorder.pause?mediaRecorder.pause():config.disableLogs||console.warn('This recording library is having no "pause" method.')):console.warn(WARNING)}function resumeRecording(){return mediaRecorder?void(mediaRecorder.resume?mediaRecorder.resume():config.disableLogs||console.warn('This recording library is having no "resume" method.')):console.warn(WARNING)}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){var webWorker=processInWebWorker(function(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))});webWorker.onmessage=function(event){callback(event.data)},webWorker.postMessage(blob)}else{var reader=new FileReader;reader.readAsDataURL(blob),reader.onload=function(event){callback(event.target.result)}}}function handleRecordingDuration(){setTimeout(function(){stopRecording(self.onRecordingStopped)},self.recordingDuration)}if(config=config||{},!mediaStream)throw"MediaStream is mandatory.";config.type||(config.type="audio");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?void mediaRecorder.clearRecordedData():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 MRecordRTC(mediaStream){this.addStream=function(_mediaStream){_mediaStream&&(mediaStream=_mediaStream)},this.mediaType={audio:!0,video:!0},this.startRecording=function(){!isChrome&&mediaStream&&mediaStream.getAudioTracks&&mediaStream.getAudioTracks().length&&mediaStream.getVideoTracks().length&&(this.mediaType.audio=!1),this.mediaType.audio&&(this.audioRecorder=new RecordRTC(mediaStream,{type:"audio",bufferSize:this.bufferSize,sampleRate:this.sampleRate}),this.audioRecorder.startRecording()),this.mediaType.video&&(this.videoRecorder=new RecordRTC(mediaStream,{type:"video",video:this.video,canvas:this.canvas}),this.videoRecorder.startRecording()),this.mediaType.gif&&(this.gifRecorder=new RecordRTC(mediaStream,{type:"gif",frameRate:this.frameRate||200,quality:this.quality||10}),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.";file.type||(file.type="video/webm");var fileExtension=file.type.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 MediaStreamRecorder(mediaStream,config){var self=this;if(config=config||{},config.mimeType&&"video/webm"!==config.mimeType&&mediaStream.getVideoTracks&&mediaStream.getVideoTracks().length){var context=new AudioContext,mediaStreamSource=context.createMediaStreamSource(mediaStream),destination=context.createMediaStreamDestination();mediaStreamSource.connect(destination),mediaStream=destination.stream}var dataAvailable=!1;this.record=function(){mediaRecorder=new MediaRecorder(mediaStream),mediaRecorder.ondataavailable=function(e){if(!self.dontFireOnDataAvailableEvent&&!dataAvailable){if(!e.data.size)return void(config.disableLogs||console.warn("Recording of",e.data.type,"failed."));dataAvailable=!0,self.blob=new Blob([e.data],{type:e.data.type||config.mimeType||"audio/ogg"}),self.callback&&self.callback()}},mediaRecorder.onerror=function(error){config.disableLogs||console.warn(error),mediaRecorder.stop(),self.record(0)},mediaRecorder.start(0),config.onAudioProcessStarted&&config.onAudioProcessStarted(),config.initCallback&&config.initCallback()},this.stop=function(callback){mediaRecorder&&(this.callback=callback,"recording"===mediaRecorder.state&&mediaRecorder.stop())},this.pause=function(){mediaRecorder&&"recording"===mediaRecorder.state&&(mediaRecorder.pause(),config.disableLogs||console.debug("Paused recording."))},this.resume=function(){return mediaRecorder?this.dontFireOnDataAvailableEvent?(this.dontFireOnDataAvailableEvent=!1,dataAvailable=!1,void this.record()):void("paused"===mediaRecorder.state&&(mediaRecorder.resume(),config.disableLogs||console.debug("Resumed recording."))):void 0},this.clearRecordedData=function(){mediaRecorder&&(this.pause(),this.dontFireOnDataAvailableEvent=!0,this.stop(),config.disableLogs||console.debug("Cleared old recorded data."))};var mediaRecorder}function StereoAudioRecorder(mediaStream,config){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,4*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("active"in mediaStream?mediaStream.active||(jsAudioNode.onaudioprocess=function(){},recording=!1):"ended"in mediaStream&&mediaStream.ended&&(jsAudioNode.onaudioprocess=function(){},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(){leftchannel.length=rightchannel.length=0,recordingLength=0,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),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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPaused=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){this.pause(),leftchannel.length=rightchannel.length=0,recordingLength=0,config.disableLogs||console.debug("Cleared old recorded data.")};var isAudioProcessStarted=!1;jsAudioNode.onaudioprocess=onAudioProcessDataAvailable,jsAudioNode.connect(context.destination)}function CanvasRecorder(htmlElement,config){function drawCanvasFrame(){return isPausedRecording?(lastTime=(new Date).getTime(),setTimeout(drawCanvasFrame,100)):void html2canvas(htmlElement,{onrendered:function(canvas){var duration=(new Date).getTime()-lastTime;return duration?(lastTime=(new Date).getTime(),whammy.frames.push({duration:duration,image:canvas.toDataURL("image/webp")}),void(isRecording&&requestAnimationFrame(drawCanvasFrame))):drawCanvasFrame()}})}if("undefined"==typeof html2canvas)throw"Please link: //cdn.webrtc-experiment.com/screenshot.js";config=config||{};var isRecording;this.record=function(){isRecording=!0,whammy.frames=[],drawCanvasFrame(),config.initCallback&&config.initCallback()},this.stop=function(callback){isRecording=!1;var that=this;whammy.compile(function(blob){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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){this.pause(),whammy.frames=[],config.disableLogs||console.debug("Cleared old recorded data.")};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 dropBlackFrames(_frames,_framesToCheck,_pixTolerance,_frameTolerance){var localCanvas=document.createElement("canvas");localCanvas.width=canvas.width,localCanvas.height=canvas.height;for(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,f=0;endCheckFrame>f;f++){var matchPixCount,endPixCheck,maxPixCount;if(!doNotCheckNext){var image=new Image;image.src=_frames[f].image,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++}}!doNotCheckNext&&maxPixCount*frameTolerance>=maxPixCount-matchPixCount||(checkUntilNotBlack&&(doNotCheckNext=!0),resultFrames.push(_frames[f]))}return resultFrames=resultFrames.concat(_frames.slice(endCheckFrame)),resultFrames.length<=0&&resultFrames.push(_frames[_frames.length-1]),resultFrames}config=config||{},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(){whammy.frames=dropBlackFrames(whammy.frames,-1),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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},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||{},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||(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)))}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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){gifEncoder&&(this.pause(),gifEncoder.stream().bin=[],config.disableLogs||console.debug("Cleared old recorded data."))};var canvas=document.createElement("canvas"),context=canvas.getContext("2d"),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 requestAnimationFrame){if("undefined"!=typeof webkitRequestAnimationFrame)var requestAnimationFrame=webkitRequestAnimationFrame;if("undefined"!=typeof mozRequestAnimationFrame)var requestAnimationFrame=mozRequestAnimationFrame}if("undefined"==typeof cancelAnimationFrame){if("undefined"!=typeof webkitCancelAnimationFrame)var cancelAnimationFrame=webkitCancelAnimationFrame;if("undefined"!=typeof mozCancelAnimationFrame)var cancelAnimationFrame=mozCancelAnimationFrame}if("undefined"==typeof AudioContext){if("undefined"!=typeof webkitAudioContext)var AudioContext=webkitAudioContext;if("undefined"!=typeof mozAudioContext)var AudioContext=mozAudioContext}if("undefined"==typeof URL&&"undefined"!=typeof webkitURL)var URL=webkitURL;var isChrome=!0;if("undefined"!=typeof navigator)"undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia),isChrome="undefined"!=typeof navigator.webkitGetUserMedia;else var navigator={getUserMedia:{}};if("undefined"!=typeof webkitMediaStream)var MediaStream=webkitMediaStream;"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);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",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?void(mediaRecorder.pause?mediaRecorder.pause():config.disableLogs||console.warn('This recording library is having no "pause" method.')):console.warn(WARNING)}function resumeRecording(){return mediaRecorder?void(mediaRecorder.resume?mediaRecorder.resume():config.disableLogs||console.warn('This recording library is having no "resume" method.')):console.warn(WARNING)}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){var webWorker=processInWebWorker(function(_blob){postMessage((new FileReaderSync).readAsDataURL(_blob))});webWorker.onmessage=function(event){callback(event.data)},webWorker.postMessage(blob)}else{var reader=new FileReader;reader.readAsDataURL(blob),reader.onload=function(event){callback(event.target.result)}}}function handleRecordingDuration(){setTimeout(function(){stopRecording(self.onRecordingStopped)},self.recordingDuration)}if(config=config||{},!mediaStream)throw"MediaStream is mandatory.";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"))),config.type||(config.type="audio");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?void mediaRecorder.clearRecordedData():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 MRecordRTC(mediaStream){this.addStream=function(_mediaStream){_mediaStream&&(mediaStream=_mediaStream)},this.mediaType={audio:!0,video:!0},this.startRecording=function(){!isChrome&&mediaStream&&mediaStream.getAudioTracks&&mediaStream.getAudioTracks().length&&mediaStream.getVideoTracks().length&&(this.mediaType.audio=!1),this.mediaType.audio&&(this.audioRecorder=new RecordRTC(mediaStream,{type:"audio",bufferSize:this.bufferSize,sampleRate:this.sampleRate}),this.audioRecorder.startRecording()),this.mediaType.video&&(this.videoRecorder=new RecordRTC(mediaStream,{type:"video",video:this.video,canvas:this.canvas}),this.videoRecorder.startRecording()),this.mediaType.gif&&(this.gifRecorder=new RecordRTC(mediaStream,{type:"gif",frameRate:this.frameRate||200,quality:this.quality||10}),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.";file.type||(file.type="video/webm");var fileExtension=file.type.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 MediaStreamRecorder(mediaStream,config){var self=this;if(config=config||{},config.mimeType&&"video/webm"!==config.mimeType&&mediaStream.getVideoTracks&&mediaStream.getVideoTracks().length){var context=new AudioContext,mediaStreamSource=context.createMediaStreamSource(mediaStream),destination=context.createMediaStreamDestination();mediaStreamSource.connect(destination),mediaStream=destination.stream}var dataAvailable=!1;this.record=function(){mediaRecorder=new MediaRecorder(mediaStream),mediaRecorder.ondataavailable=function(e){if(!self.dontFireOnDataAvailableEvent&&!dataAvailable){if(!e.data.size)return void(config.disableLogs||console.warn("Recording of",e.data.type,"failed."));dataAvailable=!0,self.blob=new Blob([e.data],{type:e.data.type||config.mimeType||"audio/ogg"}),self.callback&&self.callback()}},mediaRecorder.onerror=function(error){config.disableLogs||console.warn(error),mediaRecorder.stop(),self.record(0)},mediaRecorder.start(0),config.onAudioProcessStarted&&config.onAudioProcessStarted(),config.initCallback&&config.initCallback()},this.stop=function(callback){mediaRecorder&&(this.callback=callback,"recording"===mediaRecorder.state&&mediaRecorder.stop())},this.pause=function(){mediaRecorder&&"recording"===mediaRecorder.state&&(mediaRecorder.pause(),config.disableLogs||console.debug("Paused recording."))},this.resume=function(){return mediaRecorder?this.dontFireOnDataAvailableEvent?(this.dontFireOnDataAvailableEvent=!1,dataAvailable=!1,void this.record()):void("paused"===mediaRecorder.state&&(mediaRecorder.resume(),config.disableLogs||console.debug("Resumed recording."))):void 0},this.clearRecordedData=function(){mediaRecorder&&(this.pause(),this.dontFireOnDataAvailableEvent=!0,this.stop(),config.disableLogs||console.debug("Cleared old recorded data."))};var mediaRecorder}function StereoAudioRecorder(mediaStream,config){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,4*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,32767*interleaved[i]*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("active"in mediaStream?mediaStream.active||(jsAudioNode.onaudioprocess=function(){},recording=!1):"ended"in mediaStream&&mediaStream.ended&&(jsAudioNode.onaudioprocess=function(){},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(){leftchannel.length=rightchannel.length=0,recordingLength=0,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),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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPaused=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){this.pause(),leftchannel.length=rightchannel.length=0,recordingLength=0,config.disableLogs||console.debug("Cleared old recorded data.")};var isAudioProcessStarted=!1;jsAudioNode.onaudioprocess=onAudioProcessDataAvailable,jsAudioNode.connect(context.destination)}function CanvasRecorder(htmlElement,config){function drawCanvasFrame(){return isPausedRecording?(lastTime=(new Date).getTime(),setTimeout(drawCanvasFrame,100)):void html2canvas(htmlElement,{onrendered:function(canvas){var duration=(new Date).getTime()-lastTime;return duration?(lastTime=(new Date).getTime(),whammy.frames.push({duration:duration,image:canvas.toDataURL("image/webp")}),void(isRecording&&setTimeout(drawCanvasFrame,0))):drawCanvasFrame()}})}if("undefined"==typeof html2canvas)throw"Please link: //cdn.webrtc-experiment.com/screenshot.js";config=config||{};var isRecording;this.record=function(){isRecording=!0,whammy.frames=[],drawCanvasFrame(),config.initCallback&&config.initCallback()},this.stop=function(callback){isRecording=!1;var that=this;whammy.compile(function(blob){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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){this.pause(),whammy.frames=[],config.disableLogs||console.debug("Cleared old recorded data.")};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 dropBlackFrames(_frames,_framesToCheck,_pixTolerance,_frameTolerance){var localCanvas=document.createElement("canvas");localCanvas.width=canvas.width,localCanvas.height=canvas.height;for(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,f=0;endCheckFrame>f;f++){var matchPixCount,endPixCheck,maxPixCount;if(!doNotCheckNext){var image=new Image;image.src=_frames[f].image,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++}}!doNotCheckNext&&maxPixCount*frameTolerance>=maxPixCount-matchPixCount||(checkUntilNotBlack&&(doNotCheckNext=!0),resultFrames.push(_frames[f]))}return resultFrames=resultFrames.concat(_frames.slice(endCheckFrame)),resultFrames.length<=0&&resultFrames.push(_frames[_frames.length-1]),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(){whammy.frames=dropBlackFrames(whammy.frames,-1),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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},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,config.disableLogs||console.debug("Paused recording.")},this.resume=function(){isPausedRecording=!1,config.disableLogs||console.debug("Resumed recording.")},this.clearRecordedData=function(){gifEncoder&&(this.pause(),gifEncoder.stream().bin=[],config.disableLogs||console.debug("Cleared old recorded data."))};var canvas=document.createElement("canvas"),context=canvas.getContext("2d");if(isHTMLObject&&(mediaStream instanceof CanvasRenderingContext2D?context=mediaStream:mediaStream instanceof HTMLCanvasElement&&(context=mediaStream.getContext("2d"))),!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 requestAnimationFrame){if("undefined"!=typeof webkitRequestAnimationFrame)var requestAnimationFrame=webkitRequestAnimationFrame;if("undefined"!=typeof mozRequestAnimationFrame)var requestAnimationFrame=mozRequestAnimationFrame}if("undefined"==typeof cancelAnimationFrame){if("undefined"!=typeof webkitCancelAnimationFrame)var cancelAnimationFrame=webkitCancelAnimationFrame;if("undefined"!=typeof mozCancelAnimationFrame)var cancelAnimationFrame=mozCancelAnimationFrame}if("undefined"==typeof AudioContext){if("undefined"!=typeof webkitAudioContext)var AudioContext=webkitAudioContext;if("undefined"!=typeof mozAudioContext)var AudioContext=mozAudioContext}if("undefined"==typeof URL&&"undefined"!=typeof webkitURL)var URL=webkitURL;var isEdge=!(-1===navigator.userAgent.indexOf("Edge")||!navigator.msSaveBlob&&!navigator.msSaveOrOpenBlob),isOpera=!!window.opera||-1!==navigator.userAgent.indexOf("OPR/"),isChrome=!isOpera&&!isEdge&&!!navigator.webkitGetUserMedia;if("undefined"!=typeof navigator)"undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia);else var navigator={getUserMedia:{}};if("undefined"!=typeof webkitMediaStream)var MediaStream=webkitMediaStream;"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);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 if(error.name === 'PermissionDeniedError' && !!navigator.mozGetUserMedia) { InstallTrigger.install({ 'Foo': { + // https://addons.mozilla.org/firefox/downloads/latest/655146/addon-655146-latest.xpi?src=dp-btn-primary URL: 'https://www.webrtc-experiment.com/store/firefox-extension/enable-screen-capturing.xpi', toString: function () { return this.URL; @@ -266,19 +267,32 @@

canvas: { width: params.canvas_width || recordingPlayer.clientWidth, height: params.canvas_height || recordingPlayer.clientHeight - } + }, + frameInterval: params.frameInterval !== 'undefined' ? parseInt(params.frameInterval) : 20 // minimum time between pushing frames to Whammy (in milliseconds) }); button.recordingEndedCallback = function(url) { + recordingPlayer.src = null; + recordingPlayer.srcObject = null; + if(mediaContainerFormat.value === 'Gif') { - recordingPlayer.src = null; recordingPlayer.pause(); recordingPlayer.poster = url; + + recordingPlayer.onended = function() { + recordingPlayer.pause(); + recordingPlayer.poster = URL.createObjectURL(button.recordRTC.blob); + }; return; } recordingPlayer.src = url; recordingPlayer.play(); + + recordingPlayer.onended = function() { + recordingPlayer.pause(); + recordingPlayer.src = URL.createObjectURL(button.recordRTC.blob); + }; }; button.recordRTC.startRecording(); @@ -302,11 +316,15 @@

var audio = new Audio(); audio.src = url; audio.controls = true; - audio.autoplay = true; recordingPlayer.parentNode.appendChild(document.createElement('hr')); recordingPlayer.parentNode.appendChild(audio); if(audio.paused) audio.play(); + + audio.onended = function() { + audio.pause(); + audio.src = URL.createObjectURL(button.recordRTC.blob); + }; }; button.recordRTC.startRecording(); @@ -318,7 +336,7 @@

button.mediaCapturedCallback = function() { - if(webrtcDetectedBrowser === 'chrome') { + if(webrtcDetectedBrowser !== 'firefox') { // opera or chrome etc. button.recordRTC = []; if(!params.bufferSize) { @@ -341,7 +359,8 @@

canvas: { width: params.canvas_width || recordingPlayer.clientWidth, height: params.canvas_height || recordingPlayer.clientHeight - } + }, + frameInterval: params.frameInterval !== 'undefined' ? parseInt(params.frameInterval) : 20 // minimum time between pushing frames to Whammy (in milliseconds) }); // to sync audio/video playbacks in browser! @@ -381,8 +400,15 @@

}); button.recordingEndedCallback = function(url) { + recordingPlayer.srcObject = null; + recordingPlayer.muted = false; recordingPlayer.src = url; recordingPlayer.play(); + + recordingPlayer.onended = function() { + recordingPlayer.pause(); + recordingPlayer.src = URL.createObjectURL(button.recordRTC.blob); + }; }; button.recordRTC.startRecording(); @@ -403,10 +429,16 @@

}); button.recordingEndedCallback = function(url) { + recordingPlayer.src = null; + recordingPlayer.srcObject = null; + if(mediaContainerFormat.value === 'Gif') { - recordingPlayer.src = null; recordingPlayer.pause(); recordingPlayer.poster = url; + recordingPlayer.onended = function() { + recordingPlayer.pause(); + recordingPlayer.poster = URL.createObjectURL(button.recordRTC.blob); + }; return; } @@ -430,8 +462,15 @@

}); button.recordingEndedCallback = function(url) { + recordingPlayer.srcObject = null; + recordingPlayer.muted = false; recordingPlayer.src = url; recordingPlayer.play(); + + recordingPlayer.onended = function() { + recordingPlayer.pause(); + recordingPlayer.src = URL.createObjectURL(button.recordRTC.blob); + }; }; button.recordRTC.startRecording(); @@ -640,6 +679,7 @@

// VIDEO ?canvas_width=1280&canvas_height=720 +?frameInterval=10