feat: preShareKey using fetchOrCreateGroupCall
fix: only fire backend.onNewParticipant and backend.onLeftParticipant when it is not the local participant, this fixes the issue where onNewParticipant would get triggered when it detects a new call even though you were not in the call, as of now there is no code in those functions which needs to be triggered before you have joined the call so this should be fine chore: also improve participants join leave tracking logic
This commit is contained in:
parent
f98a947181
commit
fd6c7a1016
|
|
@ -73,6 +73,8 @@ abstract class CallBackend {
|
||||||
List<CallParticipant> anyLeft,
|
List<CallParticipant> anyLeft,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Future<void> preShareKey(GroupCallSession groupCall);
|
||||||
|
|
||||||
Future<void> requestEncrytionKey(
|
Future<void> requestEncrytionKey(
|
||||||
GroupCallSession groupCall,
|
GroupCallSession groupCall,
|
||||||
List<CallParticipant> remoteParticipants,
|
List<CallParticipant> remoteParticipants,
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,10 @@ class LiveKitBackend extends CallBackend {
|
||||||
return newIndex;
|
return newIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void> preShareKey(GroupCallSession groupCall) async {
|
Future<void> preShareKey(GroupCallSession groupCall) async {
|
||||||
await groupCall.onMemberStateChanged();
|
await groupCall.onMemberStateChanged();
|
||||||
await _makeNewSenderKey(groupCall, false);
|
await _changeEncryptionKey(groupCall, groupCall.participants, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// makes a new e2ee key for local user and sets it with a delay if specified
|
/// makes a new e2ee key for local user and sets it with a delay if specified
|
||||||
|
|
@ -120,6 +121,19 @@ class LiveKitBackend extends CallBackend {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _changeEncryptionKey(
|
||||||
|
GroupCallSession groupCall,
|
||||||
|
List<CallParticipant> anyJoined,
|
||||||
|
bool delayBeforeUsingKeyOurself,
|
||||||
|
) async {
|
||||||
|
if (!e2eeEnabled) return;
|
||||||
|
if (groupCall.voip.enableSFUE2EEKeyRatcheting) {
|
||||||
|
await _ratchetLocalParticipantKey(groupCall, anyJoined);
|
||||||
|
} else {
|
||||||
|
await _makeNewSenderKey(groupCall, delayBeforeUsingKeyOurself);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// sets incoming keys and also sends the key if it was for the local user
|
/// sets incoming keys and also sends the key if it was for the local user
|
||||||
/// if sendTo is null, its sent to all _participants, see `_sendEncryptionKeysEvent`
|
/// if sendTo is null, its sent to all _participants, see `_sendEncryptionKeysEvent`
|
||||||
Future<void> _setEncryptionKey(
|
Future<void> _setEncryptionKey(
|
||||||
|
|
@ -180,8 +194,6 @@ class LiveKitBackend extends CallBackend {
|
||||||
int keyIndex, {
|
int keyIndex, {
|
||||||
List<CallParticipant>? sendTo,
|
List<CallParticipant>? sendTo,
|
||||||
}) async {
|
}) async {
|
||||||
Logs().i('Sending encryption keys event');
|
|
||||||
|
|
||||||
final myKeys = _getKeysForParticipant(groupCall.localParticipant!);
|
final myKeys = _getKeysForParticipant(groupCall.localParticipant!);
|
||||||
final myLatestKey = myKeys?[keyIndex];
|
final myLatestKey = myKeys?[keyIndex];
|
||||||
|
|
||||||
|
|
@ -235,6 +247,7 @@ class LiveKitBackend extends CallBackend {
|
||||||
Map<String, Object> data,
|
Map<String, Object> data,
|
||||||
String eventType,
|
String eventType,
|
||||||
) async {
|
) async {
|
||||||
|
if (remoteParticipants.isEmpty) return;
|
||||||
Logs().v(
|
Logs().v(
|
||||||
'[VOIP] _sendToDeviceEvent: sending ${data.toString()} to ${remoteParticipants.map((e) => e.id)} ');
|
'[VOIP] _sendToDeviceEvent: sending ${data.toString()} to ${remoteParticipants.map((e) => e.id)} ');
|
||||||
final txid =
|
final txid =
|
||||||
|
|
@ -392,14 +405,8 @@ class LiveKitBackend extends CallBackend {
|
||||||
Future<void> onNewParticipant(
|
Future<void> onNewParticipant(
|
||||||
GroupCallSession groupCall,
|
GroupCallSession groupCall,
|
||||||
List<CallParticipant> anyJoined,
|
List<CallParticipant> anyJoined,
|
||||||
) async {
|
) =>
|
||||||
if (!e2eeEnabled) return;
|
_changeEncryptionKey(groupCall, anyJoined, true);
|
||||||
if (groupCall.voip.enableSFUE2EEKeyRatcheting) {
|
|
||||||
await _ratchetLocalParticipantKey(groupCall, anyJoined);
|
|
||||||
} else {
|
|
||||||
await _makeNewSenderKey(groupCall, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> onLeftParticipant(
|
Future<void> onLeftParticipant(
|
||||||
|
|
|
||||||
|
|
@ -877,4 +877,9 @@ class MeshBackend extends CallBackend {
|
||||||
List<CallParticipant> remoteParticipants) async {
|
List<CallParticipant> remoteParticipants) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> preShareKey(GroupCallSession groupCall) async {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class GroupCallSession {
|
||||||
CallParticipant? get localParticipant => voip.localParticipant;
|
CallParticipant? get localParticipant => voip.localParticipant;
|
||||||
|
|
||||||
List<CallParticipant> get participants => List.unmodifiable(_participants);
|
List<CallParticipant> get participants => List.unmodifiable(_participants);
|
||||||
final List<CallParticipant> _participants = [];
|
final Set<CallParticipant> _participants = {};
|
||||||
|
|
||||||
String groupCallId;
|
String groupCallId;
|
||||||
|
|
||||||
|
|
@ -218,7 +218,7 @@ class GroupCallSession {
|
||||||
'[VOIP] Ignored ${mem.userId}\'s mem event ${mem.toJson()} while updating _participants list for callId: $groupCallId, expiry status: ${mem.isExpired}');
|
'[VOIP] Ignored ${mem.userId}\'s mem event ${mem.toJson()} while updating _participants list for callId: $groupCallId, expiry status: ${mem.isExpired}');
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<CallParticipant> newP = [];
|
final Set<CallParticipant> newP = {};
|
||||||
|
|
||||||
for (final mem in memsForCurrentGroupCall) {
|
for (final mem in memsForCurrentGroupCall) {
|
||||||
final rp = CallParticipant(
|
final rp = CallParticipant(
|
||||||
|
|
@ -239,23 +239,29 @@ class GroupCallSession {
|
||||||
|
|
||||||
await backend.setupP2PCallWithNewMember(this, rp, mem);
|
await backend.setupP2PCallWithNewMember(this, rp, mem);
|
||||||
}
|
}
|
||||||
final newPcopy = List<CallParticipant>.from(newP);
|
final newPcopy = Set<CallParticipant>.from(newP);
|
||||||
final oldPcopy = List<CallParticipant>.from(_participants);
|
final oldPcopy = Set<CallParticipant>.from(_participants);
|
||||||
final anyJoined = newPcopy.where((element) => !oldPcopy.contains(element));
|
final anyJoined = newPcopy.difference(oldPcopy);
|
||||||
final anyLeft = oldPcopy.where((element) => !newPcopy.contains(element));
|
final anyLeft = oldPcopy.difference(newPcopy);
|
||||||
|
|
||||||
if (anyJoined.isNotEmpty || anyLeft.isNotEmpty) {
|
if (anyJoined.isNotEmpty || anyLeft.isNotEmpty) {
|
||||||
if (anyJoined.isNotEmpty) {
|
if (anyJoined.isNotEmpty) {
|
||||||
Logs().d('anyJoined: ${anyJoined.map((e) => e.id).toString()}');
|
final nonLocalAnyJoined = 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);
|
_participants.addAll(anyJoined);
|
||||||
await backend.onNewParticipant(this, anyJoined.toList());
|
|
||||||
}
|
}
|
||||||
if (anyLeft.isNotEmpty) {
|
if (anyLeft.isNotEmpty) {
|
||||||
Logs().d('anyLeft: ${anyLeft.map((e) => e.id).toString()}');
|
final nonLocalAnyLeft = anyLeft..remove(localParticipant);
|
||||||
for (final leftp in anyLeft) {
|
if (nonLocalAnyLeft.isNotEmpty && state == GroupCallState.entered) {
|
||||||
_participants.remove(leftp);
|
Logs().v(
|
||||||
|
'nonLocalAnyLeft: ${nonLocalAnyLeft.map((e) => e.id).toString()} roomId: ${room.id} groupCallId: $groupCallId');
|
||||||
|
await backend.onLeftParticipant(this, nonLocalAnyLeft.toList());
|
||||||
}
|
}
|
||||||
await backend.onLeftParticipant(this, anyLeft.toList());
|
_participants.removeAll(anyLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
onGroupCallEvent.add(GroupCallStateChange.participantsChanged);
|
onGroupCallEvent.add(GroupCallStateChange.participantsChanged);
|
||||||
|
|
|
||||||
|
|
@ -756,37 +756,44 @@ class VoIP {
|
||||||
/// [application] normal group call, thrirdroom, etc
|
/// [application] normal group call, thrirdroom, etc
|
||||||
///
|
///
|
||||||
/// [scope] room, between specifc users, etc.
|
/// [scope] room, between specifc users, etc.
|
||||||
|
///
|
||||||
|
/// [preShareKey] for livekit calls it creates and shares a key with other
|
||||||
|
/// participants in the call without entering, useful on onboarding screens.
|
||||||
|
/// does not do anything in mesh calls
|
||||||
|
|
||||||
Future<GroupCallSession> fetchOrCreateGroupCall(
|
Future<GroupCallSession> fetchOrCreateGroupCall(
|
||||||
String groupCallId,
|
String groupCallId,
|
||||||
Room room,
|
Room room,
|
||||||
CallBackend backend,
|
CallBackend backend,
|
||||||
String? application,
|
String? application,
|
||||||
String? scope,
|
String? scope, {
|
||||||
) async {
|
bool preShareKey = true,
|
||||||
|
}) async {
|
||||||
if (!room.groupCallsEnabledForEveryone) {
|
if (!room.groupCallsEnabledForEveryone) {
|
||||||
await room.enableGroupCalls();
|
await room.enableGroupCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
final groupCall = getGroupCallById(room.id, groupCallId);
|
if (!room.canJoinGroupCall) {
|
||||||
|
throw MatrixSDKVoipException(
|
||||||
if (groupCall != null) {
|
'User ${client.userID}:${client.deviceID} is not allowed to join famedly calls in room ${room.id}, canJoinGroupCall: ${room.canJoinGroupCall}, room.canJoinGroupCall: ${room.groupCallsEnabledForEveryone}',
|
||||||
if (!room.canJoinGroupCall) {
|
);
|
||||||
throw MatrixSDKVoipException(
|
|
||||||
'User ${client.userID}:${client.deviceID} is not allowed to join famedly calls in room ${room.id}, canJoinGroupCall: ${room.canJoinGroupCall}, room.canJoinGroupCall: ${room.groupCallsEnabledForEveryone}',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return groupCall;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The call doesn't exist, but we can create it
|
GroupCallSession? groupCall = getGroupCallById(room.id, groupCallId);
|
||||||
return await _newGroupCall(
|
|
||||||
|
groupCall ??= await _newGroupCall(
|
||||||
groupCallId,
|
groupCallId,
|
||||||
room,
|
room,
|
||||||
backend,
|
backend,
|
||||||
application,
|
application,
|
||||||
scope,
|
scope,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (preShareKey) {
|
||||||
|
await groupCall.backend.preShareKey(groupCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupCall;
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupCallSession? getGroupCallById(String roomId, String groupCallId) {
|
GroupCallSession? getGroupCallById(String roomId, String groupCallId) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue