Skip to content

Commit 80baf65

Browse files
mihhucatFurr
authored andcommitted
fix(JitsiConference): handles mute state updates arriving before track creation (jitsi#2956)
* feat(JitsiParticipant): Add participant-level mute state change events Adds TRACK_AUDIO_MUTED_CHANGED and TRACK_VIDEO_MUTED_CHANGED events that emit when a participant's aggregate mute state changes. A participant is considered unmuted if ANY source for that media type is unmuted. Also fixes bug where sources weren't added when media type map didn't exist. * fix(JitsiConference): Emit TRACK_MUTE_CHANGED for initial remote track mute state * fix(JitsiConference): handle mute state updates arriving before track creation
1 parent 1b9895e commit 80baf65

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

JitsiConference.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3546,6 +3546,16 @@ export default class JitsiConference extends Listenable {
35463546
);
35473547

35483548
emitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
3549+
3550+
// Apply any pending mute state that arrived before the track was created
3551+
// Always call setMute when there's a pending state, even if it matches current state,
3552+
// because setMute() is designed to emit on the first call regardless of state change
3553+
const pendingMutedState = track._getPendingMuteState();
3554+
3555+
if (pendingMutedState !== undefined) {
3556+
track._clearPendingMuteState();
3557+
track.setMute(pendingMutedState);
3558+
}
35493559
}
35503560

35513561

modules/RTC/JitsiRemoteTrack.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ export default class JitsiRemoteTrack extends JitsiTrack {
4747
private _rtc: RTC;
4848
private _muted: boolean;
4949
private _hasBeenMuted: boolean;
50+
private _setMuteCalled: boolean;
5051
private _ssrc: number;
52+
private _pendingMuteState?: boolean;
5153

5254
public ownerEndpointId: string;
5355
public isP2P: boolean;
@@ -101,6 +103,7 @@ export default class JitsiRemoteTrack extends JitsiTrack {
101103
this._ssrc = ssrc;
102104
this.ownerEndpointId = ownerEndpointId;
103105
this._muted = muted;
106+
this._setMuteCalled = false;
104107
this.isP2P = isP2P;
105108
this._sourceName = sourceName;
106109
this._trackStreamingStatus = null;
@@ -423,6 +426,37 @@ export default class JitsiRemoteTrack extends JitsiTrack {
423426
return this._enteredForwardedSourcesTimestamp;
424427
}
425428

429+
/**
430+
* Sets the pending mute state for this track,
431+
* received before the track was fully initialized.
432+
*
433+
* @param {boolean | undefined} state - The pending mute state
434+
* @internal
435+
*/
436+
_setPendingMuteState(state: boolean | undefined): void {
437+
this._pendingMuteState = state;
438+
}
439+
440+
/**
441+
* Returns the pending mute state for this track,
442+
* received before the track was fully initialized.
443+
*
444+
* @returns {boolean | undefined} the pending mute state
445+
* @internal
446+
*/
447+
_getPendingMuteState(): boolean | undefined {
448+
return this._pendingMuteState;
449+
}
450+
451+
/**
452+
* Clears the pending mute state for this track.
453+
*
454+
* @internal
455+
*/
456+
_clearPendingMuteState(): void {
457+
this._pendingMuteState = undefined;
458+
}
459+
426460
/**
427461
* Removes attached event listeners and dispose TrackStreamingStatus .
428462
*
@@ -444,10 +478,16 @@ export default class JitsiRemoteTrack extends JitsiTrack {
444478
* @internal
445479
*/
446480
setMute(value: boolean): void {
447-
if (this._muted === value) {
481+
const isFirstCall = !this._setMuteCalled;
482+
const stateChanged = this._muted !== value;
483+
484+
// Skip if state didn't change, unless this is the first call (to emit initial state)
485+
if (!stateChanged && !isFirstCall) {
448486
return;
449487
}
450488

489+
this._setMuteCalled = true;
490+
451491
if (value) {
452492
this._hasBeenMuted = true;
453493
}

modules/RTC/TraceablePeerConnection.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export default class TraceablePeerConnection {
157157
private _pcId: string;
158158
private _remoteUfrag: string;
159159
private _signalingLayer: SignalingLayer;
160+
private _pendingMuteUpdates: Map<string, boolean>;
160161
/**
161162
* @internal
162163
*/
@@ -324,6 +325,13 @@ export default class TraceablePeerConnection {
324325
*/
325326
this.remoteTracks = new Map();
326327

328+
/**
329+
* Stores pending mute updates for sources that haven't had tracks created yet.
330+
* @type {Map<string, boolean>}
331+
* @private
332+
*/
333+
this._pendingMuteUpdates = new Map();
334+
327335
/**
328336
* A map which stores local tracks mapped by {@link JitsiLocalTrack.rtcId}
329337
* @type {Map<number, JitsiLocalTrack>}
@@ -1203,11 +1211,14 @@ export default class TraceablePeerConnection {
12031211
const track = this.getRemoteTracks().slice().reverse().find(t => t.getSourceName() === sourceName);
12041212

12051213
if (!track) {
1206-
logger.debug(`Remote track not found for source=${sourceName}, mute update failed!`);
1214+
// Store the pending mute update to be applied when the track is created
1215+
this._pendingMuteUpdates.set(sourceName, isMuted);
12071216

12081217
return;
12091218
}
12101219

1220+
// Clear any pending mute update since we're applying the current state to an existing track
1221+
this._pendingMuteUpdates.delete(sourceName);
12111222
track.setMute(isMuted);
12121223
}
12131224

@@ -1692,6 +1703,14 @@ export default class TraceablePeerConnection {
16921703
userTracksByMediaType.add(remoteTrack);
16931704
}
16941705

1706+
// Store pending mute update on the track itself so JitsiConference can apply it after attaching listeners
1707+
if (this._pendingMuteUpdates.has(sourceName)) {
1708+
const pendingMutedState = this._pendingMuteUpdates.get(sourceName);
1709+
1710+
remoteTrack._setPendingMuteState(pendingMutedState);
1711+
this._pendingMuteUpdates.delete(sourceName);
1712+
}
1713+
16951714
this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack, this);
16961715
}
16971716

0 commit comments

Comments
 (0)