2020-08-13 18:21:48 +02:00
|
|
|
import {DivImportance, layoutManager} from "./LayoutManager";
|
2020-08-21 22:53:17 +02:00
|
|
|
import {HtmlUtils} from "./HtmlUtils";
|
2020-12-04 11:30:35 +01:00
|
|
|
import {discussionManager, SendMessageCallback} from "./DiscussionManager";
|
2020-11-10 12:38:32 +01:00
|
|
|
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
2021-03-30 22:38:44 +02:00
|
|
|
import {localUserStore} from "../Connexion/LocalUserStore";
|
2021-02-02 18:19:51 +01:00
|
|
|
import {UserSimplePeerInterface} from "./SimplePeer";
|
2020-10-23 16:16:30 +02:00
|
|
|
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
2020-08-13 18:21:48 +02:00
|
|
|
|
2020-11-27 16:24:07 +01:00
|
|
|
let videoConstraint: boolean|MediaTrackConstraints = {
|
|
|
|
width: { min: 640, ideal: 1280, max: 1920 },
|
|
|
|
height: { min: 400, ideal: 720 },
|
2021-03-30 22:38:44 +02:00
|
|
|
frameRate: { ideal: localUserStore.getVideoQualityValue() },
|
2020-11-27 16:24:07 +01:00
|
|
|
facingMode: "user",
|
|
|
|
resizeMode: 'crop-and-scale',
|
|
|
|
aspectRatio: 1.777777778
|
2020-05-03 14:29:45 +02:00
|
|
|
};
|
2020-06-23 14:56:57 +02:00
|
|
|
|
2020-08-31 15:21:05 +02:00
|
|
|
export type UpdatedLocalStreamCallback = (media: MediaStream|null) => void;
|
|
|
|
export type StartScreenSharingCallback = (media: MediaStream) => void;
|
|
|
|
export type StopScreenSharingCallback = (media: MediaStream) => void;
|
2020-10-13 19:56:42 +02:00
|
|
|
export type ReportCallback = (message: string) => void;
|
2021-01-29 21:09:10 +01:00
|
|
|
export type ShowReportCallBack = (userId: string, userName: string|undefined) => void;
|
2020-06-23 14:56:57 +02:00
|
|
|
|
2020-06-23 12:24:36 +02:00
|
|
|
// TODO: Split MediaManager in 2 classes: MediaManagerUI (in charge of HTML) and MediaManager (singleton in charge of the camera only)
|
|
|
|
export class MediaManager {
|
2020-06-03 11:55:31 +02:00
|
|
|
localStream: MediaStream|null = null;
|
2020-06-06 17:03:10 +02:00
|
|
|
localScreenCapture: MediaStream|null = null;
|
2020-06-10 12:15:25 +02:00
|
|
|
private remoteVideo: Map<string, HTMLVideoElement> = new Map<string, HTMLVideoElement>();
|
2020-06-03 11:55:31 +02:00
|
|
|
myCamVideo: HTMLVideoElement;
|
2020-06-10 12:15:25 +02:00
|
|
|
cinemaClose: HTMLImageElement;
|
|
|
|
cinema: HTMLImageElement;
|
2020-06-06 17:03:10 +02:00
|
|
|
monitorClose: HTMLImageElement;
|
|
|
|
monitor: HTMLImageElement;
|
2020-06-10 12:15:25 +02:00
|
|
|
microphoneClose: HTMLImageElement;
|
|
|
|
microphone: HTMLImageElement;
|
2020-06-03 11:55:31 +02:00
|
|
|
webrtcInAudio: HTMLAudioElement;
|
2020-12-11 15:35:13 +01:00
|
|
|
private webrtcOutAudio: HTMLAudioElement;
|
2020-06-10 12:15:25 +02:00
|
|
|
constraintsMedia : MediaStreamConstraints = {
|
2020-05-03 14:29:45 +02:00
|
|
|
audio: true,
|
|
|
|
video: videoConstraint
|
|
|
|
};
|
2020-06-23 14:56:57 +02:00
|
|
|
updatedLocalStreamCallBacks : Set<UpdatedLocalStreamCallback> = new Set<UpdatedLocalStreamCallback>();
|
2020-08-21 22:53:17 +02:00
|
|
|
startScreenSharingCallBacks : Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
|
|
|
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
2021-01-29 21:09:10 +01:00
|
|
|
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
2020-08-22 15:26:40 +02:00
|
|
|
private microphoneBtn: HTMLDivElement;
|
|
|
|
private cinemaBtn: HTMLDivElement;
|
|
|
|
private monitorBtn: HTMLDivElement;
|
2020-06-08 09:20:36 +02:00
|
|
|
|
2020-10-24 14:13:23 +02:00
|
|
|
private previousConstraint : MediaStreamConstraints;
|
2020-10-26 22:39:52 +01:00
|
|
|
private focused : boolean = true;
|
|
|
|
|
|
|
|
private lastUpdateScene : Date = new Date();
|
|
|
|
private setTimeOutlastUpdateScene? : NodeJS.Timeout;
|
2020-10-24 14:13:23 +02:00
|
|
|
|
2020-11-10 14:03:29 +01:00
|
|
|
private hasCamera = true;
|
|
|
|
|
2020-11-17 18:03:44 +01:00
|
|
|
private triggerCloseJistiFrame : Map<String, Function> = new Map<String, Function>();
|
|
|
|
|
2020-08-18 00:12:38 +02:00
|
|
|
constructor() {
|
2020-04-19 19:32:38 +02:00
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.myCamVideo = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('myCamVideo');
|
|
|
|
this.webrtcInAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audio-webrtc-in');
|
2020-12-11 15:35:13 +01:00
|
|
|
this.webrtcOutAudio = HtmlUtils.getElementByIdOrFail<HTMLAudioElement>('audio-webrtc-out');
|
2020-05-14 20:39:30 +02:00
|
|
|
this.webrtcInAudio.volume = 0.2;
|
2020-12-11 15:35:13 +01:00
|
|
|
this.webrtcOutAudio.volume = 0.2;
|
2020-04-26 20:55:20 +02:00
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.microphoneBtn = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('btn-micro');
|
|
|
|
this.microphoneClose = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('microphone-close');
|
2020-05-03 17:19:42 +02:00
|
|
|
this.microphoneClose.style.display = "none";
|
2020-06-10 12:15:25 +02:00
|
|
|
this.microphoneClose.addEventListener('click', (e: MouseEvent) => {
|
2020-04-19 19:32:38 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.enableMicrophone();
|
2020-04-19 19:32:38 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
2020-10-25 19:38:00 +01:00
|
|
|
this.microphone = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('microphone');
|
2020-06-10 12:15:25 +02:00
|
|
|
this.microphone.addEventListener('click', (e: MouseEvent) => {
|
2020-04-19 19:32:38 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.disableMicrophone();
|
2020-04-19 19:32:38 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.cinemaBtn = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('btn-video');
|
|
|
|
this.cinemaClose = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('cinema-close');
|
2020-05-03 17:19:42 +02:00
|
|
|
this.cinemaClose.style.display = "none";
|
2020-06-10 12:15:25 +02:00
|
|
|
this.cinemaClose.addEventListener('click', (e: MouseEvent) => {
|
2020-04-19 19:32:38 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.enableCamera();
|
2020-04-19 19:32:38 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
2020-10-25 19:38:00 +01:00
|
|
|
this.cinema = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('cinema');
|
2020-06-10 12:15:25 +02:00
|
|
|
this.cinema.addEventListener('click', (e: MouseEvent) => {
|
2020-04-19 19:32:38 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.disableCamera();
|
2020-04-19 19:32:38 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
2020-06-06 17:03:10 +02:00
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.monitorBtn = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('btn-monitor');
|
|
|
|
this.monitorClose = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('monitor-close');
|
2020-06-06 17:03:10 +02:00
|
|
|
this.monitorClose.style.display = "block";
|
2020-08-18 14:59:50 +02:00
|
|
|
this.monitorClose.addEventListener('click', (e: MouseEvent) => {
|
2020-06-06 17:03:10 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.enableScreenSharing();
|
2020-06-06 17:03:10 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
2020-10-25 19:38:00 +01:00
|
|
|
this.monitor = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('monitor');
|
2020-06-06 17:03:10 +02:00
|
|
|
this.monitor.style.display = "none";
|
2020-08-18 14:59:50 +02:00
|
|
|
this.monitor.addEventListener('click', (e: MouseEvent) => {
|
2020-06-06 17:03:10 +02:00
|
|
|
e.preventDefault();
|
2020-08-20 00:05:00 +02:00
|
|
|
this.disableScreenSharing();
|
2020-06-06 17:03:10 +02:00
|
|
|
//update tracking
|
|
|
|
});
|
2020-10-25 21:59:14 +01:00
|
|
|
|
2020-10-24 14:13:23 +02:00
|
|
|
this.previousConstraint = JSON.parse(JSON.stringify(this.constraintsMedia));
|
2020-10-24 14:40:51 +02:00
|
|
|
this.pingCameraStatus();
|
2020-10-26 22:39:52 +01:00
|
|
|
|
2020-11-27 14:51:50 +01:00
|
|
|
this.checkActiveUser(); //todo: desactivated in case of bug
|
2020-04-26 20:55:20 +02:00
|
|
|
}
|
2020-04-19 19:32:38 +02:00
|
|
|
|
2020-10-26 22:39:52 +01:00
|
|
|
public setLastUpdateScene(){
|
|
|
|
this.lastUpdateScene = new Date();
|
|
|
|
}
|
|
|
|
|
|
|
|
public blurCamera() {
|
|
|
|
if(!this.focused){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.focused = false;
|
|
|
|
this.previousConstraint = JSON.parse(JSON.stringify(this.constraintsMedia));
|
|
|
|
this.disableCamera();
|
|
|
|
}
|
|
|
|
|
|
|
|
public focusCamera() {
|
|
|
|
if(this.focused){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.focused = true;
|
|
|
|
this.applyPreviousConfig();
|
2020-04-26 20:55:20 +02:00
|
|
|
}
|
2020-04-19 19:32:38 +02:00
|
|
|
|
2020-08-20 00:05:00 +02:00
|
|
|
public onUpdateLocalStream(callback: UpdatedLocalStreamCallback): void {
|
2020-06-23 14:56:57 +02:00
|
|
|
this.updatedLocalStreamCallBacks.add(callback);
|
|
|
|
}
|
|
|
|
|
2020-08-21 22:53:17 +02:00
|
|
|
public onStartScreenSharing(callback: StartScreenSharingCallback): void {
|
|
|
|
this.startScreenSharingCallBacks.add(callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
public onStopScreenSharing(callback: StopScreenSharingCallback): void {
|
|
|
|
this.stopScreenSharingCallBacks.add(callback);
|
2020-08-18 00:12:38 +02:00
|
|
|
}
|
|
|
|
|
2020-06-23 14:56:57 +02:00
|
|
|
removeUpdateLocalStreamEventListener(callback: UpdatedLocalStreamCallback): void {
|
|
|
|
this.updatedLocalStreamCallBacks.delete(callback);
|
|
|
|
}
|
|
|
|
|
2020-08-31 15:21:05 +02:00
|
|
|
private triggerUpdatedLocalStreamCallbacks(stream: MediaStream|null): void {
|
2020-06-23 14:56:57 +02:00
|
|
|
for (const callback of this.updatedLocalStreamCallBacks) {
|
|
|
|
callback(stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 22:53:17 +02:00
|
|
|
private triggerStartedScreenSharingCallbacks(stream: MediaStream): void {
|
|
|
|
for (const callback of this.startScreenSharingCallBacks) {
|
|
|
|
callback(stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private triggerStoppedScreenSharingCallbacks(stream: MediaStream): void {
|
|
|
|
for (const callback of this.stopScreenSharingCallBacks) {
|
2020-08-18 00:12:38 +02:00
|
|
|
callback(stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 14:54:52 +02:00
|
|
|
public showGameOverlay(){
|
2020-10-25 19:38:00 +01:00
|
|
|
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
2020-08-13 18:21:48 +02:00
|
|
|
gameOverlay.classList.add('active');
|
2020-11-17 18:03:44 +01:00
|
|
|
|
|
|
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail('cowebsite-close');
|
|
|
|
const functionTrigger = () => {
|
|
|
|
this.triggerCloseJitsiFrameButton();
|
|
|
|
}
|
|
|
|
buttonCloseFrame.removeEventListener('click', functionTrigger);
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
|
|
|
|
2020-09-01 14:43:21 +02:00
|
|
|
public hideGameOverlay(){
|
2020-10-25 19:38:00 +01:00
|
|
|
const gameOverlay = HtmlUtils.getElementByIdOrFail('game-overlay');
|
2020-09-01 14:43:21 +02:00
|
|
|
gameOverlay.classList.remove('active');
|
2020-11-17 18:03:44 +01:00
|
|
|
|
|
|
|
const buttonCloseFrame = HtmlUtils.getElementByIdOrFail('cowebsite-close');
|
|
|
|
const functionTrigger = () => {
|
|
|
|
this.triggerCloseJitsiFrameButton();
|
|
|
|
}
|
|
|
|
buttonCloseFrame.addEventListener('click', functionTrigger);
|
2020-09-01 14:43:21 +02:00
|
|
|
}
|
|
|
|
|
2020-11-27 16:24:07 +01:00
|
|
|
public updateCameraQuality(value: number) {
|
|
|
|
this.enableCameraStyle();
|
|
|
|
const newVideoConstraint = JSON.parse(JSON.stringify(videoConstraint));
|
|
|
|
newVideoConstraint.frameRate = {exact: value, ideal: value};
|
|
|
|
videoConstraint = newVideoConstraint;
|
|
|
|
this.constraintsMedia.video = videoConstraint;
|
|
|
|
this.getCamera().then((stream: MediaStream) => {
|
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-26 15:07:34 +01:00
|
|
|
public enableCamera() {
|
2020-05-03 14:29:45 +02:00
|
|
|
this.constraintsMedia.video = videoConstraint;
|
2021-01-07 10:30:28 +01:00
|
|
|
|
2020-06-22 22:55:28 +02:00
|
|
|
this.getCamera().then((stream: MediaStream) => {
|
2021-01-07 11:02:00 +01:00
|
|
|
//TODO show error message tooltip upper of camera button
|
|
|
|
//TODO message : please check camera permission of your navigator
|
|
|
|
if(stream.getVideoTracks().length === 0) {
|
|
|
|
throw Error('Video track is empty, please check camera permission of your navigator')
|
|
|
|
}
|
2021-01-07 10:30:28 +01:00
|
|
|
this.enableCameraStyle();
|
2020-06-23 14:56:57 +02:00
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
2021-01-07 11:02:00 +01:00
|
|
|
}).catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
this.disableCameraStyle();
|
2020-05-03 17:19:42 +02:00
|
|
|
});
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 15:07:34 +01:00
|
|
|
public async disableCamera() {
|
2020-10-24 14:13:23 +02:00
|
|
|
this.disableCameraStyle();
|
2020-08-31 15:21:05 +02:00
|
|
|
|
|
|
|
if (this.constraintsMedia.audio !== false) {
|
|
|
|
const stream = await this.getCamera();
|
2020-06-23 14:56:57 +02:00
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
2020-08-31 15:21:05 +02:00
|
|
|
} else {
|
|
|
|
this.triggerUpdatedLocalStreamCallbacks(null);
|
|
|
|
}
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 15:07:34 +01:00
|
|
|
public enableMicrophone() {
|
2020-04-19 19:32:38 +02:00
|
|
|
this.constraintsMedia.audio = true;
|
2020-08-31 15:21:05 +02:00
|
|
|
|
2020-05-03 17:19:42 +02:00
|
|
|
this.getCamera().then((stream) => {
|
2021-01-07 11:02:00 +01:00
|
|
|
//TODO show error message tooltip upper of camera button
|
|
|
|
//TODO message : please check microphone permission of your navigator
|
|
|
|
if(stream.getAudioTracks().length === 0) {
|
|
|
|
throw Error('Audio track is empty, please check microphone permission of your navigator')
|
|
|
|
}
|
2021-01-07 10:30:28 +01:00
|
|
|
this.enableMicrophoneStyle();
|
2020-06-23 14:56:57 +02:00
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
2021-01-07 11:02:00 +01:00
|
|
|
}).catch((err) => {
|
|
|
|
console.error(err);
|
|
|
|
this.disableMicrophoneStyle();
|
2020-05-03 17:19:42 +02:00
|
|
|
});
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-26 15:07:34 +01:00
|
|
|
public async disableMicrophone() {
|
2020-10-24 14:13:23 +02:00
|
|
|
this.disableMicrophoneStyle();
|
2020-08-31 14:54:52 +02:00
|
|
|
this.stopMicrophone();
|
2020-08-31 15:21:05 +02:00
|
|
|
|
|
|
|
if (this.constraintsMedia.video !== false) {
|
|
|
|
const stream = await this.getCamera();
|
2020-06-23 14:56:57 +02:00
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
2020-08-31 15:21:05 +02:00
|
|
|
} else {
|
|
|
|
this.triggerUpdatedLocalStreamCallbacks(null);
|
|
|
|
}
|
2020-04-26 20:55:20 +02:00
|
|
|
}
|
|
|
|
|
2020-10-24 14:13:23 +02:00
|
|
|
private applyPreviousConfig() {
|
|
|
|
this.constraintsMedia = this.previousConstraint;
|
|
|
|
if(!this.constraintsMedia.video){
|
|
|
|
this.disableCameraStyle();
|
|
|
|
}else{
|
|
|
|
this.enableCameraStyle();
|
|
|
|
}
|
|
|
|
if(!this.constraintsMedia.audio){
|
|
|
|
this.disableMicrophoneStyle()
|
|
|
|
}else{
|
|
|
|
this.enableMicrophoneStyle()
|
|
|
|
}
|
|
|
|
|
|
|
|
this.getCamera().then((stream: MediaStream) => {
|
|
|
|
this.triggerUpdatedLocalStreamCallbacks(stream);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private enableCameraStyle(){
|
|
|
|
this.cinemaClose.style.display = "none";
|
|
|
|
this.cinemaBtn.classList.remove("disabled");
|
|
|
|
this.cinema.style.display = "block";
|
|
|
|
}
|
|
|
|
|
|
|
|
private disableCameraStyle(){
|
|
|
|
this.cinemaClose.style.display = "block";
|
|
|
|
this.cinema.style.display = "none";
|
|
|
|
this.cinemaBtn.classList.add("disabled");
|
|
|
|
this.constraintsMedia.video = false;
|
|
|
|
this.myCamVideo.srcObject = null;
|
2020-11-10 15:27:22 +01:00
|
|
|
this.stopCamera();
|
2020-10-24 14:13:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private enableMicrophoneStyle(){
|
|
|
|
this.microphoneClose.style.display = "none";
|
|
|
|
this.microphone.style.display = "block";
|
|
|
|
this.microphoneBtn.classList.remove("disabled");
|
|
|
|
}
|
|
|
|
|
|
|
|
private disableMicrophoneStyle(){
|
|
|
|
this.microphoneClose.style.display = "block";
|
|
|
|
this.microphone.style.display = "none";
|
|
|
|
this.microphoneBtn.classList.add("disabled");
|
|
|
|
this.constraintsMedia.audio = false;
|
|
|
|
}
|
|
|
|
|
2020-08-20 00:05:00 +02:00
|
|
|
private enableScreenSharing() {
|
2020-06-06 17:03:10 +02:00
|
|
|
this.monitorClose.style.display = "none";
|
|
|
|
this.monitor.style.display = "block";
|
2020-08-22 15:26:40 +02:00
|
|
|
this.monitorBtn.classList.add("enabled");
|
2020-06-06 17:03:10 +02:00
|
|
|
this.getScreenMedia().then((stream) => {
|
2020-08-21 22:53:17 +02:00
|
|
|
this.triggerStartedScreenSharingCallbacks(stream);
|
2020-06-06 17:03:10 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-08-20 00:05:00 +02:00
|
|
|
private disableScreenSharing() {
|
2020-06-06 17:03:10 +02:00
|
|
|
this.monitorClose.style.display = "block";
|
|
|
|
this.monitor.style.display = "none";
|
2020-08-22 15:26:40 +02:00
|
|
|
this.monitorBtn.classList.remove("enabled");
|
2020-08-21 22:53:17 +02:00
|
|
|
this.removeActiveScreenSharingVideo('me');
|
2020-06-06 17:03:10 +02:00
|
|
|
this.localScreenCapture?.getTracks().forEach((track: MediaStreamTrack) => {
|
|
|
|
track.stop();
|
|
|
|
});
|
2020-08-21 22:53:17 +02:00
|
|
|
if (this.localScreenCapture === null) {
|
|
|
|
console.warn('Weird: trying to remove a screen sharing that is not enabled');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const localScreenCapture = this.localScreenCapture;
|
2020-06-06 17:03:10 +02:00
|
|
|
this.getCamera().then((stream) => {
|
2020-08-21 22:53:17 +02:00
|
|
|
this.triggerStoppedScreenSharingCallbacks(localScreenCapture);
|
2021-01-07 09:42:11 +01:00
|
|
|
}).catch((err) => { //catch error get camera
|
|
|
|
console.error(err);
|
2021-01-06 17:09:17 +01:00
|
|
|
this.triggerStoppedScreenSharingCallbacks(localScreenCapture);
|
2020-06-06 17:03:10 +02:00
|
|
|
});
|
2020-08-21 22:53:17 +02:00
|
|
|
this.localScreenCapture = null;
|
2020-06-06 17:03:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//get screen
|
|
|
|
getScreenMedia() : Promise<MediaStream>{
|
|
|
|
try {
|
|
|
|
return this._startScreenCapture()
|
|
|
|
.then((stream: MediaStream) => {
|
|
|
|
this.localScreenCapture = stream;
|
2020-08-20 22:23:38 +02:00
|
|
|
|
|
|
|
// If stream ends (for instance if user clicks the stop screen sharing button in the browser), let's close the view
|
|
|
|
for (const track of stream.getTracks()) {
|
|
|
|
track.onended = () => {
|
|
|
|
this.disableScreenSharing();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-08-21 22:53:17 +02:00
|
|
|
this.addScreenSharingActiveVideo('me', DivImportance.Normal);
|
|
|
|
HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('screen-sharing-me').srcObject = stream;
|
|
|
|
|
2020-06-06 17:03:10 +02:00
|
|
|
return stream;
|
|
|
|
})
|
2020-08-18 14:59:50 +02:00
|
|
|
.catch((err: unknown) => {
|
|
|
|
console.error("Error => getScreenMedia => ", err);
|
2020-06-06 17:03:10 +02:00
|
|
|
throw err;
|
|
|
|
});
|
|
|
|
}catch (err) {
|
|
|
|
return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
|
|
|
|
reject(err);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private _startScreenCapture() {
|
2020-10-23 16:16:30 +02:00
|
|
|
if (navigator.getDisplayMedia) {
|
|
|
|
return navigator.getDisplayMedia({video: true});
|
|
|
|
} else if (navigator.mediaDevices.getDisplayMedia) {
|
|
|
|
return navigator.mediaDevices.getDisplayMedia({video: true});
|
2020-06-06 17:03:10 +02:00
|
|
|
} else {
|
|
|
|
return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars
|
|
|
|
reject("error sharing screen");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-19 19:32:38 +02:00
|
|
|
//get camera
|
2020-06-25 10:43:27 +02:00
|
|
|
async getCamera(): Promise<MediaStream> {
|
2020-06-22 22:55:28 +02:00
|
|
|
if (navigator.mediaDevices === undefined) {
|
2020-06-25 10:43:27 +02:00
|
|
|
if (window.location.protocol === 'http:') {
|
|
|
|
throw new Error('Unable to access your camera or microphone. You need to use a HTTPS connection.');
|
|
|
|
} else {
|
|
|
|
throw new Error('Unable to access your camera or microphone. Your browser is too old.');
|
|
|
|
}
|
2020-06-22 22:55:28 +02:00
|
|
|
}
|
|
|
|
|
2020-11-10 14:03:29 +01:00
|
|
|
return this.getLocalStream().catch(() => {
|
|
|
|
console.info('Error get camera, trying with video option at null');
|
2020-11-10 15:27:22 +01:00
|
|
|
this.disableCameraStyle();
|
2020-11-10 14:03:29 +01:00
|
|
|
return this.getLocalStream().then((stream : MediaStream) => {
|
|
|
|
this.hasCamera = false;
|
|
|
|
return stream;
|
|
|
|
}).catch((err) => {
|
|
|
|
console.info("error get media ", this.constraintsMedia.video, this.constraintsMedia.audio, err);
|
|
|
|
throw err;
|
|
|
|
});
|
|
|
|
});
|
2020-06-25 10:43:27 +02:00
|
|
|
|
2020-11-10 14:03:29 +01:00
|
|
|
//TODO resize remote cam
|
|
|
|
/*console.log(this.localStream.getTracks());
|
|
|
|
let videoMediaStreamTrack = this.localStream.getTracks().find((media : MediaStreamTrack) => media.kind === "video");
|
|
|
|
let {width, height} = videoMediaStreamTrack.getSettings();
|
|
|
|
console.info(`${width}x${height}`); // 6*/
|
|
|
|
}
|
|
|
|
|
|
|
|
private getLocalStream() : Promise<MediaStream> {
|
|
|
|
return navigator.mediaDevices.getUserMedia(this.constraintsMedia).then((stream : MediaStream) => {
|
2020-06-25 10:43:27 +02:00
|
|
|
this.localStream = stream;
|
|
|
|
this.myCamVideo.srcObject = this.localStream;
|
|
|
|
return stream;
|
2020-11-10 14:03:29 +01:00
|
|
|
}).catch((err: Error) => {
|
2020-06-25 10:43:27 +02:00
|
|
|
throw err;
|
2020-11-10 14:03:29 +01:00
|
|
|
});
|
2020-04-19 19:32:38 +02:00
|
|
|
}
|
2020-04-25 20:29:03 +02:00
|
|
|
|
2020-08-31 14:54:52 +02:00
|
|
|
/**
|
|
|
|
* Stops the camera from filming
|
|
|
|
*/
|
|
|
|
public stopCamera(): void {
|
|
|
|
if (this.localStream) {
|
|
|
|
for (const track of this.localStream.getVideoTracks()) {
|
|
|
|
track.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stops the microphone from listening
|
|
|
|
*/
|
|
|
|
public stopMicrophone(): void {
|
|
|
|
if (this.localStream) {
|
|
|
|
for (const track of this.localStream.getAudioTracks()) {
|
|
|
|
track.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 12:24:36 +02:00
|
|
|
setCamera(id: string): Promise<MediaStream> {
|
|
|
|
let video = this.constraintsMedia.video;
|
|
|
|
if (typeof(video) === 'boolean' || video === undefined) {
|
|
|
|
video = {}
|
|
|
|
}
|
2020-06-25 10:33:26 +02:00
|
|
|
video.deviceId = {
|
|
|
|
exact: id
|
|
|
|
};
|
2020-06-23 12:24:36 +02:00
|
|
|
|
|
|
|
return this.getCamera();
|
|
|
|
}
|
|
|
|
|
|
|
|
setMicrophone(id: string): Promise<MediaStream> {
|
|
|
|
let audio = this.constraintsMedia.audio;
|
|
|
|
if (typeof(audio) === 'boolean' || audio === undefined) {
|
|
|
|
audio = {}
|
|
|
|
}
|
2020-06-25 11:26:55 +02:00
|
|
|
audio.deviceId = {
|
|
|
|
exact: id
|
|
|
|
};
|
2020-06-23 12:24:36 +02:00
|
|
|
|
|
|
|
return this.getCamera();
|
|
|
|
}
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
addActiveVideo(user: UserSimplePeerInterface, userName: string = ""){
|
2020-05-14 20:39:30 +02:00
|
|
|
this.webrtcInAudio.play();
|
2021-02-02 18:19:51 +01:00
|
|
|
const userId = ''+user.userId
|
2020-08-13 18:21:48 +02:00
|
|
|
|
2020-05-14 20:39:30 +02:00
|
|
|
userName = userName.toUpperCase();
|
2020-06-09 23:13:26 +02:00
|
|
|
const color = this.getColorByString(userName);
|
2020-08-13 18:21:48 +02:00
|
|
|
|
|
|
|
const html = `
|
|
|
|
<div id="div-${userId}" class="video-container">
|
|
|
|
<div class="connecting-spinner"></div>
|
|
|
|
<div class="rtc-error" style="display: none"></div>
|
2020-08-16 23:19:04 +02:00
|
|
|
<i id="name-${userId}" style="background-color: ${color};">${userName}</i>
|
2021-02-02 18:19:51 +01:00
|
|
|
<img id="microphone-${userId}" title="mute" src="resources/logos/microphone-close.svg">
|
|
|
|
<button id="report-${userId}" class="report">
|
|
|
|
<img title="report this user" src="resources/logos/report.svg">
|
|
|
|
<span>Report/Block</span>
|
|
|
|
</button>
|
|
|
|
<video id="${userId}" autoplay></video>
|
|
|
|
<img src="resources/logos/blockSign.svg" id="blocking-${userId}" class="block-logo">
|
2020-08-13 18:21:48 +02:00
|
|
|
</div>
|
|
|
|
`;
|
|
|
|
|
|
|
|
layoutManager.add(DivImportance.Normal, userId, html);
|
2021-02-02 18:19:51 +01:00
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId));
|
2020-10-25 21:59:14 +01:00
|
|
|
|
|
|
|
//permit to create participant in discussion part
|
2021-01-29 21:09:10 +01:00
|
|
|
const showReportUser = () => {
|
|
|
|
for(const callBack of this.showReportModalCallBacks){
|
|
|
|
callBack(userId, userName);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.addNewParticipant(userId, userName, undefined, showReportUser);
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
const reportBanUserActionEl: HTMLImageElement = HtmlUtils.getElementByIdOrFail<HTMLImageElement>(`report-${userId}`);
|
|
|
|
reportBanUserActionEl.addEventListener('click', (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
showReportUser();
|
|
|
|
});
|
2020-04-26 19:12:01 +02:00
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){
|
2020-08-20 00:05:00 +02:00
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
userId = this.getScreenSharingId(userId);
|
2020-08-20 00:05:00 +02:00
|
|
|
const html = `
|
|
|
|
<div id="div-${userId}" class="video-container">
|
2020-06-08 09:20:36 +02:00
|
|
|
<video id="${userId}" autoplay></video>
|
|
|
|
</div>
|
2020-08-20 00:05:00 +02:00
|
|
|
`;
|
|
|
|
|
2020-08-21 22:53:17 +02:00
|
|
|
layoutManager.add(divImportance, userId, html);
|
2020-08-20 00:05:00 +02:00
|
|
|
|
2020-10-25 19:38:00 +01:00
|
|
|
this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId));
|
2020-06-08 09:20:36 +02:00
|
|
|
}
|
2021-02-02 18:19:51 +01:00
|
|
|
|
|
|
|
private getScreenSharingId(userId: string): string {
|
|
|
|
return `screen-sharing-${userId}`;
|
|
|
|
}
|
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
disabledMicrophoneByUserId(userId: number){
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`microphone-${userId}`);
|
2020-05-14 20:39:30 +02:00
|
|
|
if(!element){
|
|
|
|
return;
|
|
|
|
}
|
2020-11-27 14:51:50 +01:00
|
|
|
element.classList.add('active') //todo: why does a method 'disable' add a class 'active'?
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
enabledMicrophoneByUserId(userId: number){
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`microphone-${userId}`);
|
2020-05-14 20:39:30 +02:00
|
|
|
if(!element){
|
|
|
|
return;
|
|
|
|
}
|
2020-11-27 14:51:50 +01:00
|
|
|
element.classList.remove('active') //todo: why does a method 'enable' remove a class 'active'?
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
disabledVideoByUserId(userId: number) {
|
2020-05-14 20:39:30 +02:00
|
|
|
let element = document.getElementById(`${userId}`);
|
2020-05-14 20:54:34 +02:00
|
|
|
if (element) {
|
|
|
|
element.style.opacity = "0";
|
|
|
|
}
|
2020-08-16 23:19:04 +02:00
|
|
|
element = document.getElementById(`name-${userId}`);
|
|
|
|
if (element) {
|
|
|
|
element.style.display = "block";
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
enabledVideoByUserId(userId: number){
|
2020-05-14 20:39:30 +02:00
|
|
|
let element = document.getElementById(`${userId}`);
|
2020-05-14 20:54:34 +02:00
|
|
|
if(element){
|
|
|
|
element.style.opacity = "1";
|
|
|
|
}
|
2020-08-16 23:19:04 +02:00
|
|
|
element = document.getElementById(`name-${userId}`);
|
|
|
|
if(element){
|
|
|
|
element.style.display = "none";
|
2020-05-14 20:39:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
toggleBlockLogo(userId: number, show: boolean): void {
|
|
|
|
const blockLogoElement = HtmlUtils.getElementByIdOrFail<HTMLImageElement>('blocking-'+userId);
|
|
|
|
show ? blockLogoElement.classList.add('active') : blockLogoElement.classList.remove('active');
|
|
|
|
}
|
2020-11-27 14:51:50 +01:00
|
|
|
addStreamRemoteVideo(userId: string, stream : MediaStream): void {
|
2020-06-10 12:15:25 +02:00
|
|
|
const remoteVideo = this.remoteVideo.get(userId);
|
|
|
|
if (remoteVideo === undefined) {
|
2020-10-20 18:02:44 +02:00
|
|
|
throw `Unable to find video for ${userId}`;
|
2020-06-10 12:15:25 +02:00
|
|
|
}
|
|
|
|
remoteVideo.srcObject = stream;
|
2020-05-02 20:46:02 +02:00
|
|
|
}
|
2020-09-18 13:57:38 +02:00
|
|
|
addStreamRemoteScreenSharing(userId: string, stream : MediaStream){
|
2020-08-21 22:53:17 +02:00
|
|
|
// In the case of screen sharing (going both ways), we may need to create the HTML element if it does not exist yet
|
2021-02-02 18:19:51 +01:00
|
|
|
const remoteVideo = this.remoteVideo.get(this.getScreenSharingId(userId));
|
2020-08-21 22:53:17 +02:00
|
|
|
if (remoteVideo === undefined) {
|
|
|
|
this.addScreenSharingActiveVideo(userId);
|
|
|
|
}
|
|
|
|
|
2021-02-02 18:19:51 +01:00
|
|
|
this.addStreamRemoteVideo(this.getScreenSharingId(userId), stream);
|
2020-06-11 23:18:06 +02:00
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
removeActiveVideo(userId: string){
|
2020-08-13 18:21:48 +02:00
|
|
|
layoutManager.remove(userId);
|
2020-06-10 12:15:25 +02:00
|
|
|
this.remoteVideo.delete(userId);
|
2020-10-25 21:59:14 +01:00
|
|
|
|
|
|
|
//permit to remove user in discussion part
|
|
|
|
this.removeParticipant(userId);
|
2020-04-25 20:29:03 +02:00
|
|
|
}
|
2020-09-18 13:57:38 +02:00
|
|
|
removeActiveScreenSharingVideo(userId: string) {
|
2021-02-02 18:19:51 +01:00
|
|
|
this.removeActiveVideo(this.getScreenSharingId(userId))
|
2020-06-11 23:18:06 +02:00
|
|
|
}
|
2020-12-11 15:35:13 +01:00
|
|
|
|
|
|
|
playWebrtcOutSound(): void {
|
|
|
|
this.webrtcOutAudio.play();
|
|
|
|
}
|
2020-05-14 20:39:30 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
isConnecting(userId: string): void {
|
2020-06-09 23:13:26 +02:00
|
|
|
const connectingSpinnerDiv = this.getSpinner(userId);
|
2020-06-06 22:49:55 +02:00
|
|
|
if (connectingSpinnerDiv === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
connectingSpinnerDiv.style.display = 'block';
|
|
|
|
}
|
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
isConnected(userId: string): void {
|
2020-06-09 23:13:26 +02:00
|
|
|
const connectingSpinnerDiv = this.getSpinner(userId);
|
2020-06-06 22:49:55 +02:00
|
|
|
if (connectingSpinnerDiv === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
connectingSpinnerDiv.style.display = 'none';
|
|
|
|
}
|
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
isError(userId: string): void {
|
2020-11-27 16:24:07 +01:00
|
|
|
console.info("isError", `div-${userId}`);
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`div-${userId}`);
|
2020-06-06 22:49:55 +02:00
|
|
|
if(!element){
|
|
|
|
return;
|
|
|
|
}
|
2020-06-09 23:13:26 +02:00
|
|
|
const errorDiv = element.getElementsByClassName('rtc-error').item(0) as HTMLDivElement|null;
|
2020-06-06 22:49:55 +02:00
|
|
|
if (errorDiv === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
errorDiv.style.display = 'block';
|
|
|
|
}
|
2020-09-18 13:57:38 +02:00
|
|
|
isErrorScreenSharing(userId: string): void {
|
2021-02-02 18:19:51 +01:00
|
|
|
this.isError(this.getScreenSharingId(userId));
|
2020-06-14 14:47:16 +02:00
|
|
|
}
|
|
|
|
|
2020-06-06 22:49:55 +02:00
|
|
|
|
2020-09-18 13:57:38 +02:00
|
|
|
private getSpinner(userId: string): HTMLDivElement|null {
|
2020-06-09 23:13:26 +02:00
|
|
|
const element = document.getElementById(`div-${userId}`);
|
2020-06-06 22:49:55 +02:00
|
|
|
if(!element){
|
|
|
|
return null;
|
|
|
|
}
|
2020-06-09 23:13:26 +02:00
|
|
|
const connnectingSpinnerDiv = element.getElementsByClassName('connecting-spinner').item(0) as HTMLDivElement|null;
|
2020-06-06 22:49:55 +02:00
|
|
|
return connnectingSpinnerDiv;
|
|
|
|
}
|
2020-10-23 16:16:30 +02:00
|
|
|
|
2020-05-14 20:39:30 +02:00
|
|
|
private getColorByString(str: String) : String|null {
|
|
|
|
let hash = 0;
|
|
|
|
if (str.length === 0) return null;
|
|
|
|
for (let i = 0; i < str.length; i++) {
|
|
|
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
|
|
|
hash = hash & hash;
|
|
|
|
}
|
|
|
|
let color = '#';
|
|
|
|
for (let i = 0; i < 3; i++) {
|
2020-06-09 23:13:26 +02:00
|
|
|
const value = (hash >> (i * 8)) & 255;
|
2020-05-14 20:39:30 +02:00
|
|
|
color += ('00' + value.toString(16)).substr(-2);
|
|
|
|
}
|
|
|
|
return color;
|
|
|
|
}
|
2020-06-03 11:55:31 +02:00
|
|
|
|
2021-01-29 21:09:10 +01:00
|
|
|
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, showReportUserCallBack?: ShowReportCallBack){
|
|
|
|
discussionManager.addParticipant(userId, name, img, false, showReportUserCallBack);
|
2020-10-25 21:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public removeParticipant(userId: number|string){
|
2020-12-04 11:30:35 +01:00
|
|
|
discussionManager.removeParticipant(userId);
|
2020-10-25 21:59:14 +01:00
|
|
|
}
|
2020-11-17 18:03:44 +01:00
|
|
|
public addTriggerCloseJitsiFrameButton(id: String, Function: Function){
|
|
|
|
this.triggerCloseJistiFrame.set(id, Function);
|
|
|
|
}
|
|
|
|
|
|
|
|
public removeTriggerCloseJitsiFrameButton(id: String){
|
|
|
|
this.triggerCloseJistiFrame.delete(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
private triggerCloseJitsiFrameButton(): void {
|
|
|
|
for (const callback of this.triggerCloseJistiFrame.values()) {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
}
|
2020-11-04 12:42:33 +01:00
|
|
|
/**
|
|
|
|
* For some reasons, the microphone muted icon or the stream is not always up to date.
|
|
|
|
* Here, every 30 seconds, we are "reseting" the streams and sending again the constraints to the other peers via the data channel again (see SimplePeer::pushVideoToRemoteUser)
|
|
|
|
**/
|
2020-10-24 14:40:51 +02:00
|
|
|
private pingCameraStatus(){
|
2020-11-27 14:51:50 +01:00
|
|
|
/*setInterval(() => {
|
2020-10-24 14:40:51 +02:00
|
|
|
console.log('ping camera status');
|
2020-11-21 18:47:38 +01:00
|
|
|
this.triggerUpdatedLocalStreamCallbacks(this.localStream);
|
2020-11-27 14:51:50 +01:00
|
|
|
}, 30000);*/
|
2020-10-24 14:40:51 +02:00
|
|
|
}
|
2020-10-13 19:56:42 +02:00
|
|
|
|
2020-10-25 21:59:14 +01:00
|
|
|
public addNewMessage(name: string, message: string, isMe: boolean = false){
|
2020-12-04 11:30:35 +01:00
|
|
|
discussionManager.addMessage(name, message, isMe);
|
2020-11-17 16:46:46 +01:00
|
|
|
|
|
|
|
//when there are new message, show discussion
|
2020-12-04 11:30:35 +01:00
|
|
|
if(!discussionManager.activatedDiscussion) {
|
|
|
|
discussionManager.showDiscussionPart();
|
2020-11-17 16:46:46 +01:00
|
|
|
}
|
2020-10-25 21:59:14 +01:00
|
|
|
}
|
|
|
|
|
2020-10-26 14:13:51 +01:00
|
|
|
public addSendMessageCallback(userId: string|number, callback: SendMessageCallback){
|
2020-12-04 11:30:35 +01:00
|
|
|
discussionManager.onSendMessageCallback(userId, callback);
|
2020-10-25 21:59:14 +01:00
|
|
|
}
|
2020-10-27 20:46:53 +01:00
|
|
|
|
|
|
|
get activatedDiscussion(){
|
2020-12-04 11:30:35 +01:00
|
|
|
return discussionManager.activatedDiscussion;
|
2020-10-27 20:46:53 +01:00
|
|
|
}
|
2020-11-10 12:38:32 +01:00
|
|
|
|
|
|
|
public setUserInputManager(userInputManager : UserInputManager){
|
2020-12-04 11:30:35 +01:00
|
|
|
discussionManager.setUserInputManager(userInputManager);
|
2020-11-10 12:38:32 +01:00
|
|
|
}
|
2020-10-26 22:39:52 +01:00
|
|
|
//check if user is active
|
|
|
|
private checkActiveUser(){
|
|
|
|
if(this.setTimeOutlastUpdateScene){
|
|
|
|
clearTimeout(this.setTimeOutlastUpdateScene);
|
|
|
|
}
|
|
|
|
this.setTimeOutlastUpdateScene = setTimeout(() => {
|
|
|
|
const now = new Date();
|
|
|
|
//if last update is more of 10 sec
|
|
|
|
if( (now.getTime() - this.lastUpdateScene.getTime()) > 10000) {
|
|
|
|
this.blurCamera();
|
|
|
|
}else{
|
|
|
|
this.focusCamera();
|
|
|
|
}
|
|
|
|
this.checkActiveUser();
|
|
|
|
}, this.focused ? 10000 : 1000);
|
|
|
|
}
|
2021-01-29 21:09:10 +01:00
|
|
|
|
|
|
|
public setShowReportModalCallBacks(callback: ShowReportCallBack){
|
|
|
|
this.showReportModalCallBacks.add(callback);
|
|
|
|
}
|
2020-06-03 11:55:31 +02:00
|
|
|
}
|
2020-06-23 14:56:57 +02:00
|
|
|
|
|
|
|
export const mediaManager = new MediaManager();
|