From 23bf78a026df4fd66a48c6d6faacba08e52d6049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 11 May 2021 10:56:50 +0200 Subject: [PATCH] Refactoring code to use the "visibilitychange" event Using the "visiblitychange" event instead of relying on a "trick" related to RAF being disabled when a window is not open allows us to have cleaner code. Bonus: the recursive call to "setTimeout" is gone, so the stacktrace growing indefinitely is gone too. This should make the application a bit more stable. --- front/src/Phaser/Game/GameScene.ts | 17 ++++++++ front/src/Phaser/Login/EnableCameraScene.ts | 1 - front/src/WebRtc/MediaManager.ts | 44 ++++++--------------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index c433ed0f..cd1b8892 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -183,6 +183,7 @@ export class GameScene extends ResizableScene implements CenterListener { private messageSubscription: Subscription|null = null; private popUpElements : Map = new Map(); private originalMapUrl: string|undefined; + private onVisibilityChangeCallback: () => void; constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) { super({ @@ -202,6 +203,7 @@ export class GameScene extends ResizableScene implements CenterListener { this.connectionAnswerPromise = new Promise((resolve, reject): void => { this.connectionAnswerPromiseResolve = resolve; }) + this.onVisibilityChangeCallback = this.onVisibilityChange.bind(this); } //hook preload scene @@ -499,6 +501,8 @@ export class GameScene extends ResizableScene implements CenterListener { if (!this.room.isDisconnected()) { this.connect(); } + + document.addEventListener('visibilitychange', this.onVisibilityChangeCallback); } /** @@ -620,6 +624,7 @@ export class GameScene extends ResizableScene implements CenterListener { self.chatModeSprite.setVisible(false); self.openChatIcon.setVisible(false); audioManager.restoreVolume(); + self.onVisibilityChange(); } } }) @@ -918,6 +923,8 @@ ${escapedMessage} for(const iframeEvents of this.iframeSubscriptionList){ iframeEvents.unsubscribe(); } + + document.removeEventListener('visibilitychange', this.onVisibilityChangeCallback); } private removeAllRemotePlayers(): void { @@ -1510,4 +1517,14 @@ ${escapedMessage} }); } } + + private onVisibilityChange(): void { + if (document.visibilityState === 'visible') { + mediaManager.focusCamera(); + } else { + if (this.simplePeer.getNbConnections() === 0) { + mediaManager.blurCamera(); + } + } + } } diff --git a/front/src/Phaser/Login/EnableCameraScene.ts b/front/src/Phaser/Login/EnableCameraScene.ts index 917dd44b..dfe48aea 100644 --- a/front/src/Phaser/Login/EnableCameraScene.ts +++ b/front/src/Phaser/Login/EnableCameraScene.ts @@ -247,7 +247,6 @@ export class EnableCameraScene extends Phaser.Scene { update(time: number, delta: number): void { this.soundMeterSprite.setVolume(this.soundMeter.getVolume()); - mediaManager.updateScene(); const middleX = this.getMiddleX(); this.tweens.add({ diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index 460d5807..437e5e76 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -55,7 +55,7 @@ export class MediaManager { stopScreenSharingCallBacks : Set = new Set(); showReportModalCallBacks : Set = new Set(); helpCameraSettingsCallBacks : Set = new Set(); - + private microphoneBtn: HTMLDivElement; private cinemaBtn: HTMLDivElement; private monitorBtn: HTMLDivElement; @@ -63,9 +63,6 @@ export class MediaManager { private previousConstraint : MediaStreamConstraints; private focused : boolean = true; - private lastUpdateScene : Date = new Date(); - private setTimeOutlastUpdateScene? : NodeJS.Timeout; - private hasCamera = true; private triggerCloseJistiFrame : Map = new Map(); @@ -134,8 +131,6 @@ export class MediaManager { this.previousConstraint = JSON.parse(JSON.stringify(this.constraintsMedia)); this.pingCameraStatus(); - this.checkActiveUser(); //todo: desactivated in case of bug - //FIX ME SOUNDMETER: check stalability of sound meter calculation /*this.mySoundMeterElement = (HtmlUtils.getElementByIdOrFail('mySoundMeter')); this.mySoundMeterElement.childNodes.forEach((value: ChildNode, index) => { @@ -147,7 +142,6 @@ export class MediaManager { } public updateScene(){ - this.lastUpdateScene = new Date(); //FIX ME SOUNDMETER: check stalability of sound meter calculation //this.updateSoudMeter(); } @@ -418,7 +412,7 @@ export class MediaManager { } private _startScreenCapture() { - if (navigator.getDisplayMedia) { + if (navigator.getDisplayMedia) { return navigator.getDisplayMedia({video: true}); } else if (navigator.mediaDevices.getDisplayMedia) { return navigator.mediaDevices.getDisplayMedia({video: true}); @@ -553,7 +547,7 @@ export class MediaManager { `; layoutManager.add(DivImportance.Normal, userId, html); - + this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail(userId)); //permit to create participant in discussion part @@ -571,7 +565,7 @@ export class MediaManager { showReportUser(); }); } - + addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){ userId = this.getScreenSharingId(userId); @@ -597,7 +591,7 @@ export class MediaManager { } element.classList.add('active') //todo: why does a method 'disable' add a class 'active'? } - + enabledMicrophoneByUserId(userId: number){ const element = document.getElementById(`microphone-${userId}`); if(!element){ @@ -605,7 +599,7 @@ export class MediaManager { } element.classList.remove('active') //todo: why does a method 'enable' remove a class 'active'? } - + disabledVideoByUserId(userId: number) { let element = document.getElementById(`${userId}`); if (element) { @@ -616,7 +610,7 @@ export class MediaManager { element.style.display = "block"; } } - + enabledVideoByUserId(userId: number){ let element = document.getElementById(`${userId}`); if(element){ @@ -655,7 +649,7 @@ export class MediaManager { this.addStreamRemoteVideo(this.getScreenSharingId(userId), stream); } - + removeActiveVideo(userId: string){ layoutManager.remove(userId); this.remoteVideo.delete(userId); @@ -671,7 +665,7 @@ export class MediaManager { removeActiveScreenSharingVideo(userId: string) { this.removeActiveVideo(this.getScreenSharingId(userId)) } - + playWebrtcOutSound(): void { this.webrtcOutAudio.play(); } @@ -717,7 +711,7 @@ export class MediaManager { const connnectingSpinnerDiv = element.getElementsByClassName('connecting-spinner').item(0) as HTMLDivElement|null; return connnectingSpinnerDiv; } - + private getColorByString(str: String) : String|null { let hash = 0; if (str.length === 0) return null; @@ -785,22 +779,6 @@ export class MediaManager { this.userInputManager = userInputManager; discussionManager.setUserInputManager(userInputManager); } - //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.remoteVideo.size === 0) { - this.blurCamera(); - }else if((now.getTime() - this.lastUpdateScene.getTime()) <= 10000){ - this.focusCamera(); - } - this.checkActiveUser(); - }, this.focused ? 10000 : 1000); - } public setShowReportModalCallBacks(callback: ShowReportCallBack){ this.showReportModalCallBacks.add(callback); @@ -821,7 +799,7 @@ export class MediaManager { try{ const volume = parseInt(((this.mySoundMeter ? this.mySoundMeter.getVolume() : 0) / 10).toFixed(0)); this.setVolumeSoundMeter(volume, this.mySoundMeterElement); - + for(const indexUserId of this.soundMeters.keys()){ const soundMeter = this.soundMeters.get(indexUserId); const soundMeterElement = this.soundMeterElements.get(indexUserId);