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.
This commit is contained in:
David Négrier 2021-05-11 10:56:50 +02:00
parent 0229f09ec6
commit 23bf78a026
3 changed files with 28 additions and 34 deletions

View File

@ -183,6 +183,7 @@ export class GameScene extends ResizableScene implements CenterListener {
private messageSubscription: Subscription|null = null; private messageSubscription: Subscription|null = null;
private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>(); private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
private originalMapUrl: string|undefined; private originalMapUrl: string|undefined;
private onVisibilityChangeCallback: () => void;
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) { constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
super({ super({
@ -202,6 +203,7 @@ export class GameScene extends ResizableScene implements CenterListener {
this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => { this.connectionAnswerPromise = new Promise<RoomJoinedMessageInterface>((resolve, reject): void => {
this.connectionAnswerPromiseResolve = resolve; this.connectionAnswerPromiseResolve = resolve;
}) })
this.onVisibilityChangeCallback = this.onVisibilityChange.bind(this);
} }
//hook preload scene //hook preload scene
@ -499,6 +501,8 @@ export class GameScene extends ResizableScene implements CenterListener {
if (!this.room.isDisconnected()) { if (!this.room.isDisconnected()) {
this.connect(); this.connect();
} }
document.addEventListener('visibilitychange', this.onVisibilityChangeCallback);
} }
/** /**
@ -620,6 +624,7 @@ export class GameScene extends ResizableScene implements CenterListener {
self.chatModeSprite.setVisible(false); self.chatModeSprite.setVisible(false);
self.openChatIcon.setVisible(false); self.openChatIcon.setVisible(false);
audioManager.restoreVolume(); audioManager.restoreVolume();
self.onVisibilityChange();
} }
} }
}) })
@ -918,6 +923,8 @@ ${escapedMessage}
for(const iframeEvents of this.iframeSubscriptionList){ for(const iframeEvents of this.iframeSubscriptionList){
iframeEvents.unsubscribe(); iframeEvents.unsubscribe();
} }
document.removeEventListener('visibilitychange', this.onVisibilityChangeCallback);
} }
private removeAllRemotePlayers(): void { 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();
}
}
}
} }

View File

@ -247,7 +247,6 @@ export class EnableCameraScene extends Phaser.Scene {
update(time: number, delta: number): void { update(time: number, delta: number): void {
this.soundMeterSprite.setVolume(this.soundMeter.getVolume()); this.soundMeterSprite.setVolume(this.soundMeter.getVolume());
mediaManager.updateScene();
const middleX = this.getMiddleX(); const middleX = this.getMiddleX();
this.tweens.add({ this.tweens.add({

View File

@ -55,7 +55,7 @@ export class MediaManager {
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>(); stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>(); showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
helpCameraSettingsCallBacks : Set<HelpCameraSettingsCallBack> = new Set<HelpCameraSettingsCallBack>(); helpCameraSettingsCallBacks : Set<HelpCameraSettingsCallBack> = new Set<HelpCameraSettingsCallBack>();
private microphoneBtn: HTMLDivElement; private microphoneBtn: HTMLDivElement;
private cinemaBtn: HTMLDivElement; private cinemaBtn: HTMLDivElement;
private monitorBtn: HTMLDivElement; private monitorBtn: HTMLDivElement;
@ -63,9 +63,6 @@ export class MediaManager {
private previousConstraint : MediaStreamConstraints; private previousConstraint : MediaStreamConstraints;
private focused : boolean = true; private focused : boolean = true;
private lastUpdateScene : Date = new Date();
private setTimeOutlastUpdateScene? : NodeJS.Timeout;
private hasCamera = true; private hasCamera = true;
private triggerCloseJistiFrame : Map<String, Function> = new Map<String, Function>(); private triggerCloseJistiFrame : Map<String, Function> = new Map<String, Function>();
@ -134,8 +131,6 @@ export class MediaManager {
this.previousConstraint = JSON.parse(JSON.stringify(this.constraintsMedia)); this.previousConstraint = JSON.parse(JSON.stringify(this.constraintsMedia));
this.pingCameraStatus(); this.pingCameraStatus();
this.checkActiveUser(); //todo: desactivated in case of bug
//FIX ME SOUNDMETER: check stalability of sound meter calculation //FIX ME SOUNDMETER: check stalability of sound meter calculation
/*this.mySoundMeterElement = (HtmlUtils.getElementByIdOrFail('mySoundMeter')); /*this.mySoundMeterElement = (HtmlUtils.getElementByIdOrFail('mySoundMeter'));
this.mySoundMeterElement.childNodes.forEach((value: ChildNode, index) => { this.mySoundMeterElement.childNodes.forEach((value: ChildNode, index) => {
@ -147,7 +142,6 @@ export class MediaManager {
} }
public updateScene(){ public updateScene(){
this.lastUpdateScene = new Date();
//FIX ME SOUNDMETER: check stalability of sound meter calculation //FIX ME SOUNDMETER: check stalability of sound meter calculation
//this.updateSoudMeter(); //this.updateSoudMeter();
} }
@ -418,7 +412,7 @@ export class MediaManager {
} }
private _startScreenCapture() { private _startScreenCapture() {
if (navigator.getDisplayMedia) { if (navigator.getDisplayMedia) {
return navigator.getDisplayMedia({video: true}); return navigator.getDisplayMedia({video: true});
} else if (navigator.mediaDevices.getDisplayMedia) { } else if (navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia({video: true}); return navigator.mediaDevices.getDisplayMedia({video: true});
@ -553,7 +547,7 @@ export class MediaManager {
`; `;
layoutManager.add(DivImportance.Normal, userId, html); layoutManager.add(DivImportance.Normal, userId, html);
this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId)); this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId));
//permit to create participant in discussion part //permit to create participant in discussion part
@ -571,7 +565,7 @@ export class MediaManager {
showReportUser(); showReportUser();
}); });
} }
addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){ addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){
userId = this.getScreenSharingId(userId); 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'? element.classList.add('active') //todo: why does a method 'disable' add a class 'active'?
} }
enabledMicrophoneByUserId(userId: number){ enabledMicrophoneByUserId(userId: number){
const element = document.getElementById(`microphone-${userId}`); const element = document.getElementById(`microphone-${userId}`);
if(!element){ if(!element){
@ -605,7 +599,7 @@ export class MediaManager {
} }
element.classList.remove('active') //todo: why does a method 'enable' remove a class 'active'? element.classList.remove('active') //todo: why does a method 'enable' remove a class 'active'?
} }
disabledVideoByUserId(userId: number) { disabledVideoByUserId(userId: number) {
let element = document.getElementById(`${userId}`); let element = document.getElementById(`${userId}`);
if (element) { if (element) {
@ -616,7 +610,7 @@ export class MediaManager {
element.style.display = "block"; element.style.display = "block";
} }
} }
enabledVideoByUserId(userId: number){ enabledVideoByUserId(userId: number){
let element = document.getElementById(`${userId}`); let element = document.getElementById(`${userId}`);
if(element){ if(element){
@ -655,7 +649,7 @@ export class MediaManager {
this.addStreamRemoteVideo(this.getScreenSharingId(userId), stream); this.addStreamRemoteVideo(this.getScreenSharingId(userId), stream);
} }
removeActiveVideo(userId: string){ removeActiveVideo(userId: string){
layoutManager.remove(userId); layoutManager.remove(userId);
this.remoteVideo.delete(userId); this.remoteVideo.delete(userId);
@ -671,7 +665,7 @@ export class MediaManager {
removeActiveScreenSharingVideo(userId: string) { removeActiveScreenSharingVideo(userId: string) {
this.removeActiveVideo(this.getScreenSharingId(userId)) this.removeActiveVideo(this.getScreenSharingId(userId))
} }
playWebrtcOutSound(): void { playWebrtcOutSound(): void {
this.webrtcOutAudio.play(); this.webrtcOutAudio.play();
} }
@ -717,7 +711,7 @@ export class MediaManager {
const connnectingSpinnerDiv = element.getElementsByClassName('connecting-spinner').item(0) as HTMLDivElement|null; const connnectingSpinnerDiv = element.getElementsByClassName('connecting-spinner').item(0) as HTMLDivElement|null;
return connnectingSpinnerDiv; return connnectingSpinnerDiv;
} }
private getColorByString(str: String) : String|null { private getColorByString(str: String) : String|null {
let hash = 0; let hash = 0;
if (str.length === 0) return null; if (str.length === 0) return null;
@ -785,22 +779,6 @@ export class MediaManager {
this.userInputManager = userInputManager; this.userInputManager = userInputManager;
discussionManager.setUserInputManager(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){ public setShowReportModalCallBacks(callback: ShowReportCallBack){
this.showReportModalCallBacks.add(callback); this.showReportModalCallBacks.add(callback);
@ -821,7 +799,7 @@ export class MediaManager {
try{ try{
const volume = parseInt(((this.mySoundMeter ? this.mySoundMeter.getVolume() : 0) / 10).toFixed(0)); const volume = parseInt(((this.mySoundMeter ? this.mySoundMeter.getVolume() : 0) / 10).toFixed(0));
this.setVolumeSoundMeter(volume, this.mySoundMeterElement); this.setVolumeSoundMeter(volume, this.mySoundMeterElement);
for(const indexUserId of this.soundMeters.keys()){ for(const indexUserId of this.soundMeters.keys()){
const soundMeter = this.soundMeters.get(indexUserId); const soundMeter = this.soundMeters.get(indexUserId);
const soundMeterElement = this.soundMeterElements.get(indexUserId); const soundMeterElement = this.soundMeterElements.get(indexUserId);