onMemberStateChanged method
Implementation
Future<void> onMemberStateChanged(SDNEvent event) async {
// The member events may be received for another room, which we will ignore.
if (event.roomId != room.id) {
return;
}
final user = await room.requestUser(event.stateKey!);
if (user == null) {
return;
}
final callsState = IGroupCallRoomMemberState.fromJson(event);
if (callsState is List) {
Logs()
.w('Ignoring member state from ${user.id} member not in any calls.');
await _removeParticipant(user.id);
return;
}
// Currently we only support a single call per room. So grab the first call.
IGroupCallRoomMemberCallState? callState;
if (callsState.calls.isNotEmpty) {
final index = callsState.calls
.indexWhere((element) => element.call_id == groupCallId);
if (index != -1) {
callState = callsState.calls[index];
}
}
if (callState == null) {
Logs().w(
'Room member ${user.id} does not have a valid m.call_id set. Ignoring.');
await _removeParticipant(user.id);
return;
}
final callId = callState.call_id;
if (callId != null && callId != groupCallId) {
Logs().w(
'Call id $callId does not match group call id $groupCallId, ignoring.');
await _removeParticipant(user.id);
return;
}
await _addParticipant(user);
// Don't process your own member.
final localUserId = client.userID;
if (user.id == localUserId) {
return;
}
if (state != GroupCallState.Entered) {
return;
}
// Only initiate a call with a user who has a userId that is lexicographically
// less than your own. Otherwise, that user will call you.
if (localUserId!.compareTo(user.id) > 0) {
Logs().i('Waiting for ${user.id} to send call invite.');
return;
}
final existingCall = getCallByUserId(user.id);
if (existingCall != null) {
return;
}
final opponentDevice = await getDeviceForMember(user.id);
if (opponentDevice == null) {
Logs().w('No opponent device found for ${user.id}, ignoring.');
lastError = GroupCallError(
'400',
GroupCallErrorCode.UnknownDevice,
'Outgoing Call: No opponent device found for ${user.id}, ignoring.',
);
onGroupCallEvent.add(GroupCallEvent.Error);
return;
}
final opts = CallOptions()
..callId = genCallID()
..room = room
..voip = voip
..dir = CallDirection.kOutgoing
..localPartyId = client.deviceID!
..groupCallId = groupCallId
..type = CallType.kVideo
..iceServers = await voip.getIceSevers();
final newCall = voip.createNewCall(opts);
newCall.opponentDeviceId = opponentDevice.device_id;
newCall.opponentSessionId = opponentDevice.session_id;
newCall.remoteUser = await room.requestUser(user.id, ignoreErrors: true);
newCall.invitee = user.id;
final requestScreenshareFeed = opponentDevice.feeds.indexWhere(
(IGroupCallRoomMemberFeed feed) =>
feed.purpose == SDPStreamMetadataPurpose.Screenshare) !=
-1;
await newCall.placeCallWithStreams(
getLocalStreams(), requestScreenshareFeed);
await addCall(newCall);
}