var LivekitClient = window.LivekitClient; var room; var myRoomName; var token; var nickname; /* OPENVIDU METHODS */ function joinRoom() { document.getElementById('join-btn').disabled = true; document.getElementById('join-btn').innerHTML = 'Joining...'; const myParticipantName = $('#myParticipantName').val(); const myRoomName = $('#myRoomName').val(); room = new LivekitClient.Room(); room.on( LivekitClient.RoomEvent.TrackSubscribed, (track, publication, participant) => { const element = track.attach(); element.id = track.sid; element.className = 'removable'; document.getElementById('video-container').appendChild(element); if (track.kind === 'video') { var participantNickname; try { participantNickname = JSON.parse(participant.metadata).nickname; } catch (error) { console.warn('Error parsing participant metadata: ' + error); } appendUserData(element, participant.identity, participantNickname); } } ); // On every new Track destroyed... room.on( LivekitClient.RoomEvent.TrackUnsubscribed, (track, publication, participant) => { track.detach(); document.getElementById(track.sid)?.remove(); if (track.kind === 'video') { removeUserData(participant); } } ); getToken(myRoomName, myParticipantName).then((token) => { const livekitUrl = getLivekitUrlFromMetadata(token); room .connect(livekitUrl, token) .then(async () => { var participantName = $('#user').val(); $('#room-title').text(myRoomName); $('#join').hide(); $('#room').show(); const canPublish = room.localParticipant.permissions.canPublish; if (canPublish) { const [microphonePublication, cameraPublication] = await Promise.all([ room.localParticipant.setMicrophoneEnabled(true), room.localParticipant.setCameraEnabled(true), ]); const element = cameraPublication.track.attach(); element.className = 'removable'; document.getElementById('video-container').appendChild(element); initMainVideo(element, myParticipantName, nickname); appendUserData(element, myParticipantName, nickname); } else { initMainVideoThumbnail(); } }) .catch((error) => { console.warn( 'There was an error connecting to the room:', error.code, error.message ); enableBtn(); }); }); return false; } function leaveRoom() { room.disconnect(); room = null; // Removing all HTML elements with the user's nicknames cleanRoomView(); $('#join').show(); $('#room').hide(); enableBtn(); } /* OPENVIDU METHODS */ function enableBtn() { document.getElementById('join-btn').disabled = false; document.getElementById('join-btn').innerHTML = 'Join!'; } /* APPLICATION REST METHODS */ function logIn() { nickname = $('#user').val(); var pass = $('#pass').val(); httpPostRequest( 'login', { user: nickname, pass }, 'Login WRONG', (response) => { $('#name-user').text(nickname); $('#not-logged').hide(); $('#logged').show(); // Random myParticipantName and room $('#myRoomName').val('Room ' + Math.floor(Math.random() * 10)); $('#myParticipantName').val( 'Participant ' + Math.floor(Math.random() * 100) ); } ); } function logOut() { httpPostRequest('logout', {}, 'Logout WRONG', (response) => { $('#not-logged').show(); $('#logged').hide(); }); enableBtn(); } function getToken(roomName, participantName) { return new Promise((resolve, reject) => { // Video-call chosen by the user httpPostRequest( 'token', { roomName, participantName }, 'Error generating token', (response) => resolve(response.token) ); }); } async function httpPostRequest(url, body, errorMsg, successCallback) { try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body), }); if (response.ok) { const data = await response.json(); successCallback(data); } else { console.warn(errorMsg); console.warn('Error: ' + response.statusText); } } catch (error) { console.error(error); } } /* APPLICATION REST METHODS */ /* APPLICATION BROWSER METHODS */ window.onbeforeunload = () => { if (room) { leaveRoom(); } logOut(); }; function getLivekitUrlFromMetadata(token) { if (!token) throw new Error('Trying to get metadata from an empty token'); try { const base64Url = token.split('.')[1]; const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); const jsonPayload = decodeURIComponent( window .atob(base64) .split('') .map((c) => { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }) .join('') ); const payload = JSON.parse(jsonPayload); if (!payload?.metadata) throw new Error('Token does not contain metadata'); const metadata = JSON.parse(payload.metadata); return metadata.livekitUrl; } catch (error) { throw new Error('Error decoding and parsing token: ' + error); } } function appendUserData(videoElement, participantName, nickname) { var dataNode = document.createElement('div'); dataNode.className = 'removable'; dataNode.id = 'data-' + participantName; dataNode.innerHTML = `
${nickname}
${participantName}
`; videoElement.parentNode.insertBefore(dataNode, videoElement.nextSibling); addClickListener(videoElement, participantName); } function removeUserData(participant) { var dataNode = document.getElementById('data-' + participant.identity); dataNode?.parentNode.removeChild(dataNode); } function removeAllUserData() { var elementsToRemove = document.getElementsByClassName('removable'); while (elementsToRemove[0]) { elementsToRemove[0].parentNode.removeChild(elementsToRemove[0]); } } function cleanMainVideo() { $('#main-video video').get(0).srcObject = null; $('#main-video p').each(function () { $(this).html(''); }); } function addClickListener(videoElement, clientData, serverData) { videoElement.addEventListener('click', function () { var mainVideo = $('#main-video video').get(0); if (mainVideo.srcObject !== videoElement.srcObject) { $('#main-video').fadeOut('fast', () => { $('#main-video p.nickname').html(clientData); $('#main-video p.participantName').html(serverData); mainVideo.srcObject = videoElement.srcObject; $('#main-video').fadeIn('fast'); }); } }); } function initMainVideo(videoElement, participantName, nickname) { $('#main-video video').get(0).srcObject = videoElement.srcObject; $('#main-video p.nickname').html(nickname); $('#main-video p.participantName').html(participantName); } function initMainVideoThumbnail() { $('#main-video video').css( 'background', "url('images/subscriber-msg.jpg') round" ); } function cleanRoomView() { removeAllUserData(); cleanMainVideo(); $('#main-video video').css('background', ''); } /* APPLICATION BROWSER METHODS */