diff --git a/front/src/Api/Events/PlaySoundEvent.ts b/front/src/Api/Events/PlaySoundEvent.ts new file mode 100644 index 00000000..49b657b1 --- /dev/null +++ b/front/src/Api/Events/PlaySoundEvent.ts @@ -0,0 +1,24 @@ +import * as tg from "generic-type-guard"; + + +const isSoundConfig = + new tg.IsInterface().withProperties({ + volume: tg.isOptional(tg.isNumber), + loop: tg.isOptional(tg.isBoolean), + mute: tg.isOptional(tg.isBoolean), + rate: tg.isOptional(tg.isNumber), + detune: tg.isOptional(tg.isNumber), + seek: tg.isOptional(tg.isNumber), + delay: tg.isOptional(tg.isNumber) + }).get(); + +export const isPlaySoundEvent = + new tg.IsInterface().withProperties({ + url: tg.isString, + config : isSoundConfig, + }).get(); + +/** + * A message sent from the iFrame to the game to add a message in the chat. + */ +export type PlaySoundEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index c875ebbb..7273d8cc 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,7 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import {isPlaySoundEvent, PlaySoundEvent} from "./Events/PlaySoundEvent"; /** @@ -52,6 +53,9 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + private readonly _playSoundStream: Subject = new Subject(); + public readonly playSoundStream = this._playSoundStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -89,6 +93,9 @@ class IframeListener { else if(payload.type === 'openCoWebSite' && isOpenCoWebsite(payload.data)) { scriptUtils.openCoWebsite(payload.data.url); } + else if(payload.type === 'playSound' && isPlaySoundEvent(payload.data)) { + this._playSoundStream.next(payload.data); + } else if(payload.type === 'closeCoWebSite') { scriptUtils.closeCoWebSite(); } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 9ecf9d43..0e4507fa 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -39,6 +39,7 @@ import {mediaManager} from "../../WebRtc/MediaManager"; import {ItemFactoryInterface} from "../Items/ItemFactoryInterface"; import {ActionableItem} from "../Items/ActionableItem"; import {UserInputManager} from "../UserInput/UserInputManager"; +import {soundManager} from "./SoundManager"; import {UserMovedMessage} from "../../Messages/generated/messages_pb"; import {ProtobufClientUtils} from "../../Network/ProtobufClientUtils"; import {connectionManager} from "../../Connexion/ConnectionManager"; @@ -793,6 +794,11 @@ ${escapedMessage} this.userInputManager.disableControls(); })); + this.iframeSubscriptionList.push(iframeListener.playSoundStream.subscribe((playSoundEvent)=> + { + soundManager.playSound(this.load,this.sound,playSoundEvent.url,playSoundEvent.config); + })) + this.iframeSubscriptionList.push(iframeListener.enablePlayerControlStream.subscribe(()=>{ this.userInputManager.restoreControls(); })); diff --git a/front/src/Phaser/Game/SoundManager.ts b/front/src/Phaser/Game/SoundManager.ts new file mode 100644 index 00000000..ef87ce7f --- /dev/null +++ b/front/src/Phaser/Game/SoundManager.ts @@ -0,0 +1,30 @@ +import LoaderPlugin = Phaser.Loader.LoaderPlugin; +import BaseSoundManager = Phaser.Sound.BaseSoundManager; +import BaseSound = Phaser.Sound.BaseSound; +import Config = Phaser.Core.Config; +import SoundConfig = Phaser.Types.Sound.SoundConfig; + + +class SoundManager { + + public loadSound (loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string) : Promise { + return new Promise((res) => { + let sound = soundManager.get(soundUrl); + if (sound !== null) { + return res(sound); + } + loadPlugin.audio(soundUrl, soundUrl); + loadPlugin.once('filecomplete-audio-' + soundUrl, () => res(soundManager.add(soundUrl))); + loadPlugin.start(); + }); + } + + public async playSound(loadPlugin: LoaderPlugin, soundManager : BaseSoundManager, soundUrl: string, config: SoundConfig) : Promise { + console.log("play sound"); + const sound = await this.loadSound(loadPlugin,soundManager,soundUrl); + + sound.play(config); + console.log("j'ai joué le son"); + } +} +export const soundManager = new SoundManager(); \ No newline at end of file diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..a3e6b5f0 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,8 @@ import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import {PlaySoundEvent} from "./Api/Events/PlaySoundEvent"; +import SoundConfig = Phaser.Types.Sound.SoundConfig; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -24,6 +26,7 @@ interface WorkAdventureApi { restorePlayerControl() : void; displayBubble() : void; removeBubble() : void; + playSound(url : string, config : SoundConfig): void; } declare global { @@ -113,6 +116,18 @@ window.WA = { },'*'); }, + playSound(url: string, config : SoundConfig) : string{ + window.parent.postMessage({ + "type" : 'playSound', + "data": { + url, + config + } as PlaySoundEvent + + },'*'); + return url; + }, + goToPage(url : string) : void{ window.parent.postMessage({ "type" : 'goToPage', diff --git a/maps/Tuto/scriptTuto.js b/maps/Tuto/scriptTuto.js index 869ec447..bcec0446 100644 --- a/maps/Tuto/scriptTuto.js +++ b/maps/Tuto/scriptTuto.js @@ -5,6 +5,12 @@ var targetObjectTutoBubble ='Tutobubble'; var targetObjectTutoChat ='tutoChat'; var targetObjectTutoExplanation ='tutoExplanation'; var popUpExplanation = undefined; +var enterSoundUrl = "/resources/objects/webrtc-in.mp3"; +var exitSoundUrl = "/resources/objects/webrtc-out.mp3"; +var soundConfig = { + volume : 0.5, + loop : false +} function launchTuto (){ WA.openPopup(targetObjectTutoBubble, textFirstPopup, [ { @@ -43,6 +49,8 @@ function launchTuto (){ WA.onEnterZone('popupZone', () => { WA.displayBubble(); + + WA.playSound(enterSoundUrl,soundConfig); if (!isFirstTimeTuto) { isFirstTimeTuto = true; launchTuto(); @@ -71,4 +79,6 @@ WA.onEnterZone('popupZone', () => { WA.onLeaveZone('popupZone', () => { if (popUpExplanation !== undefined) popUpExplanation.close(); WA.removeBubble(); + WA.playSound(exitSoundUrl,soundConfig); + })