onMemberStateChanged method
compltetely rebuilds the local _participants list
Implementation
Future<void> onMemberStateChanged() async {
// The member events may be received for another room, which we will ignore.
final mems =
room.getCallMembershipsFromRoom().values.expand((element) => element);
final memsForCurrentGroupCall = mems.where((element) {
return element.callId == groupCallId &&
!element.isExpired &&
element.application == application &&
element.scope == scope &&
element.roomId == room.id; // sanity checks
}).toList();
final ignoredMems =
mems.where((element) => !memsForCurrentGroupCall.contains(element));
for (final mem in ignoredMems) {
Logs().v(
'[VOIP] Ignored ${mem.userId}\'s mem event ${mem.toJson()} while updating _participants list for callId: $groupCallId, expiry status: ${mem.isExpired}');
}
final Set<CallParticipant> newP = {};
for (final mem in memsForCurrentGroupCall) {
final rp = CallParticipant(
voip,
userId: mem.userId,
deviceId: mem.deviceId,
);
newP.add(rp);
if (rp.isLocal) continue;
if (state != GroupCallState.entered) {
Logs().w(
'[VOIP] onMemberStateChanged groupCall state is currently $state, skipping member update');
continue;
}
await backend.setupP2PCallWithNewMember(this, rp, mem);
}
final newPcopy = Set<CallParticipant>.from(newP);
final oldPcopy = Set<CallParticipant>.from(_participants);
final anyJoined = newPcopy.difference(oldPcopy);
final anyLeft = oldPcopy.difference(newPcopy);
if (anyJoined.isNotEmpty || anyLeft.isNotEmpty) {
if (anyJoined.isNotEmpty) {
final nonLocalAnyJoined = Set<CallParticipant>.from(anyJoined)
..remove(localParticipant);
if (nonLocalAnyJoined.isNotEmpty && state == GroupCallState.entered) {
Logs().v(
'nonLocalAnyJoined: ${nonLocalAnyJoined.map((e) => e.id).toString()} roomId: ${room.id} groupCallId: $groupCallId');
await backend.onNewParticipant(this, nonLocalAnyJoined.toList());
}
_participants.addAll(anyJoined);
matrixRTCEventStream
.add(ParticipantsJoinEvent(participants: anyJoined.toList()));
}
if (anyLeft.isNotEmpty) {
final nonLocalAnyLeft = Set<CallParticipant>.from(anyLeft)
..remove(localParticipant);
if (nonLocalAnyLeft.isNotEmpty && state == GroupCallState.entered) {
Logs().v(
'nonLocalAnyLeft: ${nonLocalAnyLeft.map((e) => e.id).toString()} roomId: ${room.id} groupCallId: $groupCallId');
await backend.onLeftParticipant(this, nonLocalAnyLeft.toList());
}
_participants.removeAll(anyLeft);
matrixRTCEventStream
.add(ParticipantsLeftEvent(participants: anyLeft.toList()));
}
onGroupCallEvent.add(GroupCallStateChange.participantsChanged);
Logs().d(
'[VOIP] onMemberStateChanged current list: ${_participants.map((e) => e.id).toString()}');
}
}