Skip to content

Commit 0a56661

Browse files
committed
fix: moderated unmute when client is remotely muted
1 parent 840d96f commit 0a56661

File tree

4 files changed

+72
-33
lines changed

4 files changed

+72
-33
lines changed

packages/@webex/plugin-meetings/src/locus-info/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ export default class LocusInfo extends EventsScope {
14061406
}
14071407
);
14081408
}
1409-
if (parsedSelves.updates.isMutedByOthersChanged) {
1409+
if (parsedSelves.updates.isMutedByOthersChanged.changed) {
14101410
this.emitScoped(
14111411
{
14121412
file: 'locus-info',
@@ -1416,6 +1416,7 @@ export default class LocusInfo extends EventsScope {
14161416
{
14171417
muted: parsedSelves.current.remoteMuted,
14181418
unmuteAllowed: parsedSelves.current.unmuteAllowed,
1419+
isModifiedBySelf: parsedSelves.updates.isMutedByOthersChanged.isModifiedBySelf,
14191420
}
14201421
);
14211422
}

packages/@webex/plugin-meetings/src/locus-info/selfUtils.ts

+14-12
Original file line numberDiff line numberDiff line change
@@ -419,25 +419,27 @@ SelfUtils.mutedByOthersChanged = (oldSelf, changedSelf) => {
419419
throw new ParameterError('New self must be defined to determine if self was muted by others.');
420420
}
421421

422+
const isModifiedBySelf = changedSelf.selfIdentity === changedSelf.modifiedBy;
423+
422424
if (!oldSelf || oldSelf.remoteMuted === null) {
423425
if (changedSelf.remoteMuted) {
424-
return true; // this happens when mute on-entry is enabled
426+
return {changed: false, isModifiedBySelf}; // this happens when mute on-entry is enabled
425427
}
426428

427429
// we don't want to be sending the 'meeting:self:unmutedByOthers' notification on meeting join
428-
return false;
429-
}
430-
431-
// there is no need to trigger user update if no one muted user
432-
if (changedSelf.selfIdentity === changedSelf.modifiedBy) {
433-
return false;
430+
return {changed: false, isModifiedBySelf};
434431
}
435-
436-
return (
437-
changedSelf.remoteMuted !== null &&
438-
(oldSelf.remoteMuted !== changedSelf.remoteMuted ||
439-
(changedSelf.remoteMuted && oldSelf.unmuteAllowed !== changedSelf.unmuteAllowed))
432+
console.log(
433+
`marcin: mutedByOthersChanged: old.remoteMuted=${oldSelf.remoteMuted} new.remoteMuted=${changedSelf.remoteMuted} selfId=${changedSelf.selfIdentity} modifiedBy=${changedSelf.modifiedBy}`
440434
);
435+
436+
return {
437+
changed:
438+
changedSelf.remoteMuted !== null &&
439+
(oldSelf.remoteMuted !== changedSelf.remoteMuted ||
440+
(changedSelf.remoteMuted && oldSelf.unmuteAllowed !== changedSelf.unmuteAllowed)),
441+
isModifiedBySelf,
442+
};
441443
};
442444

443445
SelfUtils.localAudioUnmuteRequestedByServer = (oldSelf: any = {}, changedSelf: any) => {

packages/@webex/plugin-meetings/src/meeting/index.ts

+28-20
Original file line numberDiff line numberDiff line change
@@ -3144,26 +3144,34 @@ export default class Meeting extends StatelessWebexPlugin {
31443144

31453145
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_REMOTE_MUTE_STATUS_UPDATED, (payload) => {
31463146
if (payload) {
3147-
if (this.audio) {
3148-
this.audio.handleServerRemoteMuteUpdate(this, payload.muted, payload.unmuteAllowed);
3149-
}
3150-
// with "mute on entry" server will send us remote mute even if we don't have media configured,
3151-
// so if being muted by others, always send the notification,
3152-
// but if being unmuted, only send it if we are also locally unmuted
3153-
if (payload.muted || !this.audio?.isMuted()) {
3154-
Trigger.trigger(
3155-
this,
3156-
{
3157-
file: 'meeting/index',
3158-
function: 'setUpLocusInfoSelfListener',
3159-
},
3160-
payload.muted
3161-
? EVENT_TRIGGERS.MEETING_SELF_MUTED_BY_OTHERS
3162-
: EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS,
3163-
{
3164-
payload,
3165-
}
3166-
);
3147+
const ignore = this.audio
3148+
? this.audio.shouldIgnoreRemoteMuteUpdate(payload.muted, payload.isModifiedBySelf)
3149+
: false;
3150+
3151+
if (!ignore) {
3152+
if (this.audio) {
3153+
this.audio.handleServerRemoteMuteUpdate(this, payload.muted, payload.unmuteAllowed);
3154+
}
3155+
// with "mute on entry" server will send us remote mute even if we don't have media configured,
3156+
// so if being muted by others, always send the notification,
3157+
// but if being unmuted, only send it if we are also locally unmuted
3158+
if (payload.muted || !this.audio?.isMuted()) {
3159+
Trigger.trigger(
3160+
this,
3161+
{
3162+
file: 'meeting/index',
3163+
function: 'setUpLocusInfoSelfListener',
3164+
},
3165+
payload.muted
3166+
? EVENT_TRIGGERS.MEETING_SELF_MUTED_BY_OTHERS
3167+
: EVENT_TRIGGERS.MEETING_SELF_UNMUTED_BY_OTHERS,
3168+
{
3169+
payload,
3170+
}
3171+
);
3172+
}
3173+
} else {
3174+
console.log(`marcin: ignoring remote mute update payload.muted=${payload.muted}`);
31673175
}
31683176
}
31693177
});

packages/@webex/plugin-meetings/src/meeting/muteState.ts

+28
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class MuteState {
3232
};
3333
server: {localMute: boolean; remoteMute: boolean; unmuteAllowed: boolean};
3434
syncToServerInProgress: boolean;
35+
isRemoteUnmutePendingLocusDtoUpdate: boolean; // true if we've sent a remote unmute request to Locus and haven't received a Locus DTO confirming it happened, yet
3536
};
3637

3738
type: any;
@@ -62,6 +63,7 @@ export class MuteState {
6263
unmuteAllowed: type === AUDIO ? meeting.unmuteAllowed : meeting.unmuteVideoAllowed ?? true,
6364
},
6465
syncToServerInProgress: false,
66+
isRemoteUnmutePendingLocusDtoUpdate: false,
6567
};
6668
}
6769

@@ -327,6 +329,13 @@ export class MuteState {
327329
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: sending remote mute:${remoteMute} to server`
328330
);
329331

332+
this.state.isRemoteUnmutePendingLocusDtoUpdate = true;
333+
334+
setTimeout(() => {
335+
console.log('marcin: resetting isRemoteUnmutePendingLocusDtoUpdate after timeout');
336+
this.state.isRemoteUnmutePendingLocusDtoUpdate = false;
337+
}, 10 * 1000);
338+
330339
return meeting.members
331340
.muteMember(meeting.members.selfId, remoteMute, this.type === AUDIO)
332341
.then(() => {
@@ -337,6 +346,8 @@ export class MuteState {
337346
this.state.server.remoteMute = remoteMute;
338347
})
339348
.catch((remoteUpdateError) => {
349+
this.state.isRemoteUnmutePendingLocusDtoUpdate = false;
350+
340351
LoggerProxy.logger.warn(
341352
`Meeting:muteState#sendRemoteMuteRequestToServer --> ${this.type}: failed to apply remote mute ${remoteMute} to server: ${remoteUpdateError}`
342353
);
@@ -359,6 +370,23 @@ export class MuteState {
359370
}
360371
}
361372

373+
public shouldIgnoreRemoteMuteUpdate(remoteMute: boolean, isModifiedBySelf: boolean) {
374+
console.log(
375+
`marcin: shouldIgnoreRemoteMuteUpdate: flag=${this.state.isRemoteUnmutePendingLocusDtoUpdate} remoteMute=${remoteMute}, isModifiedBySelf=${isModifiedBySelf}`
376+
);
377+
if (this.state.isRemoteUnmutePendingLocusDtoUpdate && isModifiedBySelf && !remoteMute) {
378+
console.log('marcin: FIX: ignoring remote mute update');
379+
380+
this.state.isRemoteUnmutePendingLocusDtoUpdate = false;
381+
382+
return true;
383+
}
384+
385+
console.log('marcin: FIX: NOT ignoring remote mute update');
386+
387+
return false;
388+
}
389+
362390
/**
363391
* This method should be called whenever the server remote mute state is changed
364392
*

0 commit comments

Comments
 (0)