Improvement feature circle discussion (#977)
* Improvment circle discussion - Change to lissen start event of WebRTC connection * Update help allow navigator and waring message - Show warning message. - Use help camera allow setting to show modal and help user. - Change feature to show the modal only when user have need the information on allow navigator access * Create soud for video discussion
This commit is contained in:
parent
83159a121f
commit
71eb3f3b69
14 changed files with 434 additions and 110 deletions
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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<HTMLDivElement>('webRtcSetup').style.display = 'none';
|
||||
this.helpCameraSettingsOpened = true;
|
||||
if(window.navigator.userAgent.includes('Firefox')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
|
||||
}else if(window.navigator.userAgent.includes('Chrome')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
|
||||
try{
|
||||
if(window.navigator.userAgent.includes('Firefox')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-firefox.png"/>';
|
||||
}else if(window.navigator.userAgent.includes('Chrome')){
|
||||
HtmlUtils.getElementByIdOrFail<HTMLParagraphElement>('browserHelpSetting').innerHTML ='<img src="/resources/objects/help-setting-camera-permission-chrome.png"/>';
|
||||
}
|
||||
}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 {
|
||||
|
|
|
@ -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<HTMLDivElement>('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();
|
||||
|
|
|
@ -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<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
||||
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
||||
helpCameraSettingsCallBacks : Set<HelpCameraSettingsCallBack> = new Set<HelpCameraSettingsCallBack>();
|
||||
|
||||
private microphoneBtn: HTMLDivElement;
|
||||
private cinemaBtn: HTMLDivElement;
|
||||
private monitorBtn: HTMLDivElement;
|
||||
|
@ -63,6 +69,12 @@ export class MediaManager {
|
|||
|
||||
private triggerCloseJistiFrame : Map<String, Function> = new Map<String, Function>();
|
||||
|
||||
private userInputManager?: UserInputManager;
|
||||
|
||||
private mySoundMeter?: SoundMeter|null;
|
||||
private soundMeters: Map<string, SoundMeter> = new Map<string, SoundMeter>();
|
||||
private soundMeterElements: Map<string, HTMLDivElement> = new Map<string, HTMLDivElement>();
|
||||
|
||||
constructor() {
|
||||
|
||||
this.myCamVideo = HtmlUtils.getElementByIdOrFail<HTMLVideoElement>('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<MediaStream> {
|
||||
|
@ -496,6 +535,13 @@ export class MediaManager {
|
|||
</button>
|
||||
<video id="${userId}" autoplay></video>
|
||||
<img src="resources/logos/blockSign.svg" id="blocking-${userId}" class="block-logo">
|
||||
<div id="soundMeter-${userId}" class="sound-progress">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -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<HTMLImageElement>('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();
|
||||
|
|
|
@ -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 => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue