diff --git a/front/dist/index.tmpl.html b/front/dist/index.tmpl.html index 062622b8..c4763b6e 100644 --- a/front/dist/index.tmpl.html +++ b/front/dist/index.tmpl.html @@ -48,20 +48,27 @@
+
+ + + + + +
-
- - +
+ +
-
- - +
+ +
diff --git a/front/dist/resources/html/EnableCameraScene.html b/front/dist/resources/html/EnableCameraScene.html index 0763d7dd..2dda6cc1 100644 --- a/front/dist/resources/html/EnableCameraScene.html +++ b/front/dist/resources/html/EnableCameraScene.html @@ -48,7 +48,7 @@ text-align: center; margin: 0; position: absolute; - top: 44vh; + top: 40vh; width: 100%; } #enableCameraScene button { diff --git a/front/dist/resources/html/helpCameraSettings.html b/front/dist/resources/html/helpCameraSettings.html index a04668fe..ee8e16e2 100644 --- a/front/dist/resources/html/helpCameraSettings.html +++ b/front/dist/resources/html/helpCameraSettings.html @@ -60,6 +60,9 @@ font-size: 8px; margin: 0px 20px; } + #helpCameraSettings section p a{ + font-size: 8px; + } #helpCameraSettings section p.err{ color: #ff0000; } @@ -95,6 +98,10 @@

If you prefer to continue without allowing camera and microphone access, click on Continue

+ +
Refresh diff --git a/front/dist/resources/style/mobile-style.scss b/front/dist/resources/style/mobile-style.scss index d9ed4b2e..21753ebd 100644 --- a/front/dist/resources/style/mobile-style.scss +++ b/front/dist/resources/style/mobile-style.scss @@ -23,27 +23,17 @@ } .btn-cam-action { + min-width: 150px; + &:hover{ transform: translateY(20px); } div { + margin: 0 1%; &:hover { background-color: #666; } - - bottom: 30px; - - &.btn-micro { - right: 0; - } - - &.btn-monitor { - right: 130px; - } - - &.btn-video { - right: 65px; - } + margin-bottom: 30px; } } diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css index 97e363f9..213b00f2 100644 --- a/front/dist/resources/style/style.css +++ b/front/dist/resources/style/style.css @@ -98,7 +98,7 @@ body .message-info.warning{ } .video-container button.report:hover { - width: 150px; + width: 160px; } .video-container button.report img{ @@ -126,6 +126,7 @@ body .message-info.warning{ .video-container video{ height: 100%; + cursor: url('/resources/logos/cursor_pointer.png'), pointer; } .video-container video:focus{ @@ -141,7 +142,7 @@ body .message-info.warning{ right: 15px; bottom: 30px; border-radius: 15px 15px 15px 15px; - max-height: 200px; + max-height: 20%; } video#myCamVideo{ @@ -153,19 +154,60 @@ video#myCamVideo{ /*height: 113px;*/ } +.sound-progress{ + display: none; + position: absolute; + right: 14px; + top: calc(50% - 5px); +} +.sound-progress.active{ + display: table-column; +} +.sound-progress span{ + position: absolute; + color: black; + background-color: #00000020; + width: 5px; + height: 5px; + border-radius: 50%; +} +.sound-progress span.active{ + background-color: #00c3ff66 +} +.sound-progress span:nth-child(1){ + top: calc(50% + 20px); +} +.sound-progress span:nth-child(2){ + top: calc(50% + 10px); +} +.sound-progress span:nth-child(3){ + top: calc(50% - 0px); +} +.sound-progress span:nth-child(4){ + top: calc(50% - 10px); +} +.sound-progress span:nth-child(5){ + top: calc(50% - 20px); +} .btn-cam-action { pointer-events: all; position: absolute; - bottom: 0px; - right: 0px; - width: 450px; - height: 150px; + display: inline-flex; + bottom: 10px; + right: 15px; + width: 15vw; + height: 40px; + text-align: center; + align-content: center; + align-items: center; + justify-content: center; + justify-items: center; } /*btn animation*/ .btn-cam-action div{ cursor: url('/resources/logos/cursor_pointer.png'), pointer; - position: absolute; + /*position: absolute;*/ border: solid 0px black; width: 44px; height: 44px; @@ -174,7 +216,8 @@ video#myCamVideo{ border-radius: 48px; transform: translateY(20px); transition-timing-function: ease-in-out; - bottom: 20px; + margin-bottom: 20px; + margin: 0 4%; } .btn-cam-action div.disabled { background: #d75555; @@ -193,17 +236,17 @@ video#myCamVideo{ .btn-micro{ pointer-events: auto; transition: all .3s; - right: 44px; + /*right: 44px;*/ } .btn-video{ pointer-events: auto; transition: all .25s; - right: 134px; + /*right: 134px;*/ } .btn-monitor{ pointer-events: auto; transition: all .2s; - right: 224px; + /*right: 224px;*/ } .btn-copy{ pointer-events: auto; @@ -497,7 +540,7 @@ input[type=range]:focus::-ms-fill-upper { position: absolute; width: 100%; height: 100%; - pointer-events: none; + pointer-events: all; /* TODO: DO WE NEED FLEX HERE???? WE WANT A SIDEBAR OF EXACTLY 25% (note: flex useful for direction!!!) */ } @@ -533,7 +576,7 @@ input[type=range]:focus::-ms-fill-upper { .sidebar { flex: 0 0 25%; display: flex; - pointer-events: none; + pointer-events: all; } .sidebar > div { @@ -547,6 +590,10 @@ input[type=range]:focus::-ms-fill-upper { margin: 0%; } +.sidebar > div video { + cursor: url('/resources/logos/cursor_pointer.png'), pointer; +} + /* Let's make sure videos are vertically centered if they need to be cropped */ .media-container { display: flex; @@ -1111,17 +1158,34 @@ div.action{ animation-iteration-count: infinite; animation-timing-function: ease-in-out; } +div.action.info, +div.action.warning, +div.action.danger{ + transition: all 1s ease; + animation: mymove 1s; + animation-iteration-count: infinite; + animation-timing-function: ease-in-out; +} div.action p.action-body{ + cursor: url('/resources/logos/cursor_pointer.png'), pointer; padding: 10px; background-color: #2d2d2dba; color: #fff; font-size: 14px; font-weight: 500; text-align: center; - max-width: 250px; - margin-left: calc(50% - 125px); + max-width: 350px; + margin-left: calc(50% - 175px); border-radius: 15px; } +div.action.warning p.action-body{ + background-color: #ff9800eb; + color: #000; +} +div.action.danger p.action-body{ + background-color: #da0000e3; + color: #000; +} .popUpElement{ font-family: 'Press Start 2P'; text-align: left; diff --git a/front/dist/static/images/favicons/manifest.json b/front/dist/static/images/favicons/manifest.json index 013d4a6a..47ad9377 100644 --- a/front/dist/static/images/favicons/manifest.json +++ b/front/dist/static/images/favicons/manifest.json @@ -1,41 +1,149 @@ { - "name": "App", - "icons": [ - { - "src": "\/android-icon-36x36.png", - "sizes": "36x36", - "type": "image\/png", - "density": "0.75" - }, - { - "src": "\/android-icon-48x48.png", - "sizes": "48x48", - "type": "image\/png", - "density": "1.0" - }, - { - "src": "\/android-icon-72x72.png", - "sizes": "72x72", - "type": "image\/png", - "density": "1.5" - }, - { - "src": "\/android-icon-96x96.png", - "sizes": "96x96", - "type": "image\/png", - "density": "2.0" - }, - { - "src": "\/android-icon-144x144.png", - "sizes": "144x144", - "type": "image\/png", - "density": "3.0" - }, - { - "src": "\/android-icon-192x192.png", - "sizes": "192x192", - "type": "image\/png", - "density": "4.0" - } - ] + "short_name": "WA", + "name": "WorkAdventure", + "icons": [ + { + "src": "/static/images/favicons/apple-icon-57x57.png", + "sizes": "57x57", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-60x60.png", + "sizes": "60x60", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-76x76.png", + "sizes": "76x76", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-114x114.png", + "sizes": "114x114", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-120x120.png", + "sizes": "120x120", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-152x152.png", + "sizes": "152x152", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/apple-icon-180x180.png", + "sizes": "180x180", + "type": "image\/png" + }, + { + "src": "/static/images/favicons/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "/static/images/favicons/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "/static/images/favicons/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + + { + "src": "/static/images/favicons/favicon-16x16.png", + "sizes": "16x16", + "type": "image\/png", + "density": "1" + }, + { + "src": "/static/images/favicons/favicon-32x32.png", + "sizes": "32x32", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "/static/images/favicons/favicon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + + { + "src": "/static/images/favicons/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "1" + }, + { + "src": "/static/images/favicons/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1" + }, + { + "src": "/static/images/favicons/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "/static/images/favicons/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "/static/images/favicons/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "/static/images/favicons/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ], + "start_url": "/", + "background_color": "#000000", + "display_override": ["window-control-overlay", "minimal-ui"], + "display": "standalone", + "scope": "/", + "theme_color": "#000000", + "shortcuts": [ + { + "name": "WorkAdventures", + "short_name": "WA", + "description": "WorkAdventure application", + "url": "/", + "icons": [{ "src": "/static/images/favicons/android-icon-192x192.png", "sizes": "192x192" }] + } + ], + "description": "WorkAdventure application", + "screenshots": [], + "related_applications": [{ + "platform": "web", + "url": "https://workadventu.re" + }, { + "platform": "play", + "url": "https://play.workadventu.re" + }] } \ No newline at end of file diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index da10a8ca..6047d430 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -89,10 +89,7 @@ export class GameManager { console.log('starting '+ (this.currentGameSceneName || this.startRoom.id)) scenePlugin.start(this.currentGameSceneName || this.startRoom.id); scenePlugin.launch(MenuSceneName); - - if (!localUserStore.getHelpCameraSettingsShown()) { - scenePlugin.launch(HelpCameraSettingsSceneName);//700 - } + scenePlugin.launch(HelpCameraSettingsSceneName);//700 } public gameSceneIsCreated(scene: GameScene) { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 71d7868f..c433ed0f 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1200,7 +1200,7 @@ ${escapedMessage} * @param delta The delta time in ms since the last frame. This is a smoothed and capped value based on the FPS rate. */ update(time: number, delta: number) : void { - mediaManager.setLastUpdateScene(); + mediaManager.updateScene(); this.currentTick = time; this.CurrentPlayer.moveUser(delta); diff --git a/front/src/Phaser/Login/EnableCameraScene.ts b/front/src/Phaser/Login/EnableCameraScene.ts index 603da7b9..917dd44b 100644 --- a/front/src/Phaser/Login/EnableCameraScene.ts +++ b/front/src/Phaser/Login/EnableCameraScene.ts @@ -247,8 +247,7 @@ export class EnableCameraScene extends Phaser.Scene { update(time: number, delta: number): void { this.soundMeterSprite.setVolume(this.soundMeter.getVolume()); - - mediaManager.setLastUpdateScene(); + mediaManager.updateScene(); const middleX = this.getMiddleX(); this.tweens.add({ diff --git a/front/src/Phaser/Menu/HelpCameraSettingsScene.ts b/front/src/Phaser/Menu/HelpCameraSettingsScene.ts index cc6f40c6..f7dd5c2a 100644 --- a/front/src/Phaser/Menu/HelpCameraSettingsScene.ts +++ b/front/src/Phaser/Menu/HelpCameraSettingsScene.ts @@ -21,7 +21,6 @@ export class HelpCameraSettingsScene extends Phaser.Scene { } create(){ - localUserStore.setHelpCameraSettingsShown(); this.createHelpCameraSettings(); } @@ -31,6 +30,9 @@ export class HelpCameraSettingsScene extends Phaser.Scene { this.revealMenusAfterInit(this.helpCameraSettingsElement, helpCameraSettings); this.helpCameraSettingsElement.addListener('click'); this.helpCameraSettingsElement.on('click', (event:MouseEvent) => { + if((event?.target as HTMLInputElement).id === 'mailto') { + return; + } event.preventDefault(); if((event?.target as HTMLInputElement).id === 'helpCameraSettingsFormRefresh') { window.location.reload(); @@ -39,18 +41,27 @@ export class HelpCameraSettingsScene extends Phaser.Scene { } }); - if(!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video){ + if(!localUserStore.getHelpCameraSettingsShown() && (!mediaManager.constraintsMedia.audio || !mediaManager.constraintsMedia.video)){ this.openHelpCameraSettingsOpened(); + localUserStore.setHelpCameraSettingsShown(); } + + mediaManager.setHelpCameraSettingsCallBack(() => { + this.openHelpCameraSettingsOpened(); + }); } private openHelpCameraSettingsOpened(): void{ HtmlUtils.getElementByIdOrFail('webRtcSetup').style.display = 'none'; this.helpCameraSettingsOpened = true; - if(window.navigator.userAgent.includes('Firefox')){ - HtmlUtils.getElementByIdOrFail('browserHelpSetting').innerHTML =''; - }else if(window.navigator.userAgent.includes('Chrome')){ - HtmlUtils.getElementByIdOrFail('browserHelpSetting').innerHTML =''; + try{ + if(window.navigator.userAgent.includes('Firefox')){ + HtmlUtils.getElementByIdOrFail('browserHelpSetting').innerHTML =''; + }else if(window.navigator.userAgent.includes('Chrome')){ + HtmlUtils.getElementByIdOrFail('browserHelpSetting').innerHTML =''; + } + }catch(err) { + console.error('openHelpCameraSettingsOpened => getElementByIdOrFail => error', err); } const middleY = this.getMiddleY(); const middleX = this.getMiddleX(); @@ -66,13 +77,13 @@ export class HelpCameraSettingsScene extends Phaser.Scene { private closeHelpCameraSettingsOpened(): void{ const middleX = this.getMiddleX(); - const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement; + /*const helpCameraSettingsInfo = this.helpCameraSettingsElement.getChildByID('helpCameraSettings') as HTMLParagraphElement; helpCameraSettingsInfo.innerText = ''; - helpCameraSettingsInfo.style.display = 'none'; + helpCameraSettingsInfo.style.display = 'none';*/ this.helpCameraSettingsOpened = false; this.tweens.add({ targets: this.helpCameraSettingsElement, - y: -400, + y: -1000, x: middleX, duration: 1000, ease: 'Power3', @@ -89,15 +100,17 @@ export class HelpCameraSettingsScene extends Phaser.Scene { } update(time: number, delta: number): void { - const middleX = this.getMiddleX(); - const middleY = this.getMiddleY(); - this.tweens.add({ - targets: this.helpCameraSettingsElement, - x: middleX, - y: middleY, - duration: 1000, - ease: 'Power3' - }); + if(this.helpCameraSettingsOpened){ + const middleX = this.getMiddleX(); + const middleY = this.getMiddleY(); + this.tweens.add({ + targets: this.helpCameraSettingsElement, + x: middleX, + y: middleY, + duration: 1000, + ease: 'Power3' + }); + } } public onResize(ev: UIEvent): void { diff --git a/front/src/WebRtc/LayoutManager.ts b/front/src/WebRtc/LayoutManager.ts index a0b805d4..eed12333 100644 --- a/front/src/WebRtc/LayoutManager.ts +++ b/front/src/WebRtc/LayoutManager.ts @@ -346,7 +346,7 @@ class LayoutManager { userInputManager.addSpaceEventListner(callBack); } - public removeActionButton(id: string, userInputManager: UserInputManager){ + public removeActionButton(id: string, userInputManager?: UserInputManager){ //delete previous element const previousDiv = this.actionButtonInformation.get(id); if(previousDiv){ @@ -354,10 +354,45 @@ class LayoutManager { this.actionButtonInformation.delete(id); } const previousEventCallback = this.actionButtonTrigger.get(id); - if(previousEventCallback){ + if(previousEventCallback && userInputManager){ userInputManager.removeSpaceEventListner(previousEventCallback); } } + + public addInformation(id: string, text: string, callBack?: Function, userInputManager?: UserInputManager){ + //delete previous element + for ( const [key, value] of this.actionButtonInformation ) { + this.removeActionButton(key, userInputManager); + } + + //create div and text html component + const p = document.createElement('p'); + p.classList.add('action-body'); + p.innerText = text; + + const div = document.createElement('div'); + div.classList.add('action'); + div.classList.add(id); + div.id = id; + div.appendChild(p); + + this.actionButtonInformation.set(id, div); + + const mainContainer = HtmlUtils.getElementByIdOrFail('main-container'); + mainContainer.appendChild(div); + //add trigger action + if(callBack){ + div.onpointerdown = () => { + callBack(); + this.removeActionButton(id, userInputManager); + }; + } + + //remove it after 10 sec + setTimeout(() => { + this.removeActionButton(id, userInputManager); + }, 10000) + } } const layoutManager = new LayoutManager(); diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index 09386970..d9a91940 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -4,6 +4,8 @@ import {discussionManager, SendMessageCallback} from "./DiscussionManager"; import {UserInputManager} from "../Phaser/UserInput/UserInputManager"; import {localUserStore} from "../Connexion/LocalUserStore"; import {UserSimplePeerInterface} from "./SimplePeer"; +import {SoundMeter} from "../Phaser/Components/SoundMeter"; + declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any let videoConstraint: boolean|MediaTrackConstraints = { @@ -26,6 +28,7 @@ export type StartScreenSharingCallback = (media: MediaStream) => void; export type StopScreenSharingCallback = (media: MediaStream) => void; export type ReportCallback = (message: string) => void; export type ShowReportCallBack = (userId: string, userName: string|undefined) => void; +export type HelpCameraSettingsCallBack = () => void; // TODO: Split MediaManager in 2 classes: MediaManagerUI (in charge of HTML) and MediaManager (singleton in charge of the camera only) export class MediaManager { @@ -40,6 +43,7 @@ export class MediaManager { microphoneClose: HTMLImageElement; microphone: HTMLImageElement; webrtcInAudio: HTMLAudioElement; + mySoundMeterElement: HTMLDivElement; private webrtcOutAudio: HTMLAudioElement; constraintsMedia : MediaStreamConstraints = { audio: audioConstraint, @@ -49,6 +53,8 @@ export class MediaManager { startScreenSharingCallBacks : Set = new Set(); stopScreenSharingCallBacks : Set = new Set(); showReportModalCallBacks : Set = new Set(); + helpCameraSettingsCallBacks : Set = new Set(); + private microphoneBtn: HTMLDivElement; private cinemaBtn: HTMLDivElement; private monitorBtn: HTMLDivElement; @@ -63,6 +69,12 @@ export class MediaManager { private triggerCloseJistiFrame : Map = new Map(); + private userInputManager?: UserInputManager; + + private mySoundMeter?: SoundMeter|null; + private soundMeters: Map = new Map(); + private soundMeterElements: Map = new Map(); + constructor() { this.myCamVideo = HtmlUtils.getElementByIdOrFail('myCamVideo'); @@ -121,10 +133,16 @@ export class MediaManager { this.pingCameraStatus(); this.checkActiveUser(); //todo: desactivated in case of bug + + this.mySoundMeterElement = (HtmlUtils.getElementByIdOrFail('mySoundMeter')); + this.mySoundMeterElement.childNodes.forEach((value: ChildNode, index) => { + this.mySoundMeterElement.children.item(index)?.classList.remove('active'); + }); } - public setLastUpdateScene(){ + public updateScene(){ this.lastUpdateScene = new Date(); + this.updateSoudMeter(); } public blurCamera() { @@ -225,6 +243,10 @@ export class MediaManager { }).catch((err) => { console.error(err); this.disableCameraStyle(); + + layoutManager.addInformation('warning', 'Camera access denied. Click here and check navigators permissions.', () => { + this.showHelpCameraSettingsCallBack(); + }, this.userInputManager); }); } @@ -253,6 +275,10 @@ export class MediaManager { }).catch((err) => { console.error(err); this.disableMicrophoneStyle(); + + layoutManager.addInformation('warning', 'Microphone access denied. Click here and check navigators permissions.', () => { + this.showHelpCameraSettingsCallBack(); + }, this.userInputManager); }); } @@ -324,6 +350,10 @@ export class MediaManager { this.monitorClose.style.display = "block"; this.monitor.style.display = "none"; this.monitorBtn.classList.remove("enabled"); + + layoutManager.addInformation('warning', 'Screen sharing access denied. Click here and check navigators permissions.', () => { + this.showHelpCameraSettingsCallBack(); + }, this.userInputManager); }); } @@ -402,13 +432,14 @@ export class MediaManager { } } - return this.getLocalStream().catch(() => { - console.info('Error get camera, trying with video option at null'); + return this.getLocalStream().catch((err) => { + console.info('Error get camera, trying with video option at null =>', err); this.disableCameraStyle(); return this.getLocalStream().then((stream : MediaStream) => { this.hasCamera = false; return stream; }).catch((err) => { + this.disableMicrophoneStyle(); console.info("error get media ", this.constraintsMedia.video, this.constraintsMedia.audio, err); throw err; }); @@ -425,6 +456,13 @@ export class MediaManager { return navigator.mediaDevices.getUserMedia(this.constraintsMedia).then((stream : MediaStream) => { this.localStream = stream; this.myCamVideo.srcObject = this.localStream; + + //init sound meter + this.mySoundMeter = null; + if(this.constraintsMedia.audio){ + this.mySoundMeter = new SoundMeter(); + this.mySoundMeter.connectToSource(stream, new AudioContext()); + } return stream; }).catch((err: Error) => { throw err; @@ -451,6 +489,7 @@ export class MediaManager { track.stop(); } } + this.mySoundMeter?.stop(); } setCamera(id: string): Promise { @@ -496,6 +535,13 @@ export class MediaManager { +
+ + + + + +
`; @@ -585,6 +631,12 @@ export class MediaManager { throw `Unable to find video for ${userId}`; } remoteVideo.srcObject = stream; + + //sound metter + const soundMeter = new SoundMeter(); + soundMeter.connectToSource(stream, new AudioContext()); + this.soundMeters.set(userId, soundMeter); + this.soundMeterElements.set(userId, HtmlUtils.getElementByIdOrFail('soundMeter-'+userId)); } addStreamRemoteScreenSharing(userId: string, stream : MediaStream){ // In the case of screen sharing (going both ways), we may need to create the HTML element if it does not exist yet @@ -600,6 +652,10 @@ export class MediaManager { layoutManager.remove(userId); this.remoteVideo.delete(userId); + this.soundMeters.get(userId)?.stop(); + this.soundMeters.delete(userId); + this.soundMeterElements.delete(userId); + //permit to remove user in discussion part this.removeParticipant(userId); } @@ -717,6 +773,7 @@ export class MediaManager { } public setUserInputManager(userInputManager : UserInputManager){ + this.userInputManager = userInputManager; discussionManager.setUserInputManager(userInputManager); } //check if user is active @@ -739,6 +796,57 @@ export class MediaManager { public setShowReportModalCallBacks(callback: ShowReportCallBack){ this.showReportModalCallBacks.add(callback); } + + public setHelpCameraSettingsCallBack(callback: HelpCameraSettingsCallBack){ + this.helpCameraSettingsCallBacks.add(callback); + } + + private showHelpCameraSettingsCallBack(){ + for(const callBack of this.helpCameraSettingsCallBacks){ + callBack(); + } + } + + updateSoudMeter(){ + 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); + if(!soundMeter || !soundMeterElement){ + return; + } + const volumeByUser = parseInt((soundMeter.getVolume() / 10).toFixed(0)); + this.setVolumeSoundMeter(volumeByUser, soundMeterElement); + } + }catch(err){ + //console.error(err); + } + } + + private setVolumeSoundMeter(volume: number, element: HTMLDivElement){ + if(volume <= 0 && !element.classList.contains('active')){ + return; + } + element.classList.remove('active'); + if(volume <= 0){ + return; + } + element.classList.add('active'); + element.childNodes.forEach((value: ChildNode, index) => { + const elementChildre = element.children.item(index); + if(!elementChildre){ + return; + } + elementChildre.classList.remove('active'); + if((index +1) > volume){ + return; + } + elementChildre.classList.add('active'); + }); + } } export const mediaManager = new MediaManager(); diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts index 73a87d14..7690c27d 100644 --- a/front/src/WebRtc/SimplePeer.ts +++ b/front/src/WebRtc/SimplePeer.ts @@ -82,15 +82,11 @@ export class SimplePeer { }); mediaManager.showGameOverlay(); - mediaManager.getCamera().then(() => { - + mediaManager.getCamera().finally(() => { //receive message start this.Connection.receiveWebrtcStart((message: UserSimplePeerInterface) => { this.receiveWebrtcStart(message); }); - - }).catch((err) => { - console.error("err", err); }); this.Connection.disconnectMessage((data: WebRtcDisconnectMessageInterface): void => { diff --git a/maps/Village/sol_intérieur.png b/maps/Village/sol_intérieur.png new file mode 100644 index 00000000..926a7dc2 Binary files /dev/null and b/maps/Village/sol_intérieur.png differ