From ffb5823b2af1ffc0afb95648504e198a3d8bf90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Tue, 16 Mar 2021 20:37:12 +0100 Subject: [PATCH 01/10] Adding the ability to specify a custom Jitsi URL directly in the map This feature allows to add a "jitsiUrl" property in the map. As a result, you can use for a given Jitsi room a custom instance of Jitsi. Using "jitsiUrl" will only work with public Jitsi instances (authentication is not supported when "jitsiUrl" property is provided) The Jitsi external_api.js script is now lazily loaded. --- front/src/Phaser/Game/GameScene.ts | 6 +- front/src/WebRtc/JitsiFactory.ts | 38 +++++++++++- front/src/index.ts | 7 --- maps/tests/jitsi_custom_url.json | 94 ++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 maps/tests/jitsi_custom_url.json diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index a90cb6b1..24594a44 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -682,7 +682,8 @@ export class GameScene extends ResizableScene implements CenterListener { }else{ const openJitsiRoomFunction = () => { const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance); - if (JITSI_PRIVATE_MODE) { + const jitsiUrl = allProps.get("jitsiUrl") as string|undefined; + if (JITSI_PRIVATE_MODE && !jitsiUrl) { const adminTag = allProps.get("jitsiRoomAdminTag") as string|undefined; this.connection.emitQueryJitsiJwtMessage(roomName, adminTag); @@ -1258,8 +1259,9 @@ export class GameScene extends ResizableScene implements CenterListener { const allProps = this.gameMap.getCurrentProperties(); const jitsiConfig = this.safeParseJSONstring(allProps.get("jitsiConfig") as string|undefined, 'jitsiConfig'); const jitsiInterfaceConfig = this.safeParseJSONstring(allProps.get("jitsiInterfaceConfig") as string|undefined, 'jitsiInterfaceConfig'); + const jitsiUrl = allProps.get("jitsiUrl") as string|undefined; - jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig); + jitsiFactory.start(roomName, this.playerName, jwt, jitsiConfig, jitsiInterfaceConfig, jitsiUrl); this.connection.setSilent(true); mediaManager.hideGameOverlay(); diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts index 70ee66bf..983b08e2 100644 --- a/front/src/WebRtc/JitsiFactory.ts +++ b/front/src/WebRtc/JitsiFactory.ts @@ -72,6 +72,7 @@ class JitsiFactory { private audioCallback = this.onAudioChange.bind(this); private videoCallback = this.onVideoChange.bind(this); private previousConfigMeet? : jitsiConfigInterface; + private jitsiScriptLoaded: boolean = false; /** * Slugifies the room name and prepends the room name with the instance @@ -80,11 +81,11 @@ class JitsiFactory { return slugify(instance.replace('/', '-') + "-" + roomName); } - public start(roomName: string, playerName:string, jwt?: string, config?: object, interfaceConfig?: object): void { + public start(roomName: string, playerName:string, jwt?: string, config?: object, interfaceConfig?: object, jitsiUrl?: string): void { //save previous config this.previousConfigMeet = getDefaultConfig(); - coWebsiteManager.insertCoWebsite((cowebsiteDiv => { + coWebsiteManager.insertCoWebsite((async cowebsiteDiv => { // 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 @@ -93,7 +94,12 @@ class JitsiFactory { // clear jitsi local storage before starting a new conference. window.localStorage.removeItem("jitsiLocalStorage"); - const domain = JITSI_URL; + const domain = jitsiUrl || JITSI_URL; + if (domain === undefined) { + throw new Error('Missing JITSI_URL environment variable or jitsiUrl parameter in the map.') + } + await this.loadJitsiScript(domain); + const options: any = { // eslint-disable-line @typescript-eslint/no-explicit-any roomName: roomName, jwt: jwt, @@ -157,6 +163,32 @@ class JitsiFactory { mediaManager.enableCamera(); } } + + private async loadJitsiScript(domain: string): Promise { + return new Promise((resolve, reject) => { + if (this.jitsiScriptLoaded) { + resolve(); + return; + } + + this.jitsiScriptLoaded = true; + + // Load Jitsi if the environment variable is set. + const jitsiScript = document.createElement('script'); + jitsiScript.src = 'https://' + domain + '/external_api.js'; + jitsiScript.onload = () => { + resolve(); + } + jitsiScript.onerror = () => { + reject(); + } + + document.head.appendChild(jitsiScript); + + }) + + + } } export const jitsiFactory = new JitsiFactory(); diff --git a/front/src/index.ts b/front/src/index.ts index 94b1df43..b1da5ce4 100644 --- a/front/src/index.ts +++ b/front/src/index.ts @@ -15,13 +15,6 @@ import {MenuScene} from "./Phaser/Menu/MenuScene"; import {localUserStore} from "./Connexion/LocalUserStore"; import {ErrorScene} from "./Phaser/Reconnecting/ErrorScene"; -// Load Jitsi if the environment variable is set. -if (JITSI_URL) { - const jitsiScript = document.createElement('script'); - jitsiScript.src = 'https://' + JITSI_URL + '/external_api.js'; - document.head.appendChild(jitsiScript); -} - const {width, height} = coWebsiteManager.getGameSize(); const valueGameQuality = localUserStore.getGameQualityValue(); diff --git a/maps/tests/jitsi_custom_url.json b/maps/tests/jitsi_custom_url.json new file mode 100644 index 00000000..65e3be9f --- /dev/null +++ b/maps/tests/jitsi_custom_url.json @@ -0,0 +1,94 @@ +{ "compressionlevel":-1, + "editorsettings": + { + "export": + { + "target":"." + } + }, + "height":10, + "infinite":false, + "layers":[ + { + "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + "height":10, + "id":1, + "name":"floor", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":2, + "name":"start", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":10, + "id":5, + "name":"jitsiConf", + "opacity":1, + "properties":[ + { + "name":"jitsiRoom", + "type":"string", + "value":"myRoom" + }, + { + "name":"jitsiUrl", + "type":"string", + "value":"meet.jit.si" + }], + "type":"tilelayer", + "visible":true, + "width":10, + "x":0, + "y":0 + }, + { + "draworder":"topdown", + "id":3, + "name":"floorLayer", + "objects":[], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }], + "nextlayerid":6, + "nextobjectid":1, + "orientation":"orthogonal", + "renderorder":"right-down", + "tiledversion":"1.3.3", + "tileheight":32, + "tilesets":[ + { + "columns":11, + "firstgid":1, + "image":"tileset1.png", + "imageheight":352, + "imagewidth":352, + "margin":0, + "name":"tileset1", + "spacing":0, + "tilecount":121, + "tileheight":32, + "tilewidth":32 + }], + "tilewidth":32, + "type":"map", + "version":1.2, + "width":10 +} \ No newline at end of file From 20d3236e7363e28fd336d5f39b33fb199de243a7 Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Thu, 11 Mar 2021 22:19:21 +0100 Subject: [PATCH 02/10] Fix audio control box appearance --- front/dist/resources/style/style.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css index 05ff5a03..fda0c9dd 100644 --- a/front/dist/resources/style/style.css +++ b/front/dist/resources/style/style.css @@ -363,10 +363,14 @@ body { justify-content: center; } +.audioplayer > div { + padding-right: 1.2rem; +} + #audioplayerctrl { position: fixed; top: 0; - right: 50%; + right: calc(50% - 120px); padding: 0.3rem 0.5rem; color: white; transition: transform 0.5s; From 5a7e67f5dfa6407b1c6491883d7387916f8600c1 Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Thu, 11 Mar 2021 22:31:06 +0100 Subject: [PATCH 03/10] Reflect volume change in audio control --- front/src/WebRtc/AudioManager.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/front/src/WebRtc/AudioManager.ts b/front/src/WebRtc/AudioManager.ts index 24fb74a1..735c42c3 100644 --- a/front/src/WebRtc/AudioManager.ts +++ b/front/src/WebRtc/AudioManager.ts @@ -9,6 +9,7 @@ enum audioStates { const audioPlayerDivId = "audioplayer"; const audioPlayerCtrlId = "audioplayerctrl"; +const audioPlayerVolId = "audioplayer_volume"; const animationTime = 500; class AudioManager { @@ -17,6 +18,7 @@ class AudioManager { private audioPlayerDiv: HTMLDivElement; private audioPlayerCtrl: HTMLDivElement; private audioPlayerElem: HTMLAudioElement | undefined; + private audioPlayerVol: HTMLInputElement; private volume = 1; private muted = false; @@ -26,16 +28,17 @@ class AudioManager { constructor() { this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail(audioPlayerDivId); this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail(audioPlayerCtrlId); + this.audioPlayerVol = HtmlUtils.getElementByIdOrFail(audioPlayerVolId); const storedVolume = localStorage.getItem('volume') if (storedVolume === null) { this.setVolume(1); } else { this.volume = parseFloat(storedVolume); - HtmlUtils.getElementByIdOrFail('audioplayer_volume').value = storedVolume; + this.audioPlayerVol.value = storedVolume; } - HtmlUtils.getElementByIdOrFail('audioplayer_volume').value = '' + this.volume; + this.audioPlayerVol.value = '' + this.volume; } public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void { @@ -77,6 +80,7 @@ class AudioManager { private changeVolume(talking = false): void { if (!isUndefined(this.audioPlayerElem)) { this.audioPlayerElem.volume = this.naturalVolume(talking && this.decreaseWhileTalking); + this.audioPlayerVol.value = '' + this.audioPlayerElem.volume; this.audioPlayerElem.muted = this.muted; } } @@ -127,8 +131,7 @@ class AudioManager { } } - const volumeElem = HtmlUtils.getElementByIdOrFail('audioplayer_volume'); - volumeElem.oninput = (ev: Event)=> { + this.audioPlayerVol.oninput = (ev: Event)=> { this.setVolume(parseFloat((ev.currentTarget).value)); this.changeVolume(); From 132c6c9ad666e8b3d5cf176752fc23c4729a30c2 Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Thu, 11 Mar 2021 22:51:42 +0100 Subject: [PATCH 04/10] Fix volume auto-reduction in conversations --- front/dist/index.tmpl.html | 2 +- front/src/WebRtc/AudioManager.ts | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/front/dist/index.tmpl.html b/front/dist/index.tmpl.html index eeb8bb5b..3d1b784f 100644 --- a/front/dist/index.tmpl.html +++ b/front/dist/index.tmpl.html @@ -97,7 +97,7 @@
diff --git a/front/src/WebRtc/AudioManager.ts b/front/src/WebRtc/AudioManager.ts index 735c42c3..01d978fe 100644 --- a/front/src/WebRtc/AudioManager.ts +++ b/front/src/WebRtc/AudioManager.ts @@ -78,18 +78,21 @@ class AudioManager { } private changeVolume(talking = false): void { - if (!isUndefined(this.audioPlayerElem)) { - this.audioPlayerElem.volume = this.naturalVolume(talking && this.decreaseWhileTalking); - this.audioPlayerVol.value = '' + this.audioPlayerElem.volume; - this.audioPlayerElem.muted = this.muted; + if (isUndefined(this.audioPlayerElem)) { + return; } - } - private naturalVolume(makeSofter: boolean = false): number { - const volume = this.volume - const retVol = makeSofter && !this.volumeReduced ? Math.pow(volume * 0.5, 3) : volume - this.volumeReduced = makeSofter - return retVol; + const reduceVolume = talking && this.decreaseWhileTalking; + if (reduceVolume && !this.volumeReduced) { + this.volume *= 0.5; + } else if (!reduceVolume && this.volumeReduced) { + this.volume *= 2.0; + } + this.volumeReduced = reduceVolume; + + this.audioPlayerElem.volume = this.volume; + this.audioPlayerVol.value = '' + this.volume; + this.audioPlayerElem.muted = this.muted; } private setVolume(volume: number): void { From fdbcd98a9acc7b89e225c8294a881b00b4892d23 Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Thu, 11 Mar 2021 22:34:49 +0100 Subject: [PATCH 05/10] Implement audio volume and loop properties --- front/src/Phaser/Game/GameScene.ts | 10 +++++++--- front/src/WebRtc/AudioManager.ts | 8 ++++---- front/src/WebRtc/LayoutManager.ts | 3 +++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 512319c6..4a8712ae 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -29,7 +29,9 @@ import { ON_ACTION_TRIGGER_BUTTON, TRIGGER_JITSI_PROPERTIES, TRIGGER_WEBSITE_PROPERTIES, - WEBSITE_MESSAGE_PROPERTIES + WEBSITE_MESSAGE_PROPERTIES, + AUDIO_VOLUME_PROPERTY, + AUDIO_LOOP_PROPERTY } from "../../WebRtc/LayoutManager"; import {GameMap} from "./GameMap"; import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager"; @@ -661,8 +663,10 @@ export class GameScene extends ResizableScene implements CenterListener { this.connection.setSilent(true); } }); - this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => { - newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl()); + this.gameMap.onPropertyChange('playAudio', (newValue, oldValue, allProps) => { + const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number|undefined; + const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean|undefined; + newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl(), volume, loop); }); this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => { diff --git a/front/src/WebRtc/AudioManager.ts b/front/src/WebRtc/AudioManager.ts index 01d978fe..924f1fac 100644 --- a/front/src/WebRtc/AudioManager.ts +++ b/front/src/WebRtc/AudioManager.ts @@ -41,7 +41,7 @@ class AudioManager { this.audioPlayerVol.value = '' + this.volume; } - public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void { + public playAudio(url: string|number|boolean, mapDirUrl: string, volume: number|undefined, loop=false): void { const audioPath = url as string; let realAudioPath = ''; @@ -53,7 +53,7 @@ class AudioManager { realAudioPath = mapDirUrl + '/' + url; } - this.loadAudio(realAudioPath); + this.loadAudio(realAudioPath, volume); if (loop) { this.loop(); @@ -100,8 +100,7 @@ class AudioManager { localStorage.setItem('volume', '' + volume); } - - private loadAudio(url: string): void { + private loadAudio(url: string, volume: number|undefined): void { this.load(); /* Solution 1, remove whole audio player */ @@ -119,6 +118,7 @@ class AudioManager { this.audioPlayerElem.append(srcElem); this.audioPlayerDiv.append(this.audioPlayerElem); + this.volume = volume ? Math.min(volume, this.volume) : this.volume; this.changeVolume(); this.audioPlayerElem.play(); diff --git a/front/src/WebRtc/LayoutManager.ts b/front/src/WebRtc/LayoutManager.ts index 91d78798..233b5327 100644 --- a/front/src/WebRtc/LayoutManager.ts +++ b/front/src/WebRtc/LayoutManager.ts @@ -31,6 +31,9 @@ export const TRIGGER_JITSI_PROPERTIES = 'jitsiTrigger'; export const WEBSITE_MESSAGE_PROPERTIES = 'openWebsiteTriggerMessage'; export const JITSI_MESSAGE_PROPERTIES = 'jitsiTriggerMessage'; +export const AUDIO_VOLUME_PROPERTY = 'audioVolume'; +export const AUDIO_LOOP_PROPERTY = 'audioLoop'; + /** * This class is in charge of the video-conference layout. * It receives positioning requests for videos and does its best to place them on the screen depending on the active layout mode. From 5bd6f49846addd5b10e80be416b1dcd392267d7c Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Thu, 11 Mar 2021 22:39:45 +0100 Subject: [PATCH 06/10] Fix (now legacy) 'playAudioLoop' property --- front/src/Phaser/Game/GameScene.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 4a8712ae..ba87ba23 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -668,11 +668,10 @@ export class GameScene extends ResizableScene implements CenterListener { const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean|undefined; newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl(), volume, loop); }); - + // TODO: This legacy property should be removed at some point this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => { - newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl()); + newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl(), undefined, true); }); - } private getMapDirUrl(): string { From e6accd711d6160016b67bedd70318cc2d3884a51 Mon Sep 17 00:00:00 2001 From: TabascoEye Date: Fri, 29 Jan 2021 14:42:13 +0100 Subject: [PATCH 07/10] Store muted setting of audio player in local storage This commit was originally authored by @TabascoEye, then rebased and improved by @pizkaz: * refactors local user storage, adding audio player settings * stores "muted" state of audio player in local store --- front/src/Connexion/LocalUserStore.ts | 61 +++++++++++++++++---------- front/src/WebRtc/AudioManager.ts | 27 ++++++------ 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/front/src/Connexion/LocalUserStore.ts b/front/src/Connexion/LocalUserStore.ts index 8ac8c7b2..1e4267de 100644 --- a/front/src/Connexion/LocalUserStore.ts +++ b/front/src/Connexion/LocalUserStore.ts @@ -1,12 +1,15 @@ import {LocalUser} from "./LocalUser"; -const characterLayersKey = 'characterLayers'; -const gameQualityKey = 'gameQuality'; -const videoQualityKey = 'videoQuality'; +const playerNameKey = 'playerName'; +const selectedPlayerKey = 'selectedPlayer'; +const customCursorPositionKey = 'customCursorPosition'; +const characterLayersKey = 'characterLayers'; +const gameQualityKey = 'gameQuality'; +const videoQualityKey = 'videoQuality'; +const audioPlayerVolumeKey = 'audioVolume'; +const audioPlayerMuteKey = 'audioMute'; -//todo: add localstorage fallback class LocalUserStore { - saveUser(localUser: LocalUser) { localStorage.setItem('localUser', JSON.stringify(localUser)); } @@ -14,48 +17,62 @@ class LocalUserStore { const data = localStorage.getItem('localUser'); return data ? JSON.parse(data) : null; } - + setName(name:string): void { - window.localStorage.setItem('playerName', name); + localStorage.setItem(playerNameKey, name); } getName(): string { - return window.localStorage.getItem('playerName') ?? ''; + return localStorage.getItem(playerNameKey) || ''; } setPlayerCharacterIndex(playerCharacterIndex: number): void { - window.localStorage.setItem('selectedPlayer', ''+playerCharacterIndex); + localStorage.setItem(selectedPlayerKey, ''+playerCharacterIndex); } getPlayerCharacterIndex(): number { - return parseInt(window.localStorage.getItem('selectedPlayer') || ''); + return parseInt(localStorage.getItem(selectedPlayerKey) || ''); } setCustomCursorPosition(activeRow:number, selectedLayers: number[]): void { - window.localStorage.setItem('customCursorPosition', JSON.stringify({activeRow, selectedLayers})); + localStorage.setItem(customCursorPositionKey, JSON.stringify({activeRow, selectedLayers})); } getCustomCursorPosition(): {activeRow:number, selectedLayers:number[]}|null { - return JSON.parse(window.localStorage.getItem('customCursorPosition') || "null"); + return JSON.parse(localStorage.getItem(customCursorPositionKey) || "null"); } setCharacterLayers(layers: string[]): void { - window.localStorage.setItem(characterLayersKey, JSON.stringify(layers)); + localStorage.setItem(characterLayersKey, JSON.stringify(layers)); } getCharacterLayers(): string[]|null { - return JSON.parse(window.localStorage.getItem(characterLayersKey) || "null"); - } - - getGameQualityValue(): number { - return parseInt(window.localStorage.getItem(gameQualityKey) || '') || 60; + return JSON.parse(localStorage.getItem(characterLayersKey) || "null"); } + setGameQualityValue(value: number): void { localStorage.setItem(gameQualityKey, '' + value); } - - getVideoQualityValue(): number { - return parseInt(window.localStorage.getItem(videoQualityKey) || '') || 20; + getGameQualityValue(): number { + return parseInt(localStorage.getItem(gameQualityKey) || '60'); } + setVideoQualityValue(value: number): void { localStorage.setItem(videoQualityKey, '' + value); } + getVideoQualityValue(): number { + return parseInt(localStorage.getItem(videoQualityKey) || '20'); + } + + setAudioPlayerVolume(value: number): void { + localStorage.setItem(audioPlayerVolumeKey, '' + value); + } + getAudioPlayerVolume(): number { + return parseFloat(localStorage.getItem(audioPlayerVolumeKey) || '1'); + } + + setAudioPlayerMuted(value: boolean): void { + localStorage.setItem(audioPlayerMuteKey, value.toString()); + } + getAudioPlayerMuted(): boolean { + return localStorage.getItem(audioPlayerMuteKey) === 'true'; + } } -export const localUserStore = new LocalUserStore(); \ No newline at end of file +export const localUserStore = new LocalUserStore(); diff --git a/front/src/WebRtc/AudioManager.ts b/front/src/WebRtc/AudioManager.ts index 924f1fac..60255a77 100644 --- a/front/src/WebRtc/AudioManager.ts +++ b/front/src/WebRtc/AudioManager.ts @@ -1,5 +1,6 @@ import {HtmlUtils} from "./HtmlUtils"; import {isUndefined} from "generic-type-guard"; +import {localUserStore} from "../Connexion/LocalUserStore"; enum audioStates { closed = 0, @@ -10,6 +11,7 @@ enum audioStates { const audioPlayerDivId = "audioplayer"; const audioPlayerCtrlId = "audioplayerctrl"; const audioPlayerVolId = "audioplayer_volume"; +const audioPlayerMuteId = "audioplayer_volume_icon_playing"; const animationTime = 500; class AudioManager { @@ -19,6 +21,7 @@ class AudioManager { private audioPlayerCtrl: HTMLDivElement; private audioPlayerElem: HTMLAudioElement | undefined; private audioPlayerVol: HTMLInputElement; + private audioPlayerMute: HTMLInputElement; private volume = 1; private muted = false; @@ -29,16 +32,15 @@ class AudioManager { this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail(audioPlayerDivId); this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail(audioPlayerCtrlId); this.audioPlayerVol = HtmlUtils.getElementByIdOrFail(audioPlayerVolId); + this.audioPlayerMute = HtmlUtils.getElementByIdOrFail(audioPlayerMuteId); - const storedVolume = localStorage.getItem('volume') - if (storedVolume === null) { - this.setVolume(1); - } else { - this.volume = parseFloat(storedVolume); - this.audioPlayerVol.value = storedVolume; - } - + this.volume = localUserStore.getAudioPlayerVolume(); this.audioPlayerVol.value = '' + this.volume; + + this.muted = localUserStore.getAudioPlayerMuted(); + if (this.muted) { + this.audioPlayerMute.classList.add('muted'); + } } public playAudio(url: string|number|boolean, mapDirUrl: string, volume: number|undefined, loop=false): void { @@ -97,7 +99,7 @@ class AudioManager { private setVolume(volume: number): void { this.volume = volume; - localStorage.setItem('volume', '' + volume); + localUserStore.setAudioPlayerVolume(volume); } private loadAudio(url: string, volume: number|undefined): void { @@ -123,14 +125,15 @@ class AudioManager { this.audioPlayerElem.play(); const muteElem = HtmlUtils.getElementByIdOrFail('audioplayer_mute'); - muteElem.onclick = (ev: Event)=> { + muteElem.onclick = (ev: Event) => { this.muted = !this.muted; this.changeVolume(); + localUserStore.setAudioPlayerMuted(this.muted); if (this.muted) { - HtmlUtils.getElementByIdOrFail('audioplayer_volume_icon_playing').classList.add('muted'); + this.audioPlayerMute.classList.add('muted'); } else { - HtmlUtils.getElementByIdOrFail('audioplayer_volume_icon_playing').classList.remove('muted'); + this.audioPlayerMute.classList.remove('muted'); } } From 599fdd6ceb80695e32a761c6a40bb6b270ec199b Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Fri, 19 Mar 2021 15:03:55 +0100 Subject: [PATCH 08/10] Fix group icons and audio attenuation --- front/src/Phaser/Game/GameScene.ts | 8 ++++---- front/src/WebRtc/SimplePeer.ts | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index ba87ba23..f350aff7 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -457,16 +457,12 @@ export class GameScene extends ResizableScene implements CenterListener { }); this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => { - audioManager.decreaseVolume(); this.shareGroupPosition(groupPositionMessage); - this.openChatIcon.setVisible(true); }) this.connection.onGroupDeleted((groupId: number) => { - audioManager.restoreVolume(); try { this.deleteGroup(groupId); - this.openChatIcon.setVisible(false); } catch (e) { console.error(e); } @@ -519,11 +515,15 @@ export class GameScene extends ResizableScene implements CenterListener { onConnect(user: UserSimplePeerInterface) { self.presentationModeSprite.setVisible(true); self.chatModeSprite.setVisible(true); + self.openChatIcon.setVisible(true); + audioManager.decreaseVolume(); }, onDisconnect(userId: number) { if (self.simplePeer.getNbConnections() === 0) { self.presentationModeSprite.setVisible(false); self.chatModeSprite.setVisible(false); + self.openChatIcon.setVisible(false); + audioManager.restoreVolume(); } } }) diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts index 2baeef11..73a87d14 100644 --- a/front/src/WebRtc/SimplePeer.ts +++ b/front/src/WebRtc/SimplePeer.ts @@ -63,7 +63,7 @@ export class SimplePeer { } public getNbConnections(): number { - return this.PeerConnectionArray.size; + return this.Users.length; } /** @@ -230,9 +230,6 @@ export class SimplePeer { this.closeScreenSharingConnection(userId); - for (const peerConnectionListener of this.peerConnectionListeners) { - peerConnectionListener.onDisconnect(userId); - } const userIndex = this.Users.findIndex(user => user.userId === userId); if(userIndex < 0){ throw 'Couln\'t delete user'; @@ -250,6 +247,10 @@ export class SimplePeer { this.PeerScreenSharingConnectionArray.delete(userId); } } + + for (const peerConnectionListener of this.peerConnectionListeners) { + peerConnectionListener.onDisconnect(userId); + } } /** From 821f91e996281252ccb1536b0472ad808bcbcca9 Mon Sep 17 00:00:00 2001 From: PizZaKatZe Date: Tue, 9 Feb 2021 21:00:55 +0100 Subject: [PATCH 09/10] Finer steps for audio volume --- front/dist/index.tmpl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/dist/index.tmpl.html b/front/dist/index.tmpl.html index 3d1b784f..55adcebc 100644 --- a/front/dist/index.tmpl.html +++ b/front/dist/index.tmpl.html @@ -92,7 +92,7 @@
- +
From 23c33b29717d61a4f9ae54237bb05b2112ab449a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 22 Mar 2021 22:18:06 +0100 Subject: [PATCH 10/10] Adding Discord badge to the README This should be merged only when the Discord widget mode is enabled on the server (otherwise the number of current users is not displayed) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26f1e816..cf640d9c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](https://github.com/thecodingmachine/workadventure/workflows/Continuous%20Integration/badge.svg) +![](https://github.com/thecodingmachine/workadventure/workflows/Continuous%20Integration/badge.svg) [![Discord](https://img.shields.io/discord/821338762134290432?label=Discord)](https://discord.gg/JVVhXzcE) ![WorkAdventure landscape image](README-INTRO.jpg)