recordrtc
Version:
RecordRTC is a server-less (entire client-side) JavaScript library that can be used to record WebRTC audio/video media streams. It supports cross-browser audio/video recording.
1,158 lines (927 loc) • 85.4 kB
HTML
<!--
> Muaz Khan - www.MuazKhan.com
> MIT License - www.WebRTC-Experiment.com/licence
> Documentation - github.com/muaz-khan/RecordRTC
> and - RecordRTC.org
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>RecordRTC | WebRTC Audio+Video+Screen Recording</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet" href="https://www.webrtc-experiment.com/style.css">
<style>
li {
border-bottom: 1px solid rgb(189, 189, 189);
border-left: 1px solid rgb(189, 189, 189);
padding: .5em;
}
label {
display: inline-block;
width: 8em;
}
h1 span {
background: yellow;
border: 2px solid #8e1515;
padding: 2px 8px;
margin: 2px 5px;
border-radius: 7px;
color: #8e1515;
display: inline-block;
}
.recordrtc button {
font-size: inherit;
}
.recordrtc button, .recordrtc select {
vertical-align: middle;
line-height: 1;
padding: 2px 5px;
height: auto;
font-size: inherit;
margin: 0;
}
.recordrtc, .recordrtc .header {
display: block;
text-align: center;
padding-top: 0;
}
.recordrtc video, .recordrtc img {
max-width: 100%!important;
vertical-align: top;
}
.recordrtc audio {
vertical-align: bottom;
}
.recordrtc option[disabled] {
display: none;
}
.recordrtc select {
font-size: 17px;
}
</style>
<script src="https://www.webrtc-experiment.com/RecordRTC.js"></script>
<!-- web streams API polyfill to support Firefox -->
<script src="https://unpkg.com/@mattiasbuelens/web-streams-polyfill/dist/polyfill.min.js"></script>
<!-- ../libs/DBML.js to fix video seeking issues -->
<script src="https://www.webrtc-experiment.com/EBML.js"></script>
<!-- for Edge/FF/Chrome/Opera/etc. getUserMedia support -->
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://www.webrtc-experiment.com/DetectRTC.js"> </script>
<!-- video element -->
<link href="https://www.webrtc-experiment.com/getHTMLMediaElement.css" rel="stylesheet">
<script src="https://www.webrtc-experiment.com/getHTMLMediaElement.js"></script>
</head>
<body>
<article>
<header style="text-align: center;">
<h1>
Audio+Video+Screen Recording using <a href="https://github.com/muaz-khan/RecordRTC">RecordRTC</a>
</h1>
<p style="margin:0;margin-bottom:-30px;margin-top: 15px;">
<a href="https://github.com/muaz-khan/RecordRTC">Github Source Codes</a> |
<a href="Canvas-Recording/">Canvas Recording</a> |
<a href="simple-demos/" style="color: #EC008C;border: 1px dotted;background: #ffffbe;padding: 0 6px;border-radius: 3px;">30+ Simple Demos</a>
<br><br>
<a href="https://www.npmjs.com/package/recordrtc"><img src="https://img.shields.io/npm/v/recordrtc.svg"></a>
<a href="https://www.npmjs.com/package/recordrtc"><img src="https://img.shields.io/npm/dm/recordrtc.svg"></a>
<a href="https://travis-ci.org/muaz-khan/RecordRTC"><img src="https://travis-ci.org/muaz-khan/RecordRTC.png?branch=master"></a>
</p>
</header>
<div class="github-stargazers" style="margin-top: 25px;"></div>
<section class="experiment recordrtc">
<h2 class="header" style="margin: 0;">
<select class="recording-media">
<option value="record-audio-plus-video">Microphone+Camera</option>
<option value="record-audio">Microphone</option>
<option value="record-screen">Full Screen</option>
<option value="record-audio-plus-screen">Microphone+Screen</option>
</select>
<span style="font-size: 15px;">into</span>
<select class="media-container-format">
<option>default</option>
<option>vp8</option>
<option>vp9</option>
<option>h264</option>
<option>mkv</option>
<option>opus</option>
<option>ogg</option>
<option>pcm</option>
<option>gif</option>
<option>whammy</option>
<option>WebAssembly</option>
</select>
<input type="checkbox" id="chk-timeSlice" style="margin:0;width:auto;" title="Use intervals based recording">
<label for="chk-timeSlice" style="font-size: 15px;margin:0;width: auto;cursor: pointer;-webkit-user-select:none;user-select:none;" title="Use intervals based recording">Use timeSlice?</label>
<br>
<button id="btn-start-recording">Start Recording</button>
<button id="btn-pause-recording" style="display: none; font-size: 15px;">Pause</button>
<div style="display: inline-block;">
<input type="checkbox" id="chk-fixSeeking" style="margin:0;width:auto;" title="Fix video seeking issues?">
<label for="chk-fixSeeking" style="font-size: 15px;margin:0;width: auto;cursor: pointer;-webkit-user-select:none;user-select:none;" title="Fix video seeking issues?">Fix Seeking Issues?</label>
</div>
<hr style="border-top: 0;border-bottom: 1px solid rgb(189, 189, 189);margin: 4px -12px;margin-top: 8px;">
<select class="media-resolutions">
<option value="default">Default resolutions</option>
<option value="1920x1080">1080p</option>
<option value="1280x720">720p</option>
<option value="640x480">480p</option>
<option value="3840x2160">4K Ultra HD (3840x2160)</option>
</select>
<select class="media-framerates">
<option value="default">Default framerates</option>
<option value="5">5 fps</option>
<option value="15">15 fps</option>
<option value="24">24 fps</option>
<option value="30">30 fps</option>
<option value="60">60 fps</option>
</select>
<select class="media-bitrates">
<option value="default">Default bitrates</option>
<option value="8000000000">1 GB bps</option>
<option value="800000000">100 MB bps</option>
<option value="8000000">1 MB bps</option>
<option value="800000">100 KB bps</option>
<option value="8000">1 KB bps</option>
<option value="800">100 Bytes bps</option>
</select>
</h2>
<div style="text-align: center; display: none;">
<button id="save-to-disk">Save To Disk</button>
<button id="upload-to-php">Upload to PHP</button>
<button id="open-new-tab">Open New Tab</button>
<div style="margin-top: 10px;">
<span id="signinButton" class="pre-sign-in">
<span
class="g-signin"
data-callback="signinCallback"
data-clientid="41556190767-115ifahd55lk4ln5pop4jus55cr4l7oh.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-scope="https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube">
</span>
</span>
<button id="upload-to-youtube" style="vertical-align:top;">Upload to YouTube</button>
</div>
</div>
<div style="margin-top: 10px;" id="recording-player"></div>
</section>
<script>
(function() {
var params = {},
r = /([^&=]+)=?([^&]*)/g;
function d(s) {
return decodeURIComponent(s.replace(/\+/g, ' '));
}
var match, search = window.location.search;
while (match = r.exec(search.substring(1))) {
params[d(match[1])] = d(match[2]);
if(d(match[2]) === 'true' || d(match[2]) === 'false') {
params[d(match[1])] = d(match[2]) === 'true' ? true : false;
}
}
window.params = params;
})();
function addStreamStopListener(stream, callback) {
stream.addEventListener('ended', function() {
callback();
callback = function() {};
}, false);
stream.addEventListener('inactive', function() {
callback();
callback = function() {};
}, false);
stream.getTracks().forEach(function(track) {
track.addEventListener('ended', function() {
callback();
callback = function() {};
}, false);
track.addEventListener('inactive', function() {
callback();
callback = function() {};
}, false);
});
}
</script>
<script>
var video = document.createElement('video');
video.controls = false;
var mediaElement = getHTMLMediaElement(video, {
title: 'Recording status: inactive',
buttons: ['full-screen'/*, 'take-snapshot'*/],
showOnMouseEnter: false,
width: 360,
onTakeSnapshot: function() {
var canvas = document.createElement('canvas');
canvas.width = mediaElement.clientWidth;
canvas.height = mediaElement.clientHeight;
var context = canvas.getContext('2d');
context.drawImage(recordingPlayer, 0, 0, canvas.width, canvas.height);
window.open(canvas.toDataURL('image/png'));
}
});
document.getElementById('recording-player').appendChild(mediaElement);
var div = document.createElement('section');
mediaElement.media.parentNode.appendChild(div);
mediaElement.media.muted = false;
mediaElement.media.autoplay = true;
mediaElement.media.playsinline = true;
div.appendChild(mediaElement.media);
var recordingPlayer = mediaElement.media;
var recordingMedia = document.querySelector('.recording-media');
var mediaContainerFormat = document.querySelector('.media-container-format');
var mimeType = 'video/webm';
var fileExtension = 'webm';
var type = 'video';
var recorderType;
var defaultWidth;
var defaultHeight;
var btnStartRecording = document.querySelector('#btn-start-recording');
window.onbeforeunload = function() {
btnStartRecording.disabled = false;
recordingMedia.disabled = false;
mediaContainerFormat.disabled = false;
chkFixSeeking.parentNode.style.display = 'inline-block';
};
btnStartRecording.onclick = function(event) {
var button = btnStartRecording;
if(button.innerHTML === 'Stop Recording') {
btnPauseRecording.style.display = 'none';
button.disabled = true;
button.disableStateWaiting = true;
setTimeout(function() {
button.disabled = false;
button.disableStateWaiting = false;
}, 2000);
button.innerHTML = 'Start Recording';
function stopStream() {
if(button.stream && button.stream.stop) {
button.stream.stop();
button.stream = null;
}
if(button.stream instanceof Array) {
button.stream.forEach(function(stream) {
stream.stop();
});
button.stream = null;
}
videoBitsPerSecond = null;
var html = 'Recording status: stopped';
html += '<br>Size: ' + bytesToSize(button.recordRTC.getBlob().size);
recordingPlayer.parentNode.parentNode.querySelector('h2').innerHTML = html;
}
if(button.recordRTC) {
if(button.recordRTC.length) {
button.recordRTC[0].stopRecording(function(url) {
if(!button.recordRTC[1]) {
button.recordingEndedCallback(url);
stopStream();
saveToDiskOrOpenNewTab(button.recordRTC[0]);
return;
}
button.recordRTC[1].stopRecording(function(url) {
button.recordingEndedCallback(url);
stopStream();
});
});
}
else {
button.recordRTC.stopRecording(function(url) {
if(button.blobs && button.blobs.length) {
var blob = new File(button.blobs, getFileName(fileExtension), {
type: mimeType
});
button.recordRTC.getBlob = function() {
return blob;
};
url = URL.createObjectURL(blob);
}
if(chkFixSeeking.checked === true) {
// to fix video seeking issues
getSeekableBlob(button.recordRTC.getBlob(), function(seekableBlob) {
button.recordRTC.getBlob = function() {
return seekableBlob;
};
url = URL.createObjectURL(seekableBlob);
button.recordingEndedCallback(url);
saveToDiskOrOpenNewTab(button.recordRTC);
stopStream();
})
return;
}
button.recordingEndedCallback(url);
saveToDiskOrOpenNewTab(button.recordRTC);
stopStream();
});
}
}
return;
}
if(!event) return;
button.disabled = true;
var commonConfig = {
onMediaCaptured: function(stream) {
button.stream = stream;
if(button.mediaCapturedCallback) {
button.mediaCapturedCallback();
}
button.innerHTML = 'Stop Recording';
button.disabled = false;
chkFixSeeking.parentNode.style.display = 'none';
},
onMediaStopped: function() {
button.innerHTML = 'Start Recording';
if(!button.disableStateWaiting) {
button.disabled = false;
}
chkFixSeeking.parentNode.style.display = 'inline-block';
},
onMediaCapturingFailed: function(error) {
console.error('onMediaCapturingFailed:', error);
if(error.toString().indexOf('no audio or video tracks available') !== -1) {
alert('RecordRTC failed to start because there are no audio or video tracks available.');
}
if(error.name === 'PermissionDeniedError' && DetectRTC.browser.name === 'Firefox') {
alert('Firefox requires version >= 52. Firefox also requires HTTPs.');
}
commonConfig.onMediaStopped();
}
};
if(mediaContainerFormat.value === 'h264') {
mimeType = 'video/webm\;codecs=h264';
fileExtension = 'mp4';
// video/mp4;codecs=avc1
if(isMimeTypeSupported('video/mpeg')) {
mimeType = 'video/mpeg';
}
}
if(mediaContainerFormat.value === 'mkv' && isMimeTypeSupported('video/x-matroska;codecs=avc1')) {
mimeType = 'video/x-matroska;codecs=avc1';
fileExtension = 'mkv';
}
if(mediaContainerFormat.value === 'vp8' && isMimeTypeSupported('video/webm\;codecs=vp8')) {
mimeType = 'video/webm\;codecs=vp8';
fileExtension = 'webm';
recorderType = null;
type = 'video';
}
if(mediaContainerFormat.value === 'vp9' && isMimeTypeSupported('video/webm\;codecs=vp9')) {
mimeType = 'video/webm\;codecs=vp9';
fileExtension = 'webm';
recorderType = null;
type = 'video';
}
if(mediaContainerFormat.value === 'pcm') {
mimeType = 'audio/wav';
fileExtension = 'wav';
recorderType = StereoAudioRecorder;
type = 'audio';
}
if(mediaContainerFormat.value === 'opus' || mediaContainerFormat.value === 'ogg') {
if(isMimeTypeSupported('audio/webm')) {
mimeType = 'audio/webm';
fileExtension = 'webm'; // webm
}
if(isMimeTypeSupported('audio/ogg')) {
mimeType = 'audio/ogg; codecs=opus';
fileExtension = 'ogg'; // ogg
}
recorderType = null;
type = 'audio';
}
if(mediaContainerFormat.value === 'whammy') {
mimeType = 'video/webm';
fileExtension = 'webm';
recorderType = WhammyRecorder;
type = 'video';
}
if(mediaContainerFormat.value === 'WebAssembly') {
mimeType = 'video/webm';
fileExtension = 'webm';
recorderType = WebAssemblyRecorder;
type = 'video';
}
if(mediaContainerFormat.value === 'gif') {
mimeType = 'image/gif';
fileExtension = 'gif';
recorderType = GifRecorder;
type = 'gif';
}
if(mediaContainerFormat.value === 'default') {
mimeType = 'video/webm';
fileExtension = 'webm';
recorderType = null;
type = 'video';
}
if(recordingMedia.value === 'record-audio') {
captureAudio(commonConfig);
button.mediaCapturedCallback = function() {
var options = {
type: type,
mimeType: mimeType,
leftChannel: params.leftChannel || false,
disableLogs: params.disableLogs || false
};
if(params.sampleRate) {
options.sampleRate = parseInt(params.sampleRate);
}
if(params.bufferSize) {
options.bufferSize = parseInt(params.bufferSize);
}
if(recorderType) {
options.recorderType = recorderType;
}
if(videoBitsPerSecond) {
options.videoBitsPerSecond = videoBitsPerSecond;
}
if(DetectRTC.browser.name === 'Edge') {
options.numberOfAudioChannels = 1;
}
options.ignoreMutedMedia = false;
button.recordRTC = RecordRTC(button.stream, options);
button.recordingEndedCallback = function(url) {
setVideoURL(url);
};
button.recordRTC.startRecording();
btnPauseRecording.style.display = '';
};
}
if(recordingMedia.value === 'record-audio-plus-video') {
captureAudioPlusVideo(commonConfig);
button.mediaCapturedCallback = function() {
if(typeof MediaRecorder === 'undefined') { // opera or chrome etc.
button.recordRTC = [];
if(!params.bufferSize) {
// it fixes audio issues whilst recording 720p
params.bufferSize = 16384;
}
var options = {
type: 'audio', // hard-code to set "audio"
leftChannel: params.leftChannel || false,
disableLogs: params.disableLogs || false,
video: recordingPlayer
};
if(params.sampleRate) {
options.sampleRate = parseInt(params.sampleRate);
}
if(params.bufferSize) {
options.bufferSize = parseInt(params.bufferSize);
}
if(params.frameInterval) {
options.frameInterval = parseInt(params.frameInterval);
}
if(recorderType) {
options.recorderType = recorderType;
}
if(videoBitsPerSecond) {
options.videoBitsPerSecond = videoBitsPerSecond;
}
options.ignoreMutedMedia = false;
var audioRecorder = RecordRTC(button.stream, options);
options.type = type;
var videoRecorder = RecordRTC(button.stream, options);
// to sync audio/video playbacks in browser!
videoRecorder.initRecorder(function() {
audioRecorder.initRecorder(function() {
audioRecorder.startRecording();
videoRecorder.startRecording();
btnPauseRecording.style.display = '';
});
});
button.recordRTC.push(audioRecorder, videoRecorder);
button.recordingEndedCallback = function() {
var audio = new Audio();
audio.src = audioRecorder.toURL();
audio.controls = true;
audio.autoplay = true;
recordingPlayer.parentNode.appendChild(document.createElement('hr'));
recordingPlayer.parentNode.appendChild(audio);
if(audio.paused) audio.play();
};
return;
}
var options = {
type: type,
mimeType: mimeType,
disableLogs: params.disableLogs || false,
getNativeBlob: false, // enable it for longer recordings
video: recordingPlayer
};
if(recorderType) {
options.recorderType = recorderType;
if(recorderType == WhammyRecorder || recorderType == GifRecorder || recorderType == WebAssemblyRecorder) {
options.canvas = options.video = {
width: defaultWidth || 320,
height: defaultHeight || 240
};
}
}
if(videoBitsPerSecond) {
options.videoBitsPerSecond = videoBitsPerSecond;
}
if(timeSlice && typeof MediaRecorder !== 'undefined') {
options.timeSlice = timeSlice;
button.blobs = [];
options.ondataavailable = function(blob) {
button.blobs.push(blob);
};
}
options.ignoreMutedMedia = false;
button.recordRTC = RecordRTC(button.stream, options);
button.recordingEndedCallback = function(url) {
setVideoURL(url);
};
button.recordRTC.startRecording();
btnPauseRecording.style.display = '';
recordingPlayer.parentNode.parentNode.querySelector('h2').innerHTML = '<img src="https://www.webrtc-experiment.com/images/progress.gif">';
};
}
if(recordingMedia.value === 'record-screen') {
captureScreen(commonConfig);
button.mediaCapturedCallback = function() {
var options = {
type: type,
mimeType: mimeType,
disableLogs: params.disableLogs || false,
getNativeBlob: false, // enable it for longer recordings
video: recordingPlayer
};
if(recorderType) {
options.recorderType = recorderType;
if(recorderType == WhammyRecorder || recorderType == GifRecorder || recorderType == WebAssemblyRecorder) {
options.canvas = options.video = {
width: defaultWidth || 320,
height: defaultHeight || 240
};
}
}
if(videoBitsPerSecond) {
options.videoBitsPerSecond = videoBitsPerSecond;
}
options.ignoreMutedMedia = false;
button.recordRTC = RecordRTC(button.stream, options);
button.recordingEndedCallback = function(url) {
setVideoURL(url);
};
button.recordRTC.startRecording();
btnPauseRecording.style.display = '';
};
}
// note: audio+tab is supported in Chrome 50+
// todo: add audio+tab recording
if(recordingMedia.value === 'record-audio-plus-screen') {
captureAudioPlusScreen(commonConfig);
button.mediaCapturedCallback = function() {
var options = {
type: type,
mimeType: mimeType,
disableLogs: params.disableLogs || false,
getNativeBlob: false, // enable it for longer recordings
video: recordingPlayer
};
if(recorderType) {
options.recorderType = recorderType;
if(recorderType == WhammyRecorder || recorderType == GifRecorder || recorderType == WebAssemblyRecorder) {
options.canvas = options.video = {
width: defaultWidth || 320,
height: defaultHeight || 240
};
}
}
if(videoBitsPerSecond) {
options.videoBitsPerSecond = videoBitsPerSecond;
}
options.ignoreMutedMedia = false;
button.recordRTC = RecordRTC(button.stream, options);
button.recordingEndedCallback = function(url) {
setVideoURL(url);
};
button.recordRTC.startRecording();
btnPauseRecording.style.display = '';
};
}
};
function captureVideo(config) {
captureUserMedia({video: true}, function(videoStream) {
config.onMediaCaptured(videoStream);
addStreamStopListener(videoStream, function() {
config.onMediaStopped();
});
}, function(error) {
config.onMediaCapturingFailed(error);
});
}
function captureAudio(config) {
captureUserMedia({audio: true}, function(audioStream) {
config.onMediaCaptured(audioStream);
addStreamStopListener(audioStream, function() {
config.onMediaStopped();
});
}, function(error) {
config.onMediaCapturingFailed(error);
});
}
function captureAudioPlusVideo(config) {
captureUserMedia({video: true, audio: true}, function(audioVideoStream) {
config.onMediaCaptured(audioVideoStream);
if(audioVideoStream instanceof Array) {
audioVideoStream.forEach(function(stream) {
addStreamStopListener(stream, function() {
config.onMediaStopped();
});
});
return;
}
addStreamStopListener(audioVideoStream, function() {
config.onMediaStopped();
});
}, function(error) {
config.onMediaCapturingFailed(error);
});
}
var MY_DOMAIN = 'webrtc-experiment.com';
function isMyOwnDomain() {
// replace "webrtc-experiment.com" with your own domain name
return document.domain.indexOf(MY_DOMAIN) !== -1;
}
function isLocalHost() {
// "chrome.exe" --enable-usermedia-screen-capturing
// or firefox => about:config => "media.getusermedia.screensharing.allowed_domains" => add "localhost"
return document.domain === 'localhost' || document.domain === '127.0.0.1';
}
var videoBitsPerSecond;
function setVideoBitrates() {
var select = document.querySelector('.media-bitrates');
var value = select.value;
if(value == 'default') {
videoBitsPerSecond = null;
return;
}
videoBitsPerSecond = parseInt(value);
}
function getFrameRates(mediaConstraints) {
if(!mediaConstraints.video) {
return mediaConstraints;
}
var select = document.querySelector('.media-framerates');
var value = select.value;
if(value == 'default') {
return mediaConstraints;
}
value = parseInt(value);
if(DetectRTC.browser.name === 'Firefox') {
mediaConstraints.video.frameRate = value;
return mediaConstraints;
}
if(!mediaConstraints.video.mandatory) {
mediaConstraints.video.mandatory = {};
mediaConstraints.video.optional = [];
}
var isScreen = recordingMedia.value.toString().toLowerCase().indexOf('screen') != -1;
if(isScreen) {
mediaConstraints.video.mandatory.maxFrameRate = value;
}
else {
mediaConstraints.video.mandatory.minFrameRate = value;
}
return mediaConstraints;
}
function setGetFromLocalStorage(selectors) {
selectors.forEach(function(selector) {
var storageItem = selector.replace(/\.|#/g, '');
if(localStorage.getItem(storageItem)) {
document.querySelector(selector).value = localStorage.getItem(storageItem);
}
addEventListenerToUploadLocalStorageItem(selector, ['change', 'blur'], function() {
localStorage.setItem(storageItem, document.querySelector(selector).value);
});
});
}
function addEventListenerToUploadLocalStorageItem(selector, arr, callback) {
arr.forEach(function(event) {
document.querySelector(selector).addEventListener(event, callback, false);
});
}
setGetFromLocalStorage(['.media-resolutions', '.media-framerates', '.media-bitrates', '.recording-media', '.media-container-format']);
function getVideoResolutions(mediaConstraints) {
if(!mediaConstraints.video) {
return mediaConstraints;
}
var select = document.querySelector('.media-resolutions');
var value = select.value;
if(value == 'default') {
return mediaConstraints;
}
value = value.split('x');
if(value.length != 2) {
return mediaConstraints;
}
defaultWidth = parseInt(value[0]);
defaultHeight = parseInt(value[1]);
if(DetectRTC.browser.name === 'Firefox') {
mediaConstraints.video.width = defaultWidth;
mediaConstraints.video.height = defaultHeight;
return mediaConstraints;
}
if(!mediaConstraints.video.mandatory) {
mediaConstraints.video.mandatory = {};
mediaConstraints.video.optional = [];
}
var isScreen = recordingMedia.value.toString().toLowerCase().indexOf('screen') != -1;
if(isScreen) {
mediaConstraints.video.mandatory.maxWidth = defaultWidth;
mediaConstraints.video.mandatory.maxHeight = defaultHeight;
}
else {
mediaConstraints.video.mandatory.minWidth = defaultWidth;
mediaConstraints.video.mandatory.minHeight = defaultHeight;
}
return mediaConstraints;
}
function captureUserMedia(mediaConstraints, successCallback, errorCallback) {
if(mediaConstraints.video == true) {
mediaConstraints.video = {};
}
setVideoBitrates();
mediaConstraints = getVideoResolutions(mediaConstraints);
mediaConstraints = getFrameRates(mediaConstraints);
var isBlackBerry = !!(/BB10|BlackBerry/i.test(navigator.userAgent || ''));
if(isBlackBerry && !!(navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia)) {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
navigator.getUserMedia(mediaConstraints, successCallback, errorCallback);
return;
}
navigator.mediaDevices.getUserMedia(mediaConstraints).then(function(stream) {
successCallback(stream);
setVideoURL(stream, true);
}).catch(function(error) {
if(error && (error.name === 'ConstraintNotSatisfiedError' || error.name === 'OverconstrainedError')) {
alert('Your camera or browser does NOT supports selected resolutions or frame-rates. \n\nPlease select "default" resolutions.');
}
else if(error && error.message) {
alert(error.message);
}
else {
alert('Unable to make getUserMedia request. Please check browser console logs.');
}
errorCallback(error);
});
}
function setMediaContainerFormat(arrayOfOptionsSupported) {
var options = Array.prototype.slice.call(
mediaContainerFormat.querySelectorAll('option')
);
var localStorageItem;
if(localStorage.getItem('media-container-format')) {
localStorageItem = localStorage.getItem('media-container-format');
}
var selectedItem;
options.forEach(function(option) {
option.disabled = true;
if(arrayOfOptionsSupported.indexOf(option.value) !== -1) {
option.disabled = false;
if(localStorageItem && arrayOfOptionsSupported.indexOf(localStorageItem) != -1) {
if(option.value != localStorageItem) return;
option.selected = true;
selectedItem = option;
return;
}
if(!selectedItem) {
option.selected = true;
selectedItem = option;
}
}
});
}
function isMimeTypeSupported(mimeType) {
if(typeof MediaRecorder === 'undefined') {
return false;
}
if(typeof MediaRecorder.isTypeSupported !== 'function') {
return true;
}
return MediaRecorder.isTypeSupported(mimeType);
}
recordingMedia.onchange = function() {
if(recordingMedia.value === 'record-audio') {
var recordingOptions = [];
if(isMimeTypeSupported('audio/webm')) {
recordingOptions.push('opus');
}
if(isMimeTypeSupported('audio/ogg')) {
recordingOptions.push('ogg');
}
recordingOptions.push('pcm');
setMediaContainerFormat(recordingOptions);
return;
}
var isChrome = !!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0);
var recordingOptions = ['vp8']; // MediaStreamRecorder with vp8
if(isMimeTypeSupported('video/webm\;codecs=vp9')) {
recordingOptions.push('vp9'); // MediaStreamRecorder with vp9
}
if(isMimeTypeSupported('video/webm\;codecs=h264')) {
recordingOptions.push('h264'); // MediaStreamRecorder with h264
}
if(isMimeTypeSupported('video/x-matroska;codecs=avc1')) {
recordingOptions.push('mkv'); // MediaStreamRecorder with mkv/matroska
}
recordingOptions.push('gif'); // GifRecorder
if(DetectRTC.browser.name == 'Chrome') {
recordingOptions.push('whammy'); // WhammyRecorder
}
if(DetectRTC.browser.name == 'Chrome') {
recordingOptions.push('WebAssembly'); // WebAssemblyRecorder
}
recordingOptions.push('default'); // Default mimeType for MediaStreamRecorder
setMediaContainerFormat(recordingOptions);
};
recordingMedia.onchange();
if(typeof MediaRecorder === 'undefined' && (DetectRTC.browser.name === 'Edge' || DetectRTC.browser.name === 'Safari')) {
// webp isn't supported in Microsoft Edge
// neither MediaRecorder API
// so lets disable both video/screen recording options
console.warn('Neither MediaRecorder API nor webp is supported in ' + DetectRTC.browser.name + '. You cam merely record audio.');
recordingMedia.innerHTML = '<option value="record-audio">Audio</option>';
setMediaContainerFormat(['pcm']);
}
function stringify(obj) {
var result = '';
Object.keys(obj).forEach(function(key) {
if(typeof obj[key] === 'function') {
return;
}
if(result.length) {
result += ',';
}
result += key + ': ' + obj[key];
});
return result;
}
function mediaRecorderToStringify(mediaRecorder) {
var result = '';
result += 'mimeType: ' + mediaRecorder.mimeType;
result += ', state: ' + mediaRecorder.state;
result += ', audioBitsPerSecond: ' + mediaRecorder.audioBitsPerSecond;
result += ', videoBitsPerSecond: ' + mediaRecorder.videoBitsPerSecond;
if(mediaRecorder.stream) {
result += ', streamid: ' + mediaRecorder.stream.id;
result += ', stream-active: ' + mediaRecorder.stream.active;
}
return result;
}
function getFailureReport() {
var info = 'RecordRTC seems failed. \n\n' + stringify(DetectRTC.browser) + '\n\n' + DetectRTC.osName + ' ' + DetectRTC.osVersion + '\n';
if (typeof recorderType !== 'undefined' && recorderType) {
info += '\nrecorderType: ' + recorderType.name;
}
if (typeof mimeType !== 'undefined') {
info += '\nmimeType: ' + mimeType;
}
Array.prototype.slice.call(document.querySelectorAll('select')).forEach(function(select) {
info += '\n' + (select.id || select.className) + ': ' + select.value;
});
if (btnStartRecording.recordRTC) {
info += '\n\ninternal-recorder: ' + btnStartRecording.recordRTC.getInternalRecorder().name;
if(btnStartRecording.recordRTC.getInternalRecorder().getAllStates) {
info += '\n\nrecorder-states: ' + btnStartRecording.recordRTC.getInternalRecorder().getAllStates();
}
}
if(btnStartRecording.stream) {
info += '\n\naudio-tracks: ' + getTracks(btnStartRecording.stream, 'audio').length;
info += '\nvideo-tracks: ' + getTracks(btnStartRecording.stream, 'video').length;
info += '\nstream-active? ' + !!btnStartRecording.stream.active;
btnStartRecording.stream.getTracks().forEach(function(track) {
info += '\n' + track.kind + '-track-' + (track.label || track.id) + ': (enabled: ' + !!track.enabled + ', readyState: ' + track.readyState + ', muted: ' + !!track.muted + ')';
if(track.getConstraints && Object.keys(track.getConstraints()).length) {
info += '\n' + track.kind + '-track-getConstraints: ' + stringify(track.getConstraints());
}
if(track.getSettings && Object.keys(track.getSettings()).length) {
info += '\n' + track.kind + '-track-getSettings: ' + stringify(track.getSettings());
}
});
}
if(timeSlice && btnStartRecording.recordRTC) {
info += '\ntimeSlice: ' + timeSlice;
if(btnStartRecording.recordRTC.getInternalRecorder().getArrayOfBlobs) {
var blobSizes = [];
btnStartRecording.recordRTC.getInternalRecorder().getArrayOfBlobs().forEach(function(blob) {
blobSizes.push(blob.size);
});
info += '\nblobSizes: ' + blobSizes;
}
}
else if(btnStartRecording.recordRTC && btnStartRecording.recordRTC.getBlob()) {
info += '\n\nblobSize: ' + bytesToSize(btnStartRecording.recordRTC.getBlob().size);
}
if(btnStartRecording.recordRTC && btnStartRecording.recordRTC.getInternalRecorder() && btnStartRecording.recordRTC.getInternalRecorder().getInternalRecorder && btnStartRecording.recordRTC.getInternalRecorder().getInternalRecorder()) {
info += '\n\ngetInternalRecorder: ' + mediaRecorderToStringify(btnStartRecording.recordRTC.getInternalRecorder().getInternalRecorder());
}
return info;
}
function saveToDiskOrOpenNewTab(recordRTC) {
if(!recordRTC.getBlob().size) {
var info = getFailureReport();
console.log('blob', recordRTC.getBlob());
console.log('recordrtc instance', recordRTC);