UNPKG

recordrtc

Version:

RecordRTC is a server-less (entire client-side) JavaScript library can be used to record WebRTC audio/video media streams. It supports cross-browser audio/video recording.

402 lines (358 loc) 13.2 kB
// _____________ // MRecordRTC.js /** * MRecordRTC runs top over {@link RecordRTC} to bring multiple recordings in single place, by providing simple API. * @summary MRecordRTC stands for "Multiple-RecordRTC". * @license {@link https://github.com/muaz-khan/RecordRTC#license|MIT} * @author {@link http://www.MuazKhan.com|Muaz Khan} * @typedef MRecordRTC * @class * @example * var recorder = new MRecordRTC(); * recorder.addStream(MediaStream); * recorder.mediaType = { * audio: true, // or StereoAudioRecorder or MediaStreamRecorder * video: true, // or WhammyRecorder or MediaStreamRecorder * gif: true // or GifRecorder * }; * // mimeType is optional and should be set only in advance cases. * recorder.mimeType = { * audio: 'audio/wav', * video: 'video/webm', * gif: 'image/gif' * }; * recorder.startRecording(); * @see For further information: * @see {@link https://github.com/muaz-khan/RecordRTC/tree/master/MRecordRTC|MRecordRTC Source Code} * @param {MediaStream} mediaStream - MediaStream object fetched using getUserMedia API or generated using captureStreamUntilEnded or WebAudio API. */ function MRecordRTC(mediaStream) { /** * This method attaches MediaStream object to {@link MRecordRTC}. * @param {MediaStream} mediaStream - A MediaStream object, either fetched using getUserMedia API, or generated using captureStreamUntilEnded or WebAudio API. * @method * @memberof MRecordRTC * @example * recorder.addStream(MediaStream); */ this.addStream = function(_mediaStream) { if (_mediaStream) { mediaStream = _mediaStream; } }; /** * This property can be used to set recording type e.g. audio, or video, or gif, or canvas. * @property {object} mediaType - {audio: true, video: true, gif: true} * @memberof MRecordRTC * @example * var recorder = new MRecordRTC(); * recorder.mediaType = { * audio: true, // TRUE or StereoAudioRecorder or MediaStreamRecorder * video: true, // TRUE or WhammyRecorder or MediaStreamRecorder * gif : true // TRUE or GifRecorder * }; */ this.mediaType = { audio: true, video: true }; /** * This method starts recording. * @method * @memberof MRecordRTC * @example * recorder.startRecording(); */ this.startRecording = function() { var mediaType = this.mediaType; var recorderType; var mimeType = this.mimeType || { audio: null, video: null, gif: null }; if (typeof mediaType.audio !== 'function' && isMediaRecorderCompatible() && mediaStream.getAudioTracks && !mediaStream.getAudioTracks().length) { // Firefox is supporting both audio/video in single blob mediaType.audio = false; } if (typeof mediaType.video !== 'function' && isMediaRecorderCompatible() && mediaStream.getVideoTracks && !mediaStream.getVideoTracks().length) { // Firefox is supporting both audio/video in single blob mediaType.video = false; } if (!mediaType.audio && !mediaType.video) { throw 'MediaStream must have either audio or video tracks.'; } if (!!mediaType.audio) { recorderType = null; if (typeof mediaType.audio === 'function') { 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 }); if (!mediaType.video) { this.audioRecorder.startRecording(); } } if (!!mediaType.video) { recorderType = null; if (typeof mediaType.video === 'function') { recorderType = mediaType.video; } var newStream = mediaStream; if (isMediaRecorderCompatible() && !!mediaType.audio && typeof mediaType.audio === 'function') { var videoTrack = mediaStream.getVideoTracks()[0]; if (!!navigator.mozGetUserMedia) { newStream = new MediaStream(); newStream.addTrack(videoTrack); if (recorderType && recorderType === WhammyRecorder) { // Firefox is NOT supporting webp-encoding yet recorderType = MediaStreamRecorder; } } else { 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 }); if (!mediaType.audio) { this.videoRecorder.startRecording(); } } if (!!mediaType.audio && !!mediaType.video) { var self = this; if (isMediaRecorderCompatible()) { self.audioRecorder = null; self.videoRecorder.startRecording(); } else { self.videoRecorder.initRecorder(function() { self.audioRecorder.initRecorder(function() { // Both recorders are ready to record things accurately self.videoRecorder.startRecording(); self.audioRecorder.startRecording(); }); }); } } if (!!mediaType.gif) { recorderType = null; if (typeof mediaType.gif === 'function') { 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 method stop recording. * @param {function} callback - Callback function is invoked when all encoders finish their jobs. * @method * @memberof MRecordRTC * @example * recorder.stopRecording(function(recording){ * var audioBlob = recording.audio; * var videoBlob = recording.video; * var gifBlob = recording.gif; * }); */ this.stopRecording = function(callback) { callback = callback || function() {}; if (this.audioRecorder) { this.audioRecorder.stopRecording(function(blobURL) { callback(blobURL, 'audio'); }); } if (this.videoRecorder) { this.videoRecorder.stopRecording(function(blobURL) { callback(blobURL, 'video'); }); } if (this.gifRecorder) { this.gifRecorder.stopRecording(function(blobURL) { callback(blobURL, 'gif'); }); } }; /** * This method can be used to manually get all recorded blobs. * @param {function} callback - All recorded blobs are passed back to "callback" function. * @method * @memberof MRecordRTC * @example * recorder.getBlob(function(recording){ * var audioBlob = recording.audio; * var videoBlob = recording.video; * var gifBlob = recording.gif; * }); * // or * var audioBlob = recorder.getBlob().audio; * var videoBlob = recorder.getBlob().video; */ this.getBlob = function(callback) { var output = {}; if (this.audioRecorder) { output.audio = this.audioRecorder.getBlob(); } if (this.videoRecorder) { output.video = this.videoRecorder.getBlob(); } if (this.gifRecorder) { output.gif = this.gifRecorder.getBlob(); } if (callback) { callback(output); } return output; }; /** * This method can be used to manually get all recorded blobs' DataURLs. * @param {function} callback - All recorded blobs' DataURLs are passed back to "callback" function. * @method * @memberof MRecordRTC * @example * recorder.getDataURL(function(recording){ * var audioDataURL = recording.audio; * var videoDataURL = recording.video; * var gifDataURL = recording.gif; * }); */ this.getDataURL = function(callback) { this.getBlob(function(blob) { getDataURL(blob.audio, function(_audioDataURL) { getDataURL(blob.video, function(_videoDataURL) { callback({ audio: _audioDataURL, video: _videoDataURL }); }); }); }); function getDataURL(blob, callback00) { if (typeof Worker !== 'undefined') { var webWorker = processInWebWorker(function readFile(_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 blob = URL.createObjectURL(new Blob([_function.toString(), 'this.onmessage = function (e) {' + _function.name + '(e.data);}' ], { type: 'application/javascript' })); var worker = new Worker(blob); var url; if (typeof URL !== 'undefined') { url = URL; } else if (typeof webkitURL !== 'undefined') { url = webkitURL; } else { throw 'Neither URL nor webkitURL detected.'; } url.revokeObjectURL(blob); return worker; } }; /** * This method can be used to ask {@link MRecordRTC} to write all recorded blobs into IndexedDB storage. * @method * @memberof MRecordRTC * @example * recorder.writeToDisk(); */ this.writeToDisk = function() { RecordRTC.writeToDisk({ audio: this.audioRecorder, video: this.videoRecorder, gif: this.gifRecorder }); }; /** * This method can be used to invoke save-as dialog for all recorded blobs. * @param {object} args - {audio: 'audio-name', video: 'video-name', gif: 'gif-name'} * @method * @memberof MRecordRTC * @example * recorder.save({ * audio: 'audio-file-name', * video: 'video-file-name', * gif : 'gif-file-name' * }); */ this.save = function(args) { args = args || { audio: true, video: true, gif: true }; if (!!args.audio && this.audioRecorder) { this.audioRecorder.save(typeof args.audio === 'string' ? args.audio : ''); } if (!!args.video && this.videoRecorder) { this.videoRecorder.save(typeof args.video === 'string' ? args.video : ''); } if (!!args.gif && this.gifRecorder) { this.gifRecorder.save(typeof args.gif === 'string' ? args.gif : ''); } }; } /** * This method can be used to get all recorded blobs from IndexedDB storage. * @param {string} type - 'all' or 'audio' or 'video' or 'gif' * @param {function} callback - Callback function to get all stored blobs. * @method * @memberof MRecordRTC * @example * MRecordRTC.getFromDisk('all', function(dataURL, type){ * if(type === 'audio') { } * if(type === 'video') { } * if(type === 'gif') { } * }); */ MRecordRTC.getFromDisk = RecordRTC.getFromDisk; /** * This method can be used to store recorded blobs into IndexedDB storage. * @param {object} options - {audio: Blob, video: Blob, gif: Blob} * @method * @memberof MRecordRTC * @example * MRecordRTC.writeToDisk({ * audio: audioBlob, * video: videoBlob, * gif : gifBlob * }); */ MRecordRTC.writeToDisk = RecordRTC.writeToDisk; if (typeof RecordRTC !== 'undefined') { RecordRTC.MRecordRTC = MRecordRTC; }