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
JavaScript
// _____________
// 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;
}