Share this meeting invite others to join.
+` + + RoomURL + + `
`, + showDenyButton: true, + showCancelButton: true, + confirmButtonText: `Copy meeting URL`, + denyButtonText: `Email invite`, + cancelButtonText: `Close`, + showClass: { + popup: 'animate__animated animate__fadeInUp', + }, + hideClass: { + popup: 'animate__animated animate__fadeOutUp', + }, + }).then((result) => { + if (result.isConfirmed) { + copyRoomURL(); + } else if (result.isDenied) { + let message = { + email: '', + subject: 'Please join our MiroTalkSfu Video Chat Meeting', + body: 'Click to join: ' + RoomURL, + }; + shareRoomByEmail(message); + } + }); + makeRoomQR(); + } +} + +// #################################################### +// ROOM UTILITY +// #################################################### + +function makeRoomQR() { + let qr = new QRious({ + element: document.getElementById('qrRoom'), + value: RoomURL, + }); + qr.set({ + size: 128, + }); +} + +function copyRoomURL() { + let tmpInput = document.createElement('input'); + document.body.appendChild(tmpInput); + tmpInput.value = RoomURL; + tmpInput.select(); + document.execCommand('copy'); + document.body.removeChild(tmpInput); + userLog('info', 'Room URL copied to clipboard', 'top-end'); +} + +function shareRoomByEmail(message) { + let email = message.email; + let subject = message.subject; + let emailBody = message.body; + document.location = 'mailto:' + email + '?subject=' + subject + '&body=' + emailBody; +} + +// #################################################### +// JOIN TO ROOM +// #################################################### + +function joinRoom(peer_name, room_id) { + if (rc && rc.isConnected()) { + console.log('Already connected to a room'); + } else { + console.log('05 ----> join to Room ' + room_id); + rc = new RoomClient( + localMedia, + remoteVideos, + remoteAudios, + window.mediasoupClient, + socket, + room_id, + peer_name, + peer_geo, + peer_info, + isAudioAllowed, + isVideoAllowed, + isAudioOn, + isVideoOn, + roomIsReady, + ); + handleRoomClientEvents(); + } +} + +function roomIsReady() { + control.className = ''; + show(exitButton); + show(shareButton); + show(recButton); + show(startRecButton); + show(chatButton); + show(chatSendButton); + show(chatEmojiButton); + if (DetectRTC.isMobileDevice) { + show(swapCameraButton); + setChatSize(); + } else { + rc.makeDraggable(chatRoom, chatHeader); + show(startScreenButton); + } + if (DetectRTC.browser.name != 'Safari') { + document.onfullscreenchange = () => { + if (!document.fullscreenElement) rc.isDocumentOnFullScreen = false; + }; + show(fullScreenButton); + } + show(devicesButton); + if (isAudioAllowed) show(startAudioButton); + if (isVideoAllowed) show(startVideoButton); + show(videoMedia); + show(aboutButton); + handleButtons(); + handleSelects(); + handleInputs(); + startSessionTimer(); +} + +function hide(elem) { + elem.className = 'hidden'; +} + +function show(elem) { + elem.className = ''; +} + +// #################################################### +// SET CHAT MOBILE +// #################################################### + +function setChatSize() { + document.documentElement.style.setProperty('--msger-width', '99%'); + document.documentElement.style.setProperty('--msger-height', '99%'); +} + +// #################################################### +// SESSION TIMER +// #################################################### + +function startSessionTimer() { + sessionTime.style.display = 'inline'; + let callStartTime = Date.now(); + setInterval(function printTime() { + let callElapsedTime = Date.now() - callStartTime; + sessionTime.innerHTML = getTimeToString(callElapsedTime); + }, 1000); +} + +function getTimeToString(time) { + let diffInHrs = time / 3600000; + let hh = Math.floor(diffInHrs); + let diffInMin = (diffInHrs - hh) * 60; + let mm = Math.floor(diffInMin); + let diffInSec = (diffInMin - mm) * 60; + let ss = Math.floor(diffInSec); + let formattedHH = hh.toString().padStart(2, '0'); + let formattedMM = mm.toString().padStart(2, '0'); + let formattedSS = ss.toString().padStart(2, '0'); + return `${formattedHH}:${formattedMM}:${formattedSS}`; +} + +// #################################################### +// RECORDING TIMER +// #################################################### + +function secondsToHms(d) { + d = Number(d); + let h = Math.floor(d / 3600); + let m = Math.floor((d % 3600) / 60); + let s = Math.floor((d % 3600) % 60); + let hDisplay = h > 0 ? h + 'h' : ''; + let mDisplay = m > 0 ? m + 'm' : ''; + let sDisplay = s > 0 ? s + 's' : ''; + return hDisplay + ' ' + mDisplay + ' ' + sDisplay; +} + +function startRecordingTimer() { + recElapsedTime = 0; + recTimer = setInterval(function printTime() { + if (rc.isRecording()) { + recElapsedTime++; + recordingStatus.innerHTML = '🔴 REC ' + secondsToHms(recElapsedTime); + } + }, 1000); +} +function stopRecordingTimer() { + clearInterval(recTimer); +} + +// #################################################### +// HTML BUTTONS +// #################################################### + +function handleButtons() { + exitButton.onclick = () => { + rc.exit(); + }; + shareButton.onclick = () => { + shareRoom(true); + }; + devicesButton.onclick = () => { + rc.toggleDevices(); + }; + chatButton.onclick = () => { + rc.toggleChat(); + }; + chatCleanButton.onclick = () => { + rc.chatClean(); + }; + chatSaveButton.onclick = () => { + rc.chatSave(); + }; + chatCloseButton.onclick = () => { + rc.toggleChat(); + }; + chatSendButton.onclick = () => { + rc.sendMessage(); + }; + chatEmojiButton.onclick = () => { + rc.toggleChatEmoji(); + }; + fullScreenButton.onclick = () => { + rc.toggleFullScreen(); + }; + recButton.onclick = () => { + rc.toggleRecording(); + }; + startRecButton.onclick = () => { + rc.startRecording(); + }; + stopRecButton.onclick = () => { + rc.stopRecording(); + }; + pauseRecButton.onclick = () => { + rc.pauseRecording(); + }; + resumeRecButton.onclick = () => { + rc.resumeRecording(); + }; + swapCameraButton.onclick = () => { + rc.closeThenProduce(RoomClient.mediaType.video, null, true); + }; + startAudioButton.onclick = () => { + rc.produce(RoomClient.mediaType.audio, microphoneSelect.value); + // rc.resumeProducer(RoomClient.mediaType.audio); + }; + stopAudioButton.onclick = () => { + rc.closeProducer(RoomClient.mediaType.audio); + // rc.pauseProducer(RoomClient.mediaType.audio); + }; + startVideoButton.onclick = () => { + rc.produce(RoomClient.mediaType.video, videoSelect.value); + // rc.resumeProducer(RoomClient.mediaType.video); + }; + stopVideoButton.onclick = () => { + rc.closeProducer(RoomClient.mediaType.video); + // rc.pauseProducer(RoomClient.mediaType.video); + }; + startScreenButton.onclick = () => { + rc.produce(RoomClient.mediaType.screen); + }; + stopScreenButton.onclick = () => { + rc.closeProducer(RoomClient.mediaType.screen); + }; + aboutButton.onclick = () => { + showAbout(); + }; +} + +// #################################################### +// HTML SELECTS +// #################################################### + +function handleSelects() { + microphoneSelect.onchange = () => { + rc.closeThenProduce(RoomClient.mediaType.audio, microphoneSelect.value); + }; + speakerSelect.onchange = () => { + rc.attachSinkId(localMedia, speakerSelect.value); + }; + videoSelect.onchange = () => { + rc.closeThenProduce(RoomClient.mediaType.video, videoSelect.value); + }; +} + +// #################################################### +// HTML INPUTS +// #################################################### + +function handleInputs() { + chatMessage.onkeyup = (e) => { + if (e.keyCode === 13) { + e.preventDefault(); + chatSendButton.click(); + } + }; + rc.getId('chatEmoji').addEventListener('emoji-click', (e) => { + chatMessage.value += e.detail.emoji.unicode; + rc.toggleChatEmoji(); + }); +} + +// #################################################### +// ROOM CLIENT EVENT LISTNERS +// #################################################### + +function handleRoomClientEvents() { + rc.on(RoomClient.EVENTS.startRec, () => { + hide(startRecButton); + show(stopRecButton); + show(pauseRecButton); + startRecordingTimer(); + }); + rc.on(RoomClient.EVENTS.pauseRec, () => { + hide(pauseRecButton); + show(resumeRecButton); + }); + rc.on(RoomClient.EVENTS.resumeRec, () => { + hide(resumeRecButton); + show(pauseRecButton); + }); + rc.on(RoomClient.EVENTS.stopRec, () => { + hide(stopRecButton); + hide(pauseRecButton); + hide(resumeRecButton); + show(startRecButton); + stopRecordingTimer(); + }); + rc.on(RoomClient.EVENTS.startAudio, () => { + hide(startAudioButton); + show(stopAudioButton); + }); + rc.on(RoomClient.EVENTS.pauseAudio, () => { + console.log('Room Client pause audio'); + hide(stopAudioButton); + show(startAudioButton); + }); + rc.on(RoomClient.EVENTS.resumeAudio, () => { + console.log('Room Client resume audio'); + hide(startAudioButton); + show(stopAudioButton); + }); + rc.on(RoomClient.EVENTS.stopAudio, () => { + hide(stopAudioButton); + show(startAudioButton); + }); + rc.on(RoomClient.EVENTS.startVideo, () => { + hide(startVideoButton); + show(stopVideoButton); + }); + rc.on(RoomClient.EVENTS.pauseVideo, () => { + console.log('Room Client pause video'); + hide(stopVideoButton); + show(startVideoButton); + }); + rc.on(RoomClient.EVENTS.resumeVideo, () => { + console.log('Room Client resume video'); + hide(startVideoButton); + show(stopVideoButton); + }); + rc.on(RoomClient.EVENTS.stopVideo, () => { + hide(stopVideoButton); + show(startVideoButton); + }); + rc.on(RoomClient.EVENTS.startScreen, () => { + hide(startScreenButton); + show(stopScreenButton); + }); + rc.on(RoomClient.EVENTS.pauseScreen, () => { + console.log('Room Client pause screen'); + }); + rc.on(RoomClient.EVENTS.resumeScreen, () => { + console.log('Room Client resume screen'); + }); + rc.on(RoomClient.EVENTS.stopScreen, () => { + hide(stopScreenButton); + show(startScreenButton); + }); + rc.on(RoomClient.EVENTS.exitRoom, () => { + window.location.href = '/newroom'; + }); +} + +// #################################################### +// SHOW LOG +// #################################################### + +function userLog(icon, message, position) { + const Toast = Swal.mixin({ + background: swalBackground, + toast: true, + position: position, + showConfirmButton: false, + timer: 3000, + }); + Toast.fire({ + icon: icon, + title: message, + }); +} + +// #################################################### +// SOUND +// #################################################### + +async function sound(name) { + let sound = '../sounds/' + name + '.wav'; + let audioToPlay = new Audio(sound); + try { + await audioToPlay.play(); + } catch (err) { + return false; + } +} + +// #################################################### +// ABOUT +// #################################################### + +function showAbout() { + sound('open'); + + Swal.fire({ + background: swalBackground, + imageUrl: swalImageUrl, + position: 'center', + html: ` ++ Start your next video call with a single click. No download, plug-in or login + required. Just get straight to talking, messaging and sharing your screen. +
++ MiroTalk with SFU integrated Server. We engineered a platform with maximum video + quality lowest latency that makes your calls crystal clear. +
++ Share your screen, application window, present your documents, slides and + more. +
++ Having the webcam on, allows participants to make a deeper connection with + you. Up to 4k resolution. +
++ Echo cancellation and noise suppression that makes your audio crystal clear. +
++ Chat with others in meeting with integrated emoji picker to show you + feeling. +
++ Record your Screen, Video and Audio on Your browser Blobs. Save it for use + it in future or to share with others. +
++ Data stays between you and your participants. MiroTalk SFU don't collect or + share personal information. +
++ Each room has its own disposable URL. Just pick a room name and share your custom + URL. It's really that easy. +
+