2020-10-23 16:16:30 +02:00
|
|
|
import {JITSI_URL} from "../Enum/EnvironmentVariable";
|
2020-10-23 17:00:56 +02:00
|
|
|
import {mediaManager} from "./MediaManager";
|
2020-10-27 16:59:12 +01:00
|
|
|
import {coWebsiteManager} from "./CoWebsiteManager";
|
2020-10-23 16:16:30 +02:00
|
|
|
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
|
|
|
2021-02-17 18:49:55 +01:00
|
|
|
interface jitsiConfigInterface {
|
|
|
|
startWithAudioMuted: boolean
|
|
|
|
startWithVideoMuted: boolean
|
|
|
|
prejoinPageEnabled: boolean
|
|
|
|
}
|
|
|
|
|
|
|
|
const getDefaultConfig = () : jitsiConfigInterface => {
|
2021-02-16 18:25:23 +01:00
|
|
|
return {
|
|
|
|
startWithAudioMuted: !mediaManager.constraintsMedia.audio,
|
|
|
|
startWithVideoMuted: mediaManager.constraintsMedia.video === false,
|
|
|
|
prejoinPageEnabled: false
|
|
|
|
}
|
2021-02-09 14:17:48 +01:00
|
|
|
}
|
|
|
|
|
2021-02-17 18:49:55 +01:00
|
|
|
const mergeConfig = (config?: object) => {
|
|
|
|
const currentDefaultConfig = getDefaultConfig();
|
|
|
|
if(!config){
|
|
|
|
return currentDefaultConfig;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
startWithAudioMuted: (config as jitsiConfigInterface).startWithAudioMuted ? true : currentDefaultConfig.startWithAudioMuted,
|
|
|
|
startWithVideoMuted: (config as jitsiConfigInterface).startWithVideoMuted ? true : currentDefaultConfig.startWithVideoMuted,
|
|
|
|
prejoinPageEnabled: (config as jitsiConfigInterface).prejoinPageEnabled ? true : currentDefaultConfig.prejoinPageEnabled
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:31:49 +01:00
|
|
|
const defaultInterfaceConfig = {
|
2020-10-23 16:16:30 +02:00
|
|
|
SHOW_CHROME_EXTENSION_BANNER: false,
|
|
|
|
MOBILE_APP_PROMO: false,
|
|
|
|
|
|
|
|
HIDE_INVITE_MORE_HEADER: true,
|
2021-02-10 11:13:47 +01:00
|
|
|
DISABLE_JOIN_LEAVE_NOTIFICATIONS: true,
|
2021-02-10 11:20:05 +01:00
|
|
|
DISABLE_VIDEO_BACKGROUND: true,
|
2020-10-23 16:16:30 +02:00
|
|
|
|
|
|
|
// Note: hiding brand does not seem to work, we probably need to put this on the server side.
|
|
|
|
SHOW_BRAND_WATERMARK: false,
|
|
|
|
SHOW_JITSI_WATERMARK: false,
|
|
|
|
SHOW_POWERED_BY: false,
|
|
|
|
SHOW_PROMOTIONAL_CLOSE_PAGE: false,
|
|
|
|
SHOW_WATERMARK_FOR_GUESTS: false,
|
|
|
|
|
|
|
|
TOOLBAR_BUTTONS: [
|
|
|
|
'microphone', 'camera', 'closedcaptions', 'desktop', /*'embedmeeting',*/ 'fullscreen',
|
|
|
|
'fodeviceselection', 'hangup', 'profile', 'chat', 'recording',
|
|
|
|
'livestreaming', 'etherpad', 'sharedvideo', 'settings', 'raisehand',
|
|
|
|
'videoquality', 'filmstrip', /*'invite',*/ 'feedback', 'stats', 'shortcuts',
|
|
|
|
'tileview', 'videobackgroundblur', 'download', 'help', 'mute-everyone', /*'security'*/
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
2021-02-10 11:40:59 +01:00
|
|
|
const slugify = (...args: (string | number)[]): string => {
|
|
|
|
const value = args.join(' ')
|
|
|
|
|
|
|
|
return value
|
|
|
|
.normalize('NFD') // split an accented letter in the base letter and the accent
|
|
|
|
.replace(/[\u0300-\u036f]/g, '') // remove all previously split accents
|
|
|
|
.toLowerCase()
|
|
|
|
.trim()
|
|
|
|
.replace(/[^a-z0-9 ]/g, '') // remove all chars not letters, numbers and spaces (to be replaced)
|
|
|
|
.replace(/\s+/g, '-') // separator
|
|
|
|
}
|
|
|
|
|
2020-10-23 16:16:30 +02:00
|
|
|
class JitsiFactory {
|
|
|
|
private jitsiApi: any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
2020-10-26 15:07:34 +01:00
|
|
|
private audioCallback = this.onAudioChange.bind(this);
|
|
|
|
private videoCallback = this.onVideoChange.bind(this);
|
2021-02-17 19:21:37 +01:00
|
|
|
private previousConfigMeet? : jitsiConfigInterface;
|
2021-02-10 11:13:47 +01:00
|
|
|
|
2021-02-10 11:40:59 +01:00
|
|
|
/**
|
|
|
|
* Slugifies the room name and prepends the room name with the instance
|
|
|
|
*/
|
|
|
|
public getRoomName(roomName: string, instance: string): string {
|
|
|
|
return slugify(instance.replace('/', '-') + "-" + roomName);
|
|
|
|
}
|
|
|
|
|
2021-02-09 20:31:49 +01:00
|
|
|
public start(roomName: string, playerName:string, jwt?: string, config?: object, interfaceConfig?: object): void {
|
2021-02-17 19:21:37 +01:00
|
|
|
//save previous config
|
|
|
|
this.previousConfigMeet = getDefaultConfig();
|
|
|
|
|
2020-10-27 16:59:12 +01:00
|
|
|
coWebsiteManager.insertCoWebsite((cowebsiteDiv => {
|
2021-02-15 10:36:56 +01:00
|
|
|
// Jitsi meet external API maintains some data in local storage
|
|
|
|
// which is sent via the appData URL parameter when joining a
|
|
|
|
// conference. Problem is that this data grows indefinitely. Thus
|
|
|
|
// after some time the URLs get so huge that loading the iframe
|
|
|
|
// becomes slow and eventually breaks completely. Thus lets just
|
|
|
|
// clear jitsi local storage before starting a new conference.
|
|
|
|
window.localStorage.removeItem("jitsiLocalStorage");
|
|
|
|
|
2020-10-23 16:16:30 +02:00
|
|
|
const domain = JITSI_URL;
|
2020-10-27 16:59:12 +01:00
|
|
|
const options: any = { // eslint-disable-line @typescript-eslint/no-explicit-any
|
2020-10-23 16:16:30 +02:00
|
|
|
roomName: roomName,
|
|
|
|
jwt: jwt,
|
|
|
|
width: "100%",
|
|
|
|
height: "100%",
|
|
|
|
parentNode: cowebsiteDiv,
|
2021-02-17 18:49:55 +01:00
|
|
|
configOverwrite: mergeConfig(config),
|
2021-02-09 20:31:49 +01:00
|
|
|
interfaceConfigOverwrite: {...defaultInterfaceConfig, ...interfaceConfig}
|
2020-10-23 16:16:30 +02:00
|
|
|
};
|
|
|
|
if (!options.jwt) {
|
|
|
|
delete options.jwt;
|
|
|
|
}
|
2021-02-10 11:13:47 +01:00
|
|
|
|
2020-11-13 18:08:43 +01:00
|
|
|
return new Promise((resolve, reject) => {
|
2020-10-27 16:59:12 +01:00
|
|
|
options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations.
|
2020-11-16 16:15:21 +01:00
|
|
|
setTimeout(() => resolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
2020-10-27 16:59:12 +01:00
|
|
|
this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
|
|
|
|
this.jitsiApi.executeCommand('displayName', playerName);
|
2020-10-26 15:07:34 +01:00
|
|
|
|
2020-10-27 16:59:12 +01:00
|
|
|
this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
|
|
|
|
this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
|
|
|
|
});
|
2020-10-23 16:16:30 +02:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2020-10-27 16:59:12 +01:00
|
|
|
public async stop(): Promise<void> {
|
2020-10-31 14:04:55 +01:00
|
|
|
if(!this.jitsiApi){
|
|
|
|
return;
|
|
|
|
}
|
2020-10-27 16:59:12 +01:00
|
|
|
await coWebsiteManager.closeCoWebsite();
|
2020-10-26 15:07:34 +01:00
|
|
|
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
|
|
|
|
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
|
2020-10-23 16:16:30 +02:00
|
|
|
this.jitsiApi?.dispose();
|
2021-02-17 19:21:37 +01:00
|
|
|
|
|
|
|
//restore previous config
|
|
|
|
if(this.previousConfigMeet?.startWithAudioMuted){
|
|
|
|
mediaManager.disableMicrophone();
|
|
|
|
}else{
|
|
|
|
mediaManager.enableMicrophone();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(this.previousConfigMeet?.startWithVideoMuted){
|
|
|
|
mediaManager.disableCamera();
|
|
|
|
}else{
|
|
|
|
mediaManager.enableCamera();
|
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
}
|
2020-10-26 15:07:34 +01:00
|
|
|
|
|
|
|
private onAudioChange({muted}: {muted: boolean}): void {
|
|
|
|
if (muted && mediaManager.constraintsMedia.audio === true) {
|
|
|
|
mediaManager.disableMicrophone();
|
|
|
|
} else if(!muted && mediaManager.constraintsMedia.audio === false) {
|
|
|
|
mediaManager.enableMicrophone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private onVideoChange({muted}: {muted: boolean}): void {
|
|
|
|
if (muted && mediaManager.constraintsMedia.video !== false) {
|
|
|
|
mediaManager.disableCamera();
|
|
|
|
} else if(!muted && mediaManager.constraintsMedia.video === false) {
|
|
|
|
mediaManager.enableCamera();
|
|
|
|
}
|
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
}
|
|
|
|
|
2021-02-10 11:13:47 +01:00
|
|
|
export const jitsiFactory = new JitsiFactory();
|