Changeset View
Changeset View
Standalone View
Standalone View
src/resources/js/meet/app.js
import anchorme from 'anchorme' | import anchorme from 'anchorme' | ||||
import { library } from '@fortawesome/fontawesome-svg-core' | import { library } from '@fortawesome/fontawesome-svg-core' | ||||
import { OpenVidu } from 'openvidu-browser' | import { OpenVidu } from 'openvidu-browser' | ||||
class Roles { | |||||
static get SUBSCRIBER() { return 1 << 0; } | |||||
static get PUBLISHER() { return 1 << 1; } | |||||
static get MODERATOR() { return 1 << 2; } | |||||
static get SCREEN() { return 1 << 3; } | |||||
static get OWNER() { return 1 << 4; } | |||||
} | |||||
function Meet(container) | function Meet(container) | ||||
{ | { | ||||
let OV // OpenVidu object to initialize a session | let OV // OpenVidu object to initialize a session | ||||
let session // Session object where the user will connect | let session // Session object where the user will connect | ||||
let publisher // Publisher object which the user will publish | let publisher // Publisher object which the user will publish | ||||
let audioActive = false // True if the audio track of the publisher is active | let audioActive = false // True if the audio track of the publisher is active | ||||
let videoActive = false // True if the video track of the publisher is active | let videoActive = false // True if the video track of the publisher is active | ||||
let numOfVideos = 0 // Keeps track of the number of videos that are being shown | let numOfVideos = 0 // Keeps track of the number of videos that are being shown | ||||
let audioSource = '' // Currently selected microphone | let audioSource = '' // Currently selected microphone | ||||
let videoSource = '' // Currently selected camera | let videoSource = '' // Currently selected camera | ||||
let sessionData // Room session metadata | let sessionData // Room session metadata | ||||
let role // Current user role | |||||
let screenOV // OpenVidu object to initialize a screen sharing session | let screenOV // OpenVidu object to initialize a screen sharing session | ||||
let screenSession // Session object where the user will connect for screen sharing | let screenSession // Session object where the user will connect for screen sharing | ||||
let screenPublisher // Publisher object which the user will publish the screen sharing | let screenPublisher // Publisher object which the user will publish the screen sharing | ||||
let publisherDefaults = { | let publisherDefaults = { | ||||
publishAudio: true, // Whether to start publishing with your audio unmuted or not | publishAudio: true, // Whether to start publishing with your audio unmuted or not | ||||
publishVideo: true, // Whether to start publishing with your video enabled or not | publishVideo: true, // Whether to start publishing with your video enabled or not | ||||
Show All 36 Lines | function Meet(container) | ||||
this.setup = setup | this.setup = setup | ||||
this.setupSetAudioDevice = setupSetAudioDevice | this.setupSetAudioDevice = setupSetAudioDevice | ||||
this.setupSetVideoDevice = setupSetVideoDevice | this.setupSetVideoDevice = setupSetVideoDevice | ||||
this.switchAudio = switchAudio | this.switchAudio = switchAudio | ||||
this.switchScreen = switchScreen | this.switchScreen = switchScreen | ||||
this.switchVideo = switchVideo | this.switchVideo = switchVideo | ||||
this.updateSession = updateSession | this.updateSession = updateSession | ||||
/** | /** | ||||
* Join the room session | * Join the room session | ||||
* | * | ||||
* @param data Session metadata and event handlers (session, token, shareToken, nickname, | * @param data Session metadata and event handlers (session, token, shareToken, nickname, role, | ||||
* canPublish, chatElement, menuElement, onDestroy, onJoinRequest) | * chatElement, menuElement, onDestroy, onJoinRequest) | ||||
*/ | */ | ||||
function joinRoom(data) { | function joinRoom(data) { | ||||
resize(); | resize(); | ||||
volumeMeterStop() | volumeMeterStop() | ||||
data.params = { | data.params = { | ||||
nickname: data.nickname, // user nickname | nickname: data.nickname, // user nickname | ||||
// avatar: undefined // avatar image | // avatar: undefined // avatar image | ||||
} | } | ||||
// Create a container for subscribers | // Create a container for subscribers | ||||
if (!subscribersContainer) { | if (!subscribersContainer) { | ||||
subscribersContainer = $('<div id="meet-subscribers">').appendTo(container).get(0) | subscribersContainer = $('<div id="meet-subscribers">').appendTo(container).get(0) | ||||
} | } | ||||
sessionData = data | sessionData = data | ||||
// Init a session | // Init a session | ||||
session = OV.initSession() | session = OV.initSession() | ||||
// Handle connection creation events | // Handle connection creation events | ||||
session.on('connectionCreated', event => { | session.on('connectionCreated', event => { | ||||
// Ignore the current user connection | // Ignore the current user connection | ||||
if (event.connection.role) { | if (event.connection.role) { | ||||
role = event.connection.role | |||||
return | return | ||||
} | } | ||||
// This is the first event executed when a user joins in. | // This is the first event executed when a user joins in. | ||||
// We'll create the video wrapper here, which can be re-used | // We'll create the video wrapper here, which can be re-used | ||||
// in 'streamCreated' event handler. | // in 'streamCreated' event handler. | ||||
// Note: For a user with a subscriber role 'streamCreated' event | // Note: For a user with a subscriber role 'streamCreated' event | ||||
// is not being dispatched at all | // is not being dispatched at all | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | */ | ||||
// Handle signals from all participants | // Handle signals from all participants | ||||
session.on('signal', signalEventHandler) | session.on('signal', signalEventHandler) | ||||
// Connect with the token | // Connect with the token | ||||
session.connect(data.token, data.params) | session.connect(data.token, data.params) | ||||
.then(() => { | .then(() => { | ||||
let wrapper | let wrapper | ||||
let params = { self: true, canPublish: data.canPublish, audioActive, videoActive } | let params = { self: true, role: data.role, audioActive, videoActive } | ||||
params = Object.assign({}, data.params, params) | params = Object.assign({}, data.params, params) | ||||
publisher.on('videoElementCreated', event => { | publisher.on('videoElementCreated', event => { | ||||
$(event.element).prop({ | $(event.element).prop({ | ||||
muted: true, // Mute local video to avoid feedback | muted: true, // Mute local video to avoid feedback | ||||
disablePictureInPicture: true, // this does not work in Firefox | disablePictureInPicture: true, // this does not work in Firefox | ||||
tabindex: -1 | tabindex: -1 | ||||
}) | }) | ||||
resize() | resize() | ||||
}) | }) | ||||
wrapper = participantCreate(params) | wrapper = participantCreate(params) | ||||
if (data.canPublish) { | if (data.role & Roles.PUBLISHER) { | ||||
publisher.createVideoElement(wrapper, 'PREPEND') | publisher.createVideoElement(wrapper, 'PREPEND') | ||||
session.publish(publisher) | session.publish(publisher) | ||||
} | } | ||||
resize() | resize() | ||||
sessionData.wrapper = wrapper | sessionData.wrapper = wrapper | ||||
}) | }) | ||||
.catch(error => { | .catch(error => { | ||||
▲ Show 20 Lines • Show All 441 Lines • ▼ Show 20 Lines | function nicknameUpdate(nickname, connectionId) { | ||||
if (elem.data('id') == connectionId) { | if (elem.data('id') == connectionId) { | ||||
elem.find('.nickname').text(nickname || '') | elem.find('.nickname').text(nickname || '') | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Create a participant element in the matrix. Depending on the `canPublish` | * Create a participant element in the matrix. Depending on the connection role | ||||
* parameter it will be a video element wrapper inside the matrix or a simple | * parameter it will be a video element wrapper inside the matrix or a simple | ||||
* tag-like element on the subscribers list. | * tag-like element on the subscribers list. | ||||
* | * | ||||
* @param params Connection metadata/params | * @param params Connection metadata/params | ||||
* | * | ||||
* @return The element | * @return The element | ||||
*/ | */ | ||||
function participantCreate(params) { | function participantCreate(params) { | ||||
if (params.canPublish) { | if (params.role & Roles.PUBLISHER || params.role & Roles.SCREEN) { | ||||
return publisherCreate(params) | return publisherCreate(params) | ||||
} | } | ||||
return subscriberCreate(params) | return subscriberCreate(params) | ||||
} | } | ||||
/** | /** | ||||
* Create a <video> element wrapper with controls | * Create a <video> element wrapper with controls | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | function participantUpdate(wrapper, params) { | ||||
if ('nickname' in params) { | if ('nickname' in params) { | ||||
$element.find('.meet-nickname > .content').text(params.nickname) | $element.find('.meet-nickname > .content').text(params.nickname) | ||||
} | } | ||||
if (params.self) { | if (params.self) { | ||||
$element.addClass('self') | $element.addClass('self') | ||||
} | } | ||||
if (role == 'MODERATOR') { | if (sessionData.role & Roles.MODERATOR) { | ||||
$element.addClass('moderated') | $element.addClass('moderated') | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Create a tag-like element for a subscriber participant | * Create a tag-like element for a subscriber participant | ||||
* | * | ||||
* @param params Connection metadata/params | * @param params Connection metadata/params | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | function nicknameWidget(params) { | ||||
$(editable).on('blur', editableUpdate) | $(editable).on('blur', editableUpdate) | ||||
.on('keydown', e => { | .on('keydown', e => { | ||||
// Enter or Esc | // Enter or Esc | ||||
if (e.keyCode == 13 || e.keyCode == 27) { | if (e.keyCode == 13 || e.keyCode == 27) { | ||||
editableUpdate() | editableUpdate() | ||||
return false | return false | ||||
} | } | ||||
}) | }) | ||||
} else if (role == 'MODERATOR') { | } else if (sessionData.role & Roles.MODERATOR) { | ||||
nickname.attr({title: 'Options', 'data-toggle': 'dropdown'}) | nickname.attr({title: 'Options', 'data-toggle': 'dropdown'}) | ||||
.dropdown({boundary: container}) | .dropdown({boundary: container}) | ||||
element.find('.action-dismiss').on('click', e => { | element.find('.action-dismiss').on('click', e => { | ||||
if (sessionData.onDismiss) { | if (sessionData.onDismiss) { | ||||
sessionData.onDismiss(params.connId) | sessionData.onDismiss(params.connId) | ||||
} | } | ||||
}) | }) | ||||
▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | function connectionData(connection) { | ||||
// creating a token/connection, and client-side when joining the session) | // creating a token/connection, and client-side when joining the session) | ||||
// OpenVidu is unable to merge these two objects into one, for it it is only | // OpenVidu is unable to merge these two objects into one, for it it is only | ||||
// two strings, so it puts a "%/%" separator in between, we'll replace it with comma | // two strings, so it puts a "%/%" separator in between, we'll replace it with comma | ||||
// to get one parseable json object | // to get one parseable json object | ||||
return JSON.parse(connection.data.replace('}%/%{', ',')) | return JSON.parse(connection.data.replace('}%/%{', ',')) | ||||
} | } | ||||
} | } | ||||
export default Meet | export { Meet, Roles } |