UNPKG

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
<!-- > 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);