onMemberStateChanged method

Future<void> onMemberStateChanged()

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()}');
  }
}