var video = document.querySelector('video'); var audio = document.querySelector('audio'); if(!navigator.getDisplayMedia && !navigator.mediaDevices.getDisplayMedia) { var error = tr('Recording WebRTC not supported in this browser.'); $('.box-recordrtc .card-body').html(error); throw new Error(error); } var isEdge = navigator.userAgent.indexOf('Edge') !== -1 && (!!navigator.msSaveOrOpenBlob || !!navigator.msSaveBlob); var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const VIDEO_STREAM_CONSTRAINTS = { video: true, }; const AUDIO_STREAM_CONSTRAINTS = { audio: isEdge ? true : { echoCancellation: false } }; const VIDEO_AND_AUDIO_STREAM_CONSTRAINTS = { ...AUDIO_STREAM_CONSTRAINTS, ...VIDEO_STREAM_CONSTRAINTS }; // globally accessible var recorder; var microphone; var recordingInstance; var listOfFilesUploaded = []; function uploadToServer(recordRTC, callback) { var blob = recordRTC instanceof Blob ? recordRTC : recordRTC.blob; var fileType = blob.type.split('/')[0] || 'audio'; var fileName = moment().format('YYYYMMDDhmmss'); var upload_url = document.getElementById('record-rtc-url').value; var ticket = document.getElementById('record-rtc-ticket').value; var customFileName = document.getElementById('record-name').value; if (fileType === 'audio') { fileName = customFileName ? customFileName : 'audio_record_' + fileName; fileName += '.' + (!!navigator.mozGetUserMedia ? 'ogg' : 'wav'); } else { fileName = customFileName ? customFileName : 'video_record_' + fileName; fileName += '.webm'; } // create FormData var formData = new FormData(); formData.append(fileType + 'filename', fileName); formData.append(fileType + 'blob', blob); formData.append('ticket', ticket); callback('Uploading ' + fileType + ' recording to server.'); makeXMLHttpRequest(upload_url, formData, function(progress, response) { if (progress !== 'upload-ended') { callback(progress); return; } if (!!response) { response = JSON.parse(response); var fileId = response.fileId; var thumbBox = ''; var fileUrl = ''; var nextTicket = ''; if (fileId) { thumbBox = '{mediaplayer src="display' + fileId + '"}'; fileUrl = 'tiki-download_file.php?fileId=' + fileId; nextTicket = response.nextTicket; } } var fileData = { 'thumbBox': thumbBox, 'fileUrl': fileUrl, 'fileName': fileName, 'ticket': nextTicket }; callback('ended', fileData, nextTicket); // to make sure we can delete as soon as visitor leaves listOfFilesUploaded.push(fileName); }); } function makeXMLHttpRequest(url, data, callback) { var request = new XMLHttpRequest(); request.onreadystatechange = function() { if (request.readyState == 4) { callback('upload-ended', request.response); } }; request.upload.onloadstart = function() { callback('Upload started...'); }; request.upload.onprogress = function(event) { callback('Upload progress ' + Math.round(event.loaded / event.total * 100) + "%"); }; request.upload.onload = function() { callback('Upload finished'); }; request.upload.onerror = function(error) { callback('Failed to upload to server'); console.error('XMLHttpRequest failed', error); }; request.upload.onabort = function(error) { callback('Upload aborted.'); console.error('XMLHttpRequest aborted', error); }; request.open('POST', url); request.send(data); } 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); }); } function startUpload() { if (recorder) { var $feedback = $('#upload-feedback span').text('Uploading... Please wait.').show(); var autoUpload = $('#record-rtc-auto-upload'); autoUpload.removeAttr('checked'); uploadToServer(recorder, function(progress, fileData, ticket) { if(progress === 'ended') { if (fileData.fileUrl && fileData.fileName) { let extension = fileData.fileName.split('.').pop(); $('#record-download a').attr('href', fileData.fileUrl).text(fileData.fileName); $('#record-download span').text('Upload finished '); if (fileData.thumbBox) { $('#record-download').append('
' + fileData.thumbBox + ''); } if (ticket) { document.getElementById('record-rtc-ticket').value = ticket; } recorder.destroy(); recorder = null; } else { $('#btn-upload-recording').show(); $('#record-download span').html('

Something went wrong when uploading this file. Please try again.

'); } } }); } } /** * Request permissions for specific constraints related with the display. * @param constraints * @param onSuccess * @param onFailure */ function getDisplayMedia(constraints, onSuccess, onFailure) { if(navigator.mediaDevices.getDisplayMedia) { navigator.mediaDevices.getDisplayMedia(constraints).then(onSuccess).catch(onFailure); } else { navigator.getDisplayMedia(constraints).then(onSuccess).catch(onFailure); } } /** * Request permissions for specific constraints associated with the media input. * @param constraints * @param onSuccess * @param onFailure */ function getUserMedia(constraints, onSuccess, onFailure) { if(navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia(constraints).then(onSuccess).catch(onFailure); } else { navigator.getUserMedia(constraints).then(onSuccess).catch(onFailure); } } /** * Show recording feedback based on currently recorded blob type * @return void */ function showRecordingFeedback(recordingType) { const blob = recorder.getBlob(); const fileType = blob.type.split('/')[0] || 'audio'; const src = URL.createObjectURL(blob); var html = '
'; if (fileType === 'audio') { html += '
'; } else { html += '
'; } html += '
' + '' + '' + '
'; html += '
'; var $feedback = $('#upload-feedback').show(); $feedback.html(html); } class RecordMicrophone { constructor() { if (!microphone) { this.requestPermissions(function(mic) { microphone = mic; if(isSafari) { replaceAudio(); alert('Please click startRecording button again. First time we tried to access your microphone. Now we will record it.'); } var options = { type: 'audio', numberOfAudioChannels: isEdge ? 1 : 2, checkForInactiveTracks: true, bufferSize: 16384 }; if(isSafari || isEdge) { options.recorderType = StereoAudioRecorder; } if(navigator.platform && navigator.platform.toString().toLowerCase().indexOf('win') === -1) { options.sampleRate = 48000; // or 44100 or remove this line for default } if(isSafari) { options.sampleRate = 44100; options.bufferSize = 4096; options.numberOfAudioChannels = 2; } if(recorder) { recorder.destroy(); recorder = null; } recorder = RecordRTC(microphone, options); recorder.startRecording(); $('#btn-start-recording').hide().prop('disabled', false); $('#btn-stop-recording').show(); }); } } stopRecording() { if (recorder && typeof recorder.stopRecording === "function") { recorder.stopRecording(function() { showRecordingFeedback(); var autoUpload = $('#record-rtc-auto-upload').is(':checked'); if (autoUpload == true) { startUpload(); } else { $('#btn-upload-recording').show(); } $('#btn-start-recording').show(); $('#btn-stop-recording').hide(); microphone.stop(); microphone = null; }); } } requestPermissions(callback) { getUserMedia(AUDIO_STREAM_CONSTRAINTS, function(mic) { callback(mic); }, function(error) { alert('Unable to capture your microphone. Please check console logs.'); console.error(error); }); } } class RecordCameraAndAudio { constructor() { getUserMedia(VIDEO_AND_AUDIO_STREAM_CONSTRAINTS, function(camera) { recorder = RecordRTC(camera, { type: 'video' }); recorder.startRecording(); recorder.camera = camera; $('#btn-start-recording').hide().prop('disabled', false); $('#btn-stop-recording').show(); }, function(error) { alert('Unable to capture your camera. Please check console logs.'); console.error(error); }); } stopRecording() { if (recorder && typeof recorder.stopRecording === "function") { recorder.camera.stop(); recorder.stopRecording(function() { showRecordingFeedback(); var autoUpload = $('#record-rtc-auto-upload').is(':checked'); if (autoUpload == true) { startUpload(); } else { $('#btn-upload-recording').show(); } $('#btn-start-recording').show(); $('#btn-stop-recording').hide(); }); } } } class RecordScreen { constructor() { this.requestPermissions(function (screen) { recorder = RecordRTC(screen, { type: 'video' }); recorder.startRecording(); // release screen on stopRecording recorder.screen = screen; $('#btn-start-recording').hide().prop('disabled', false); $('#btn-stop-recording').show(); }); } stopRecording() { if (recorder && typeof recorder.stopRecording === "function") { recorder.screen.stop(); recorder.stopRecording(function() { showRecordingFeedback(); var autoUpload = $('#record-rtc-auto-upload').is(':checked'); if (autoUpload == true) { startUpload(); } else { $('#btn-upload-recording').show(); } $('#btn-start-recording').show(); $('#btn-stop-recording').hide(); }); } } requestPermissions(callback) { getDisplayMedia(VIDEO_STREAM_CONSTRAINTS, function(screen) { addStreamStopListener(screen, function() { $('#btn-stop-recording').click(); }); callback(screen); }, function(error) { console.error(error); alert('Unable to capture your screen. \n' + error); $('#btn-start-recording').show().prop('disabled', false); }); } } class RecordScreenAndMicrophone { constructor() { this.requestPermissions(function (screen) { recorder = RecordRTC(screen, { type: 'video' }); recorder.startRecording(); // release screen on stopRecording recorder.screen = screen; $('#btn-start-recording').hide().prop('disabled', false); $('#btn-stop-recording').show(); }); } stopRecording() { recorder.screen.stop(); if (recorder && typeof recorder.stopRecording === "function") { recorder.stopRecording(function() { showRecordingFeedback(); var autoUpload = $('#record-rtc-auto-upload').is(':checked'); if (autoUpload == true) { startUpload(); } else { $('#btn-upload-recording').show(); } $('#btn-start-recording').show(); $('#btn-stop-recording').hide(); recorder.screen = null; }); } } requestPermissions(callback) { getDisplayMedia(VIDEO_STREAM_CONSTRAINTS, function(screen) { getUserMedia(AUDIO_STREAM_CONSTRAINTS, function(mic) { screen.addTrack(mic.getTracks()[0]); addStreamStopListener(screen, function() { $('#btn-stop-recording').click(); }); callback(screen); }); }, function(error) { console.error(error); alert('Unable to capture your screen. \n' + error); $('#btn-start-recording').show().prop('disabled', false); }); } } $('#btn-start-recording').on('click', function () { $(this).prop('disabled', true); $('#upload-feedback').hide(); switch ($('#mod_record_rtc_recording_type').val()) { case 'screen': recordingInstance = new RecordScreen(); break; case 'microphone': recordingInstance = new RecordMicrophone(); break; case 'screen,microphone': recordingInstance = new RecordScreenAndMicrophone(); break; case 'camera,microphone': recordingInstance = new RecordCameraAndAudio(); break; default: console.error('Recording type not implemented.'); } }); $('#btn-stop-recording').on('click', function(e) { e.preventDefault(); recordingInstance.stopRecording(); }); $('#btn-upload-recording').on('click', function(e) { e.preventDefault(); $('#btn-upload-recording').hide(); startUpload(); }); $('#mod_record_rtc_recording_type').on('change', function(e) { $('#btn-start-recording').prop('disabled', !$(this).val()); });