2018-05-03 16:49:33 +02:00

312 lines
8.6 KiB
JavaScript

var OV; // OpenVidu object to initialize a session
var session; // Session object where the user will connect
var publisher; // Publisher object which the user will publish
var sessionId; // Unique identifier of the session
var audioEnabled = true; // True if the audio track of publisher is active
var videoEnabled = true; // True if the video track of publisher is active
var numOfVideos = 0; // Keeps track of the number of videos that are being shown
// Check if the URL already has a room
window.addEventListener('load', function () {
sessionId = window.location.hash.slice(1); // For 'https://myurl/#roomId', sessionId would be 'roomId'
if (sessionId) {
// The URL has a session id. Join the room right away
console.log("Joining to room " + sessionId);
showSessionHideJoin();
joinRoom();
} else {
// The URL has not a session id. Show welcome page
showJoinHideSession();
}
});
// Disconnect participant on browser's window closed
window.addEventListener('beforeunload', function () {
if (session) session.disconnect();
});
function joinRoom() {
if (!sessionId) {
// If the user is joining to a new room
sessionId = randomString();
}
// --- 1) Get an OpenVidu object and init a session ---
OV = new OpenVidu();
session = OV.initSession();
// --- 2) Specify the actions when events take place ---
// On every new Stream received...
session.on('streamCreated', function (event) {
// Subscribe to the Stream to receive it. HTML video will be appended to element with 'subscriber' id
var subscriber = session.subscribe(event.stream, 'videos');
// When the new video is added to DOM, update the page layout to fit one more participant
subscriber.on('videoElementCreated', function (event) {
numOfVideos++;
updateLayout();
});
});
// On every new Stream destroyed...
session.on('streamDestroyed', function (event) {
// Update the page layout
numOfVideos--;
updateLayout();
});
// --- 3) Connect to the session with a valid user token ---
// 'getToken' method is simulating what your server-side should do.
// 'token' parameter should be retrieved and returned by your own backend
getToken().then(token => {
// Connect with the token
session.connect(token)
.then(() => {
// --- 4) Get your own camera stream with the desired properties ---
publisher = OV.initPublisher('publisher', {
audioSource: undefined, // The source of audio. If undefined default audio input
videoSource: undefined, // The source of video. If undefined default video input
publishAudio: true, // Whether you want to start the publishing with your audio unmuted or muted
publishVideo: true, // Whether you want to start the publishing with your video enabled or disabled
resolution: '640x480', // The resolution of your video
frameRate: 30, // The frame rate of your video
insertMode: 'APPEND', // How the video will be inserted in the target element 'video-container'
mirror: true // Whether to mirror your local video or not
});
publisher.on('videoElementCreated', function (event) {
// When your own video is added to DOM, update the page layout to fit it
numOfVideos++;
updateLayout();
$(event.element).prop('muted', true); // Mute local video
});
// --- 5) Publish your stream ---
session.publish(publisher);
})
.catch(error => {
console.log('There was an error connecting to the session:', error.code, error.message);
});
// Update the URL shown in the browser's navigation bar to show the session id
var pathname = (location.pathname.slice(-1) === "/" ? location.pathname : location.pathname + "/");
window.history.pushState("", "", pathname + '#' + sessionId);
// Auxiliary methods to show the session's view
showSessionHideJoin();
initializeSessionView();
});
}
function leaveRoom() {
// --- 6) Leave the session by calling 'disconnect' method over the Session object ---
session.disconnect();
// Back to welcome page
window.location.href = window.location.origin + window.location.pathname;
}
/* AUXILIARY MEHTODS */
function muteAudio() {
audioEnabled = !audioEnabled;
publisher.publishAudio(audioEnabled);
if (!audioEnabled) {
$('#mute-audio').removeClass('btn-primary');
$('#mute-audio').addClass('btn-default');
} else {
$('#mute-audio').addClass('btn-primary');
$('#mute-audio').removeClass('btn-default');
}
}
function muteVideo() {
videoEnabled = !videoEnabled;
publisher.publishVideo(videoEnabled);
if (!videoEnabled) {
$('#mute-video').removeClass('btn-primary');
$('#mute-video').addClass('btn-default');
} else {
$('#mute-video').addClass('btn-primary');
$('#mute-video').removeClass('btn-default');
}
}
function randomString() {
return Math.random().toString(36).slice(2);
}
// 'Session' page
function showSessionHideJoin() {
$('#nav-join').hide();
$('#nav-session').show();
$('#join').hide();
$('#session').show();
$('footer').hide();
$('#main-container').removeClass('container');
}
// 'Join' page
function showJoinHideSession() {
$('#nav-join').show();
$('#nav-session').hide();
$('#join').show();
$('#session').hide();
$('footer').show();
$('#main-container').addClass('container');
}
// Prepare HTML dynamic elements (URL clipboard input)
function initializeSessionView() {
// Tooltips
$('[data-toggle="tooltip"]').tooltip();
// Input clipboard
$('#copy-input').val(window.location.href);
$('#copy-button').bind('click', function () {
var input = document.getElementById('copy-input');
input.focus();
input.setSelectionRange(0, input.value.length);
try {
var success = document.execCommand('copy');
if (success) {
$('#copy-button').trigger('copied', ['Copied!']);
} else {
$('#copy-button').trigger('copied', ['Copy with Ctrl-c']);
}
} catch (err) {
$('#copy-button').trigger('copied', ['Copy with Ctrl-c']);
}
});
// Handler for updating the tooltip message.
$('#copy-button').bind('copied', function (event, message) {
$(this).attr('title', message)
.tooltip('fixTitle')
.tooltip('show')
.attr('title', "Copy to Clipboard")
.tooltip('fixTitle');
});
}
// Dynamic layout adjustemnt depending on number of videos
function updateLayout() {
console.warn('There are now ' + numOfVideos + ' videos');
var publisherDiv = $('#publisher');
var publisherVideo = $("#publisher video");
var subscriberVideos = $('#videos > video');
publisherDiv.removeClass();
publisherVideo.removeClass();
subscriberVideos.removeClass();
switch (numOfVideos) {
case 1:
publisherVideo.addClass('video1');
break;
case 2:
publisherDiv.addClass('video2');
subscriberVideos.addClass('video2');
break;
case 3:
publisherDiv.addClass('video3');
subscriberVideos.addClass('video3');
break;
case 4:
publisherDiv.addClass('video4');
publisherVideo.addClass('video4');
subscriberVideos.addClass('video4');
break;
default:
publisherDiv.addClass('videoMore');
publisherVideo.addClass('videoMore');
subscriberVideos.addClass('videoMore');
break;
}
}
/**
* --------------------------
* SERVER-SIDE RESPONSABILITY
* --------------------------
* These methods retrieve the mandatory user token from OpenVidu Server.
* This behaviour MUST BE IN YOUR SERVER-SIDE IN PRODUCTION (by using
* the API REST, openvidu-java-client or openvidu-node-client):
* 1) POST /api/sessions
* 2) POST /api/tokens
* 3) The value returned by /api/tokens must be consumed in Session.connect() method
*/
function getToken() {
return new Promise(async function (resolve) {
// POST /api/sessions
await apiSessions();
// POST /api/tokens
let t = await apiTokens();
// Return the user token
resolve(t);
});
}
function apiSessions() {
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: "https://" + location.hostname + ":4443/api/sessions",
data: JSON.stringify({ customSessionId: sessionId }),
headers: {
"Authorization": "Basic " + btoa("OPENVIDUAPP:MY_SECRET"),
"Content-Type": "application/json"
},
success: (response) => {
resolve(response.id)
},
error: (error) => {
if (error.status === 409) {
resolve(sessionId);
} else {
reject(error)
}
}
});
});
}
function apiTokens() {
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: "https://" + location.hostname + ":4443/api/tokens",
data: JSON.stringify({ session: sessionId }),
headers: {
"Authorization": "Basic " + btoa("OPENVIDUAPP:MY_SECRET"),
"Content-Type": "application/json"
},
success: (response) => {
resolve(response.id)
},
error: (error) => { reject(error) }
});
});
}