diff --git a/packages/@webex/plugin-meetings/src/locus-info/index.ts b/packages/@webex/plugin-meetings/src/locus-info/index.ts index 489d12fda57..b43c8ddece0 100644 --- a/packages/@webex/plugin-meetings/src/locus-info/index.ts +++ b/packages/@webex/plugin-meetings/src/locus-info/index.ts @@ -1406,7 +1406,7 @@ export default class LocusInfo extends EventsScope { } ); } - if (parsedSelves.updates.isMutedByOthersChanged) { + if (parsedSelves.updates.isMutedByOthersChanged.changed) { this.emitScoped( { file: 'locus-info', @@ -1416,6 +1416,7 @@ export default class LocusInfo extends EventsScope { { muted: parsedSelves.current.remoteMuted, unmuteAllowed: parsedSelves.current.unmuteAllowed, + isModifiedBySelf: parsedSelves.updates.isMutedByOthersChanged.isModifiedBySelf, } ); } diff --git a/packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts b/packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts index 27079d8221b..a9ce5b8a059 100644 --- a/packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts +++ b/packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts @@ -419,25 +419,27 @@ SelfUtils.mutedByOthersChanged = (oldSelf, changedSelf) => { throw new ParameterError('New self must be defined to determine if self was muted by others.'); } + const isModifiedBySelf = changedSelf.selfIdentity === changedSelf.modifiedBy; + if (!oldSelf || oldSelf.remoteMuted === null) { if (changedSelf.remoteMuted) { - return true; // this happens when mute on-entry is enabled + return {changed: false, isModifiedBySelf}; // this happens when mute on-entry is enabled } // we don't want to be sending the 'meeting:self:unmutedByOthers' notification on meeting join - return false; - } - - // there is no need to trigger user update if no one muted user - if (changedSelf.selfIdentity === changedSelf.modifiedBy) { - return false; + return {changed: false, isModifiedBySelf}; } - - return ( - changedSelf.remoteMuted !== null && - (oldSelf.remoteMuted !== changedSelf.remoteMuted || - (changedSelf.remoteMuted && oldSelf.unmuteAllowed !== changedSelf.unmuteAllowed)) + console.log( + `marcin: mutedByOthersChanged: old.remoteMuted=${oldSelf.remoteMuted} new.remoteMuted=${changedSelf.remoteMuted} selfId=${changedSelf.selfIdentity} modifiedBy=${changedSelf.modifiedBy}` ); + + return { + changed: + changedSelf.remoteMuted !== null && + (oldSelf.remoteMuted !== changedSelf.remoteMuted || + (changedSelf.remoteMuted && oldSelf.unmuteAllowed !== changedSelf.unmuteAllowed)), + isModifiedBySelf, + }; }; SelfUtils.localAudioUnmuteRequestedByServer = (oldSelf: any = {}, changedSelf: any) => { diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index e7ffb18fd1f..36da4f115c8 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -3144,26 +3144,34 @@ export default class Meeting extends StatelessWebexPlugin { this.locusInfo.on(LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED, (payload) => { if (payload) { - if (this.audio) { - this.audio.handleServerRemoteMuteUpdate(this, payload.muted, payload.unmuteAllowed); - } - // with "mute on entry" server will send us remote mute even if we don't have media configured, - // so if being muted by others, always send the notification, - // but if being unmuted, only send it if we are also locally unmuted - if (payload.muted || !this.audio?.isMuted()) { - Trigger.trigger( - this, - { - file: 'meeting/index', - function: 'setUpLocusInfoSelfListener', - }, - payload.muted - ? EVENT_TRIGGERS.MEETING_SELF_MUTED_BY_OTHERS - : EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS, - { - payload, - } - ); + const ignore = this.audio + ? this.audio.shouldIgnoreRemoteMuteUpdate(payload.muted, payload.isModifiedBySelf) + : false; + + if (!ignore) { + if (this.audio) { + this.audio.handleServerRemoteMuteUpdate(this, payload.muted, payload.unmuteAllowed); + } + // with "mute on entry" server will send us remote mute even if we don't have media configured, + // so if being muted by others, always send the notification, + // but if being unmuted, only send it if we are also locally unmuted + if (payload.muted || !this.audio?.isMuted()) { + Trigger.trigger( + this, + { + file: 'meeting/index', + function: 'setUpLocusInfoSelfListener', + }, + payload.muted + ? EVENT_TRIGGERS.MEETING_SELF_MUTED_BY_OTHERS + : EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS, + { + payload, + } + ); + } + } else { + console.log(`marcin: ignoring remote mute update payload.muted=${payload.muted}`); } } }); diff --git a/packages/@webex/plugin-meetings/src/meeting/muteState.ts b/packages/@webex/plugin-meetings/src/meeting/muteState.ts index 43f72fcd501..5dc0b7eaaea 100644 --- a/packages/@webex/plugin-meetings/src/meeting/muteState.ts +++ b/packages/@webex/plugin-meetings/src/meeting/muteState.ts @@ -32,6 +32,7 @@ export class MuteState { }; server: {localMute: boolean; remoteMute: boolean; unmuteAllowed: boolean}; syncToServerInProgress: boolean; + isRemoteUnmutePendingLocusDtoUpdate: boolean; // true if we've sent a remote unmute request to Locus and haven't received a Locus DTO confirming it happened, yet }; type: any; @@ -62,6 +63,7 @@ export class MuteState { unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true, }, syncToServerInProgress: false, + isRemoteUnmutePendingLocusDtoUpdate: false, }; } @@ -327,6 +329,13 @@ export class MuteState { `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server` ); + this.state.isRemoteUnmutePendingLocusDtoUpdate = true; + + setTimeout(() => { + console.log('marcin: resetting isRemoteUnmutePendingLocusDtoUpdate after timeout'); + this.state.isRemoteUnmutePendingLocusDtoUpdate = false; + }, 10 * 1000); + return meeting.members .muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO) .then(() => { @@ -337,6 +346,8 @@ export class MuteState { this.state.server.remoteMute = remoteMute; }) .catch((remoteUpdateError) => { + this.state.isRemoteUnmutePendingLocusDtoUpdate = false; + LoggerProxy.logger.warn( `Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}` ); @@ -359,6 +370,23 @@ export class MuteState { } } + public shouldIgnoreRemoteMuteUpdate(remoteMute: boolean, isModifiedBySelf: boolean) { + console.log( + `marcin: shouldIgnoreRemoteMuteUpdate: flag=${this.state.isRemoteUnmutePendingLocusDtoUpdate} remoteMute=${remoteMute}, isModifiedBySelf=${isModifiedBySelf}` + ); + if (this.state.isRemoteUnmutePendingLocusDtoUpdate && isModifiedBySelf && !remoteMute) { + console.log('marcin: FIX: ignoring remote mute update'); + + this.state.isRemoteUnmutePendingLocusDtoUpdate = false; + + return true; + } + + console.log('marcin: FIX: NOT ignoring remote mute update'); + + return false; + } + /** * This method should be called whenever the server remote mute state is changed *