/// @class MediaRecorder
/ * * P r o v i d e s a r e c o r d e r t o r e c o r d f o t o s , a u d i o a n d v i d e o f r o m a w e b
browser client using the JavaScript getUserMedia feature .
@ param constraints The constraints as JSON data :
@ code
{
video : true , // true if you want to record video
audio : true // true if you want to record audio
}
@ endcode
You can record video or audio only or both together .
if not specified , defaults to @ ref defaultconstraints .
@ note Special thanks to the following projects :
- For the basics regarding getUserMedia :
http : //www.html5rocks.com/en/tutorials/getusermedia/intro/
- For a simple example of a media recorder :
https : //github.com/samdutton/simpl/blob/gh-pages/mediarecorder
@ note Supported browsers are :
- Firefox 29 or later
- Chrome 47 or later , with @ c " Enable experimental Web Platform
features " enabled from @c " chrome : //flags"
@ note This class must be used from within a secure context . A
secure context is an encrypted SSL connection through HTTPS , or
the special address @ c localhost .
@ todo Why are mediaSource and sourceBuffer needed ? They are not
further referenced .
* /
function MediaStreamRecorder ( constraints ) {
/// @name private variables
///@{
var events = [ ] ;
var mediaSource = new MediaSource ( ) ;
var stream ;
var mediaRecorder ;
var recordedBlobs = [ ] ;
var sourceBuffer ;
var defaultconstraints = {
audio : true ,
video : true
} ;
///@}
/// @name private methods
///@{
function createURL ( data ) {
var urlCreator = window . URL || window . webkitURL ;
return urlCreator ? urlCreator . createObjectURL ( data ) : data ;
}
///@}
/// @name internal event handlers
///@{
/// Create Source Buffer on Event Source Open
function handleSourceOpen ( event ) {
sourceBuffer = mediaSource . addSourceBuffer ( 'video/webm; codecs="vp8"' ) ;
}
/// Store Data in local Binary Large Object
function handleDataAvailable ( event ) {
if ( event . data && event . data . size > 0 ) {
recordedBlobs . push ( event . data ) ;
}
}
/// Propagate @c ready Event to Registered Handler
function handleReady ( ) {
if ( events [ 'ready' ] ) events [ 'ready' ] ( ) ;
}
/// Propagate @c start Event to Registered Handler
function handleStart ( ) {
if ( events [ 'stop' ] ) events [ 'start' ] ( ) ;
}
/// Propagate @c stop Event to Registered Handler
function handleStop ( event ) {
if ( events [ 'stop' ] ) events [ 'stop' ] ( event ) ;
}
///@}
/// @name public methods
///@{
/// Register Eventhandler
/ * * @ p a r a m e v e n t n a m e T h e f o l l o w i n g e v e n t s a r e a v a i l a b l e :
- @ c ready Video preview stream is ready for use
- @ c stop Recording has stopped , parameter : @ event
- @ c start Recording has started
@ param eventhandler callback function to be called when the
event occurs .
* /
this . on = function ( eventname , eventhandler ) {
events [ eventname ] = eventhandler ;
}
/// Get Stream to the Preview
/ * * @ r e t u r n D a t a U R L p r e p a r e d t o b e u s e d i n a H T M L @ c s r c
attribute within a @ c audio or @ c video tag . * /
this . preview = function ( ) {
return createURL ( stream ) ;
}
/// Get Stream to the Recording
/ * * @ p a r a m c a l l b a c k C a l l b a c k f u n c t i o n t h a t w i l l b e c a l l e d w i t h a
data url to be used in a HTML @ c src attribute within a
@ c audio or @ c video tag , or to be used in a HTML @ c
href attribute in a @ c a tag for downloading the
recording . * /
this . recording = function ( callback ) {
var reader = new FileReader ( ) ;
reader . onload = function ( e ) {
callback ( e . target . result ) ;
}
reader . readAsDataURL ( new Blob ( recordedBlobs , { type : 'video/webm' } ) ) ;
}
/// Start Stream Recording
/** @throws Exception if browser is not supported */
this . start = function ( ) {
// The nested try blocks will be simplified when Chrome 47 moves to Stable
var options = { mimeType : 'video/webm' } ;
recordedBlobs = [ ] ;
try {
mediaRecorder = new MediaRecorder ( stream , options ) ;
} catch ( e0 ) {
try {
options = { mimeType : 'video/webm,codecs=vp9' } ;
mediaRecorder = new MediaRecorder ( stream , options ) ;
} catch ( e1 ) {
try {
options = 'video/vp8' ; // Chrome 47
mediaRecorder = new MediaRecorder ( stream , options ) ;
} catch ( e2 ) {
throw {
text : 'MediaRecorder is not supported by browser' ,
e0 : e0 ,
e1 : e1 ,
e2 : e2
} ;
}
}
}
mediaRecorder . onstop = handleStop ;
mediaRecorder . ondataavailable = handleDataAvailable ;
mediaRecorder . start ( 10 ) ; // collect 10ms of data
handleStart ( ) ;
}
/// Stop Stream Recording
/** Use recording() to get access to the result. */
this . stop = function ( ) {
if ( mediaRecorder ) mediaRecorder . stop ( ) ;
delete mediaRecorder ; mediaRecorder = null ;
}
/// Close Preview Stream
/ * * C l o s e s t h e s t r e a m a n d r e l e a s e s t h e c a m e r a . T h i s s h o u l d a l w a y s
be called to cleanup , when the camera is no more needed . * /
this . release = function ( ) {
stop ( ) ;
stream . getTracks ( ) . forEach ( function ( track ) { track . stop ( ) } ) ;
delete stream ; stream = null ;
}
///@}
/// @name initialization
///@{
mediaSource . addEventListener ( 'sourceopen' , handleSourceOpen , false ) ;
if ( ! constraints ) constraints = defaultconstraints ;
navigator . mediaDevices . getUserMedia ( constraints )
. then ( function ( s ) {
stream = s ;
handleReady ( ) ;
} ) . catch ( function ( error ) {
throw error ;
} ) ;
///@}
}