Merge pull request #825 from workadventure-xce/audio_player_improvements
Audio player improvements
This commit is contained in:
commit
7765775df5
4
front/dist/index.tmpl.html
vendored
4
front/dist/index.tmpl.html
vendored
@ -92,12 +92,12 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div class="audioplayer">
|
<div class="audioplayer">
|
||||||
<input type="range" id="audioplayer_volume" min="0" max="1" step="0.05" value="1" />
|
<input type="range" id="audioplayer_volume" min="0" max="1" step="0.025" value="1" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="audioplayer">
|
<div class="audioplayer">
|
||||||
<label id="label-audioplayer_decrease_while_talking" for="audiooplayer_decrease_while_talking" title="decrease background volume by 50% when entering conversations">
|
<label id="label-audioplayer_decrease_while_talking" for="audiooplayer_decrease_while_talking" title="decrease background volume by 50% when entering conversations">
|
||||||
autoreduce
|
reduce in conversations
|
||||||
<input type="checkbox" id="audioplayer_decrease_while_talking" checked />
|
<input type="checkbox" id="audioplayer_decrease_while_talking" checked />
|
||||||
</label>
|
</label>
|
||||||
<div id="audioplayer" style="visibility: hidden"></div>
|
<div id="audioplayer" style="visibility: hidden"></div>
|
||||||
|
6
front/dist/resources/style/style.css
vendored
6
front/dist/resources/style/style.css
vendored
@ -363,10 +363,14 @@ body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audioplayer > div {
|
||||||
|
padding-right: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
#audioplayerctrl {
|
#audioplayerctrl {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 50%;
|
right: calc(50% - 120px);
|
||||||
padding: 0.3rem 0.5rem;
|
padding: 0.3rem 0.5rem;
|
||||||
color: white;
|
color: white;
|
||||||
transition: transform 0.5s;
|
transition: transform 0.5s;
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import {LocalUser} from "./LocalUser";
|
import {LocalUser} from "./LocalUser";
|
||||||
|
|
||||||
|
const playerNameKey = 'playerName';
|
||||||
|
const selectedPlayerKey = 'selectedPlayer';
|
||||||
|
const customCursorPositionKey = 'customCursorPosition';
|
||||||
const characterLayersKey = 'characterLayers';
|
const characterLayersKey = 'characterLayers';
|
||||||
const gameQualityKey = 'gameQuality';
|
const gameQualityKey = 'gameQuality';
|
||||||
const videoQualityKey = 'videoQuality';
|
const videoQualityKey = 'videoQuality';
|
||||||
|
const audioPlayerVolumeKey = 'audioVolume';
|
||||||
|
const audioPlayerMuteKey = 'audioMute';
|
||||||
|
|
||||||
//todo: add localstorage fallback
|
|
||||||
class LocalUserStore {
|
class LocalUserStore {
|
||||||
|
|
||||||
saveUser(localUser: LocalUser) {
|
saveUser(localUser: LocalUser) {
|
||||||
localStorage.setItem('localUser', JSON.stringify(localUser));
|
localStorage.setItem('localUser', JSON.stringify(localUser));
|
||||||
}
|
}
|
||||||
@ -16,46 +19,60 @@ class LocalUserStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setName(name:string): void {
|
setName(name:string): void {
|
||||||
window.localStorage.setItem('playerName', name);
|
localStorage.setItem(playerNameKey, name);
|
||||||
}
|
}
|
||||||
getName(): string {
|
getName(): string {
|
||||||
return window.localStorage.getItem('playerName') ?? '';
|
return localStorage.getItem(playerNameKey) || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
setPlayerCharacterIndex(playerCharacterIndex: number): void {
|
||||||
window.localStorage.setItem('selectedPlayer', ''+playerCharacterIndex);
|
localStorage.setItem(selectedPlayerKey, ''+playerCharacterIndex);
|
||||||
}
|
}
|
||||||
getPlayerCharacterIndex(): number {
|
getPlayerCharacterIndex(): number {
|
||||||
return parseInt(window.localStorage.getItem('selectedPlayer') || '');
|
return parseInt(localStorage.getItem(selectedPlayerKey) || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
setCustomCursorPosition(activeRow:number, selectedLayers: number[]): void {
|
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 {
|
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 {
|
setCharacterLayers(layers: string[]): void {
|
||||||
window.localStorage.setItem(characterLayersKey, JSON.stringify(layers));
|
localStorage.setItem(characterLayersKey, JSON.stringify(layers));
|
||||||
}
|
}
|
||||||
getCharacterLayers(): string[]|null {
|
getCharacterLayers(): string[]|null {
|
||||||
return JSON.parse(window.localStorage.getItem(characterLayersKey) || "null");
|
return JSON.parse(localStorage.getItem(characterLayersKey) || "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
getGameQualityValue(): number {
|
|
||||||
return parseInt(window.localStorage.getItem(gameQualityKey) || '') || 60;
|
|
||||||
}
|
|
||||||
setGameQualityValue(value: number): void {
|
setGameQualityValue(value: number): void {
|
||||||
localStorage.setItem(gameQualityKey, '' + value);
|
localStorage.setItem(gameQualityKey, '' + value);
|
||||||
}
|
}
|
||||||
|
getGameQualityValue(): number {
|
||||||
getVideoQualityValue(): number {
|
return parseInt(localStorage.getItem(gameQualityKey) || '60');
|
||||||
return parseInt(window.localStorage.getItem(videoQualityKey) || '') || 20;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setVideoQualityValue(value: number): void {
|
setVideoQualityValue(value: number): void {
|
||||||
localStorage.setItem(videoQualityKey, '' + value);
|
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();
|
export const localUserStore = new LocalUserStore();
|
@ -29,7 +29,9 @@ import {
|
|||||||
ON_ACTION_TRIGGER_BUTTON,
|
ON_ACTION_TRIGGER_BUTTON,
|
||||||
TRIGGER_JITSI_PROPERTIES,
|
TRIGGER_JITSI_PROPERTIES,
|
||||||
TRIGGER_WEBSITE_PROPERTIES,
|
TRIGGER_WEBSITE_PROPERTIES,
|
||||||
WEBSITE_MESSAGE_PROPERTIES
|
WEBSITE_MESSAGE_PROPERTIES,
|
||||||
|
AUDIO_VOLUME_PROPERTY,
|
||||||
|
AUDIO_LOOP_PROPERTY
|
||||||
} from "../../WebRtc/LayoutManager";
|
} from "../../WebRtc/LayoutManager";
|
||||||
import {GameMap} from "./GameMap";
|
import {GameMap} from "./GameMap";
|
||||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||||
@ -455,16 +457,12 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
|
this.connection.onGroupUpdatedOrCreated((groupPositionMessage: GroupCreatedUpdatedMessageInterface) => {
|
||||||
audioManager.decreaseVolume();
|
|
||||||
this.shareGroupPosition(groupPositionMessage);
|
this.shareGroupPosition(groupPositionMessage);
|
||||||
this.openChatIcon.setVisible(true);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.onGroupDeleted((groupId: number) => {
|
this.connection.onGroupDeleted((groupId: number) => {
|
||||||
audioManager.restoreVolume();
|
|
||||||
try {
|
try {
|
||||||
this.deleteGroup(groupId);
|
this.deleteGroup(groupId);
|
||||||
this.openChatIcon.setVisible(false);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
@ -517,11 +515,15 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
onConnect(user: UserSimplePeerInterface) {
|
onConnect(user: UserSimplePeerInterface) {
|
||||||
self.presentationModeSprite.setVisible(true);
|
self.presentationModeSprite.setVisible(true);
|
||||||
self.chatModeSprite.setVisible(true);
|
self.chatModeSprite.setVisible(true);
|
||||||
|
self.openChatIcon.setVisible(true);
|
||||||
|
audioManager.decreaseVolume();
|
||||||
},
|
},
|
||||||
onDisconnect(userId: number) {
|
onDisconnect(userId: number) {
|
||||||
if (self.simplePeer.getNbConnections() === 0) {
|
if (self.simplePeer.getNbConnections() === 0) {
|
||||||
self.presentationModeSprite.setVisible(false);
|
self.presentationModeSprite.setVisible(false);
|
||||||
self.chatModeSprite.setVisible(false);
|
self.chatModeSprite.setVisible(false);
|
||||||
|
self.openChatIcon.setVisible(false);
|
||||||
|
audioManager.restoreVolume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -662,14 +664,15 @@ export class GameScene extends ResizableScene implements CenterListener {
|
|||||||
this.connection.setSilent(true);
|
this.connection.setSilent(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue) => {
|
this.gameMap.onPropertyChange('playAudio', (newValue, oldValue, allProps) => {
|
||||||
newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl());
|
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);
|
||||||
});
|
});
|
||||||
|
// TODO: This legacy property should be removed at some point
|
||||||
this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => {
|
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 {
|
private getMapDirUrl(): string {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {HtmlUtils} from "./HtmlUtils";
|
import {HtmlUtils} from "./HtmlUtils";
|
||||||
import {isUndefined} from "generic-type-guard";
|
import {isUndefined} from "generic-type-guard";
|
||||||
|
import {localUserStore} from "../Connexion/LocalUserStore";
|
||||||
|
|
||||||
enum audioStates {
|
enum audioStates {
|
||||||
closed = 0,
|
closed = 0,
|
||||||
@ -9,6 +10,8 @@ enum audioStates {
|
|||||||
|
|
||||||
const audioPlayerDivId = "audioplayer";
|
const audioPlayerDivId = "audioplayer";
|
||||||
const audioPlayerCtrlId = "audioplayerctrl";
|
const audioPlayerCtrlId = "audioplayerctrl";
|
||||||
|
const audioPlayerVolId = "audioplayer_volume";
|
||||||
|
const audioPlayerMuteId = "audioplayer_volume_icon_playing";
|
||||||
const animationTime = 500;
|
const animationTime = 500;
|
||||||
|
|
||||||
class AudioManager {
|
class AudioManager {
|
||||||
@ -17,6 +20,8 @@ class AudioManager {
|
|||||||
private audioPlayerDiv: HTMLDivElement;
|
private audioPlayerDiv: HTMLDivElement;
|
||||||
private audioPlayerCtrl: HTMLDivElement;
|
private audioPlayerCtrl: HTMLDivElement;
|
||||||
private audioPlayerElem: HTMLAudioElement | undefined;
|
private audioPlayerElem: HTMLAudioElement | undefined;
|
||||||
|
private audioPlayerVol: HTMLInputElement;
|
||||||
|
private audioPlayerMute: HTMLInputElement;
|
||||||
|
|
||||||
private volume = 1;
|
private volume = 1;
|
||||||
private muted = false;
|
private muted = false;
|
||||||
@ -26,19 +31,19 @@ class AudioManager {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerDivId);
|
this.audioPlayerDiv = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerDivId);
|
||||||
this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerCtrlId);
|
this.audioPlayerCtrl = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(audioPlayerCtrlId);
|
||||||
|
this.audioPlayerVol = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(audioPlayerVolId);
|
||||||
|
this.audioPlayerMute = HtmlUtils.getElementByIdOrFail<HTMLInputElement>(audioPlayerMuteId);
|
||||||
|
|
||||||
const storedVolume = localStorage.getItem('volume')
|
this.volume = localUserStore.getAudioPlayerVolume();
|
||||||
if (storedVolume === null) {
|
this.audioPlayerVol.value = '' + this.volume;
|
||||||
this.setVolume(1);
|
|
||||||
} else {
|
this.muted = localUserStore.getAudioPlayerMuted();
|
||||||
this.volume = parseFloat(storedVolume);
|
if (this.muted) {
|
||||||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = storedVolume;
|
this.audioPlayerMute.classList.add('muted');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume').value = '' + this.volume;
|
public playAudio(url: string|number|boolean, mapDirUrl: string, volume: number|undefined, loop=false): void {
|
||||||
}
|
|
||||||
|
|
||||||
public playAudio(url: string|number|boolean, mapDirUrl: string, loop=false): void {
|
|
||||||
const audioPath = url as string;
|
const audioPath = url as string;
|
||||||
let realAudioPath = '';
|
let realAudioPath = '';
|
||||||
|
|
||||||
@ -50,7 +55,7 @@ class AudioManager {
|
|||||||
realAudioPath = mapDirUrl + '/' + url;
|
realAudioPath = mapDirUrl + '/' + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadAudio(realAudioPath);
|
this.loadAudio(realAudioPath, volume);
|
||||||
|
|
||||||
if (loop) {
|
if (loop) {
|
||||||
this.loop();
|
this.loop();
|
||||||
@ -75,26 +80,29 @@ class AudioManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private changeVolume(talking = false): void {
|
private changeVolume(talking = false): void {
|
||||||
if (!isUndefined(this.audioPlayerElem)) {
|
if (isUndefined(this.audioPlayerElem)) {
|
||||||
this.audioPlayerElem.volume = this.naturalVolume(talking && this.decreaseWhileTalking);
|
return;
|
||||||
this.audioPlayerElem.muted = this.muted;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private naturalVolume(makeSofter: boolean = false): number {
|
const reduceVolume = talking && this.decreaseWhileTalking;
|
||||||
const volume = this.volume
|
if (reduceVolume && !this.volumeReduced) {
|
||||||
const retVol = makeSofter && !this.volumeReduced ? Math.pow(volume * 0.5, 3) : volume
|
this.volume *= 0.5;
|
||||||
this.volumeReduced = makeSofter
|
} else if (!reduceVolume && this.volumeReduced) {
|
||||||
return retVol;
|
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 {
|
private setVolume(volume: number): void {
|
||||||
this.volume = volume;
|
this.volume = volume;
|
||||||
localStorage.setItem('volume', '' + volume);
|
localUserStore.setAudioPlayerVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private loadAudio(url: string, volume: number|undefined): void {
|
||||||
private loadAudio(url: string): void {
|
|
||||||
this.load();
|
this.load();
|
||||||
|
|
||||||
/* Solution 1, remove whole audio player */
|
/* Solution 1, remove whole audio player */
|
||||||
@ -112,23 +120,24 @@ class AudioManager {
|
|||||||
this.audioPlayerElem.append(srcElem);
|
this.audioPlayerElem.append(srcElem);
|
||||||
|
|
||||||
this.audioPlayerDiv.append(this.audioPlayerElem);
|
this.audioPlayerDiv.append(this.audioPlayerElem);
|
||||||
|
this.volume = volume ? Math.min(volume, this.volume) : this.volume;
|
||||||
this.changeVolume();
|
this.changeVolume();
|
||||||
this.audioPlayerElem.play();
|
this.audioPlayerElem.play();
|
||||||
|
|
||||||
const muteElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_mute');
|
const muteElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_mute');
|
||||||
muteElem.onclick = (ev: Event)=> {
|
muteElem.onclick = (ev: Event) => {
|
||||||
this.muted = !this.muted;
|
this.muted = !this.muted;
|
||||||
this.changeVolume();
|
this.changeVolume();
|
||||||
|
localUserStore.setAudioPlayerMuted(this.muted);
|
||||||
|
|
||||||
if (this.muted) {
|
if (this.muted) {
|
||||||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume_icon_playing').classList.add('muted');
|
this.audioPlayerMute.classList.add('muted');
|
||||||
} else {
|
} else {
|
||||||
HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume_icon_playing').classList.remove('muted');
|
this.audioPlayerMute.classList.remove('muted');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const volumeElem = HtmlUtils.getElementByIdOrFail<HTMLInputElement>('audioplayer_volume');
|
this.audioPlayerVol.oninput = (ev: Event)=> {
|
||||||
volumeElem.oninput = (ev: Event)=> {
|
|
||||||
this.setVolume(parseFloat((<HTMLInputElement>ev.currentTarget).value));
|
this.setVolume(parseFloat((<HTMLInputElement>ev.currentTarget).value));
|
||||||
this.changeVolume();
|
this.changeVolume();
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@ export const TRIGGER_JITSI_PROPERTIES = 'jitsiTrigger';
|
|||||||
export const WEBSITE_MESSAGE_PROPERTIES = 'openWebsiteTriggerMessage';
|
export const WEBSITE_MESSAGE_PROPERTIES = 'openWebsiteTriggerMessage';
|
||||||
export const JITSI_MESSAGE_PROPERTIES = 'jitsiTriggerMessage';
|
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.
|
* 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.
|
* It receives positioning requests for videos and does its best to place them on the screen depending on the active layout mode.
|
||||||
|
@ -63,7 +63,7 @@ export class SimplePeer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getNbConnections(): number {
|
public getNbConnections(): number {
|
||||||
return this.PeerConnectionArray.size;
|
return this.Users.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,9 +230,6 @@ export class SimplePeer {
|
|||||||
|
|
||||||
this.closeScreenSharingConnection(userId);
|
this.closeScreenSharingConnection(userId);
|
||||||
|
|
||||||
for (const peerConnectionListener of this.peerConnectionListeners) {
|
|
||||||
peerConnectionListener.onDisconnect(userId);
|
|
||||||
}
|
|
||||||
const userIndex = this.Users.findIndex(user => user.userId === userId);
|
const userIndex = this.Users.findIndex(user => user.userId === userId);
|
||||||
if(userIndex < 0){
|
if(userIndex < 0){
|
||||||
throw 'Couln\'t delete user';
|
throw 'Couln\'t delete user';
|
||||||
@ -250,6 +247,10 @@ export class SimplePeer {
|
|||||||
this.PeerScreenSharingConnectionArray.delete(userId);
|
this.PeerScreenSharingConnectionArray.delete(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const peerConnectionListener of this.peerConnectionListeners) {
|
||||||
|
peerConnectionListener.onDisconnect(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user