Skip to content

Commit bb85db9

Browse files
committed
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.
1 parent 44b0204 commit bb85db9

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

JitsiConferenceEvents.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,13 @@ export enum JitsiConferenceEvents {
412412
*/
413413
TRACK_AUDIO_LEVEL_CHANGED = 'conference.audioLevelsChanged',
414414

415+
/**
416+
* A remote participant's audio mute status changed based on signaling.
417+
* @param {JitsiParticipant} participant - The participant whose audio mute status changed
418+
* @param {boolean} muted - true if muted, false if unmuted
419+
*/
420+
TRACK_AUDIO_MUTED_CHANGED = 'conference.trackAudioMutedChanged',
421+
415422
/**
416423
* A media track ( attached to the conference) mute status was changed.
417424
* @param {JitsiParticipant|null} the participant that initiated the mute
@@ -433,6 +440,13 @@ export enum JitsiConferenceEvents {
433440
*/
434441
TRACK_UNMUTE_REJECTED = 'conference.trackUnmuteRejected',
435442

443+
/**
444+
* A remote participant's video mute status changed based on signaling.
445+
* @param {JitsiParticipant} participant - The participant whose video mute status changed
446+
* @param {boolean} muted - true if muted, false if unmuted
447+
*/
448+
TRACK_VIDEO_MUTED_CHANGED = 'conference.trackVideoMutedChanged',
449+
436450
/**
437451
* Notifies for transcription status changes. The event provides the
438452
* following parameters to its listeners:

JitsiParticipant.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export default class JitsiParticipant {
3030
private _isSilent?: boolean;
3131
private _features: Set<string>;
3232
private _sources: Map<MediaType, Map<string, ISourceInfo>>;
33+
private _previousAudioMuted?: boolean;
34+
private _previousVideoMuted?: boolean;
3335
private _botType?: string;
3436
private _connectionJid?: string;
3537
/**
@@ -142,13 +144,41 @@ export default class JitsiParticipant {
142144

143145
if (sourceByMediaType?.size) {
144146
sourceByMediaType.set(sourceName, sourceInfo);
147+
} else {
148+
sourceByMediaType = new Map();
149+
sourceByMediaType.set(sourceName, sourceInfo);
150+
this._sources.set(mediaType, sourceByMediaType);
151+
}
145152

146-
return;
153+
// Calculate aggregate mute state for the media type
154+
// If ANY source is unmuted, consider the media type unmuted
155+
let isMediaTypeMuted = true;
156+
157+
for (const source of sourceByMediaType.values()) {
158+
if (!source.muted) {
159+
isMediaTypeMuted = false;
160+
break;
161+
}
147162
}
148163

149-
sourceByMediaType = new Map();
150-
sourceByMediaType.set(sourceName, sourceInfo);
151-
this._sources.set(mediaType, sourceByMediaType);
164+
// Detect mute state changes and emit events
165+
if (mediaType === MediaType.AUDIO) {
166+
if (this._previousAudioMuted !== undefined && this._previousAudioMuted !== isMediaTypeMuted) {
167+
this._conference.eventEmitter.emit(
168+
JitsiConferenceEvents.TRACK_AUDIO_MUTED_CHANGED,
169+
this,
170+
isMediaTypeMuted);
171+
}
172+
this._previousAudioMuted = isMediaTypeMuted;
173+
} else if (mediaType === MediaType.VIDEO) {
174+
if (this._previousVideoMuted !== undefined && this._previousVideoMuted !== isMediaTypeMuted) {
175+
this._conference.eventEmitter.emit(
176+
JitsiConferenceEvents.TRACK_VIDEO_MUTED_CHANGED,
177+
this,
178+
isMediaTypeMuted);
179+
}
180+
this._previousVideoMuted = isMediaTypeMuted;
181+
}
152182
}
153183

154184
/**

0 commit comments

Comments
 (0)