diff --git a/example/lib/pages/connect.dart b/example/lib/pages/connect.dart index b13b71136..ac9ca1fe1 100644 --- a/example/lib/pages/connect.dart +++ b/example/lib/pages/connect.dart @@ -135,7 +135,7 @@ class _ConnectPageState extends State { final keyProvider = await BaseKeyProvider.create(); e2eeOptions = E2EEOptions(keyProvider: keyProvider); var sharedKey = _sharedKeyCtrl.text; - await keyProvider.setKey(sharedKey); + await keyProvider.setSharedKey(sharedKey); } String preferredCodec = 'VP8'; diff --git a/ios/livekit_client.podspec b/ios/livekit_client.podspec index 81cbd440f..e7091aa0f 100644 --- a/ios/livekit_client.podspec +++ b/ios/livekit_client.podspec @@ -16,5 +16,5 @@ Pod::Spec.new do |s| s.static_framework = true s.dependency 'Flutter' - s.dependency 'WebRTC-SDK', '114.5735.02' + s.dependency 'WebRTC-SDK', '114.5735.06' end diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index 54134ba46..5b317e117 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -255,6 +255,11 @@ class Room extends DisposableChangeNotifier with EventsEmittable { _getOrCreateRemoteParticipant(info.sid, info); } + if (e2eeManager != null && event.response.sifTrailer.isNotEmpty) { + e2eeManager!.keyProvider + .setSifTrailer(Uint8List.fromList(event.response.sifTrailer)); + } + logger.fine('Room Connect completed'); }) ..on( diff --git a/lib/src/e2ee/e2ee_manager.dart b/lib/src/e2ee/e2ee_manager.dart index 2d3f0c0f4..01d776e62 100644 --- a/lib/src/e2ee/e2ee_manager.dart +++ b/lib/src/e2ee/e2ee_manager.dart @@ -25,8 +25,7 @@ import 'key_provider.dart'; class E2EEManager { Room? _room; - final Map _frameCryptors = {}; - final List _senderFrameCryptors = []; + final Map, FrameCryptor> _frameCryptors = {}; final BaseKeyProvider _keyProvider; final Algorithm _algorithm = Algorithm.kAesGcm; bool _enabled = true; @@ -40,13 +39,10 @@ class E2EEManager { _listener = _room!.createListener(); _listener! ..on((event) async { - var trackId = event.publication.sid; - var participantId = event.participant.sid; var frameCryptor = await _addRtpSender( - event.publication.track!.sender!, - participantId, - trackId, - event.publication.track!.kind.name.toLowerCase()); + sender: event.publication.track!.sender!, + identity: event.participant.identity, + sid: event.publication.sid); if (kIsWeb && event.publication.track!.codec != null) { await frameCryptor.updateCodec(event.publication.track!.codec!); } @@ -63,19 +59,23 @@ class E2EEManager { state: _e2eeStateFromFrameCryptoState(state), )); }; - _senderFrameCryptors.add(frameCryptor); }) ..on((event) async { - var trackId = event.publication.sid; - var frameCryptor = _frameCryptors.remove(trackId); - _senderFrameCryptors.remove(frameCryptor); - await frameCryptor?.dispose(); + for (var key in _frameCryptors.keys.toList()) { + if (key.keys.first == event.participant.identity && + key.values.first == event.publication.sid) { + var frameCryptor = _frameCryptors.remove(key); + await frameCryptor?.setEnabled(false); + await frameCryptor?.dispose(); + } + } }) ..on((event) async { - var trackId = event.publication.sid; - var participantId = event.participant.sid; - var frameCryptor = await _addRtpReceiver(event.track.receiver!, - participantId, trackId, event.track.kind.name.toLowerCase()); + var frameCryptor = await _addRtpReceiver( + receiver: event.track.receiver!, + identity: event.participant.identity, + sid: event.publication.sid, + ); if (kIsWeb) { var codec = event.publication.mimeType.split('/')[1]; await frameCryptor.updateCodec(codec.toLowerCase()); @@ -95,16 +95,28 @@ class E2EEManager { }; }) ..on((event) async { - var trackId = event.publication.sid; - var frameCryptor = _frameCryptors.remove(trackId); - await frameCryptor?.dispose(); + for (var key in _frameCryptors.keys.toList()) { + if (key.keys.first == event.participant.identity && + key.values.first == event.publication.sid) { + var frameCryptor = _frameCryptors.remove(key); + await frameCryptor?.setEnabled(false); + await frameCryptor?.dispose(); + } + } }); } } - Future ratchetKey() async { - for (var frameCryptor in _senderFrameCryptors) { - var newKey = await _keyProvider.ratchetKey(frameCryptor.participantId, 0); + BaseKeyProvider get keyProvider => _keyProvider; + + Future ratchetKey({String? participantId, int? keyIndex}) async { + if (participantId != null) { + var newKey = await _keyProvider.ratchetKey(participantId, keyIndex); + if (kDebugMode) { + print('newKey: $newKey'); + } + } else { + var newKey = await _keyProvider.ratchetSharedKey(keyIndex: keyIndex); if (kDebugMode) { print('newKey: $newKey'); } @@ -121,40 +133,34 @@ class E2EEManager { _frameCryptors.clear(); } - Future _addRtpSender(RTCRtpSender sender, String participantId, - String trackId, String kind) async { - var pid = '$kind-sender-$participantId-$trackId'; + Future _addRtpSender( + {required RTCRtpSender sender, + required String identity, + required String sid}) async { var frameCryptor = await frameCryptorFactory.createFrameCryptorForRtpSender( - participantId: pid, + participantId: identity, sender: sender, algorithm: _algorithm, keyProvider: _keyProvider.keyProvider); - _frameCryptors[trackId] = frameCryptor; + _frameCryptors[{identity: sid}] = frameCryptor; await frameCryptor.setEnabled(_enabled); - if (_keyProvider.options.sharedKey) { - await _keyProvider.keyProvider - .setKey(participantId: pid, index: 0, key: _keyProvider.sharedKey!); - await frameCryptor.setKeyIndex(0); - } + await frameCryptor.setKeyIndex(0); return frameCryptor; } - Future _addRtpReceiver(RTCRtpReceiver receiver, - String participantId, String trackId, String kind) async { - var pid = '$kind-receiver-$participantId-$trackId'; + Future _addRtpReceiver( + {required RTCRtpReceiver receiver, + required String identity, + required String sid}) async { var frameCryptor = await frameCryptorFactory.createFrameCryptorForRtpReceiver( - participantId: pid, + participantId: identity, receiver: receiver, algorithm: _algorithm, keyProvider: _keyProvider.keyProvider); - _frameCryptors[trackId] = frameCryptor; + _frameCryptors[{identity: sid}] = frameCryptor; await frameCryptor.setEnabled(_enabled); - if (_keyProvider.options.sharedKey) { - await _keyProvider.keyProvider - .setKey(participantId: pid, index: 0, key: _keyProvider.sharedKey!); - await frameCryptor.setKeyIndex(0); - } + await frameCryptor.setKeyIndex(0); return frameCryptor; } @@ -162,13 +168,6 @@ class E2EEManager { _enabled = enabled; for (var frameCryptor in _frameCryptors.entries) { await frameCryptor.value.setEnabled(enabled); - if (_keyProvider.options.sharedKey) { - await _keyProvider.keyProvider.setKey( - participantId: frameCryptor.key, - index: 0, - key: _keyProvider.sharedKey!); - await frameCryptor.value.setKeyIndex(0); - } } } diff --git a/lib/src/e2ee/key_provider.dart b/lib/src/e2ee/key_provider.dart index a899f163c..084894f5b 100644 --- a/lib/src/e2ee/key_provider.dart +++ b/lib/src/e2ee/key_provider.dart @@ -32,8 +32,13 @@ class KeyInfo { } abstract class KeyProvider { - Future setKey(String key, {String? participantId, int keyIndex = 0}); - Future ratchetKey(String participantId, int index); + Future setSharedKey(String key, {int? keyIndex}); + Future ratchetSharedKey({int? keyIndex}); + Future exportSharedKey({int? keyIndex}); + Future setKey(String key, {String? participantId, int? keyIndex}); + Future ratchetKey(String participantId, int? keyIndex); + Future exportKey(String participantId, int? keyIndex); + Future setSifTrailer(Uint8List trailer); rtc.KeyProvider get keyProvider; } @@ -54,6 +59,7 @@ class BaseKeyProvider implements KeyProvider { String? ratchetSalt, String? uncryptedMagicBytes, int? ratchetWindowSize, + int? failureTolerance, }) async { rtc.KeyProviderOptions options = rtc.KeyProviderOptions( sharedKey: sharedKey, @@ -62,6 +68,7 @@ class BaseKeyProvider implements KeyProvider { ratchetWindowSize: ratchetWindowSize ?? defaultRatchetWindowSize, uncryptedMagicBytes: Uint8List.fromList( (uncryptedMagicBytes ?? defaultMagicBytes).codeUnits), + failureTolerance: failureTolerance ?? -1, ); final keyProvider = await rtc.frameCryptorFactory.createDefaultKeyProvider(options); @@ -69,19 +76,48 @@ class BaseKeyProvider implements KeyProvider { } @override - Future ratchetKey(String participantId, int index) => - _keyProvider.ratchetKey(participantId: participantId, index: index); + Future setSharedKey(String key, {int? keyIndex}) async { + _sharedKey = Uint8List.fromList(key.codeUnits); + return _keyProvider.setSharedKey(key: _sharedKey!, index: keyIndex ?? 0); + } + + @override + Future ratchetSharedKey({int? keyIndex}) async { + if (_sharedKey == null) { + throw Exception('shared key not set'); + } + _sharedKey = await _keyProvider.ratchetSharedKey(index: keyIndex ?? 0); + return _sharedKey!; + } + + @override + Future exportSharedKey({int? keyIndex}) async { + if (_sharedKey == null) { + throw Exception('shared key not set'); + } + return _keyProvider.exportSharedKey(index: keyIndex ?? 0); + } + + @override + Future ratchetKey(String participantId, int? keyIndex) => + _keyProvider.ratchetKey( + participantId: participantId, index: keyIndex ?? 0); + + @override + Future exportKey(String participantId, int? keyIndex) => + _keyProvider.exportKey( + participantId: participantId, index: keyIndex ?? 0); @override Future setKey(String key, - {String? participantId, int keyIndex = 0}) async { + {String? participantId, int? keyIndex}) async { if (options.sharedKey) { _sharedKey = Uint8List.fromList(key.codeUnits); return; } final keyInfo = KeyInfo( participantId: participantId ?? '', - keyIndex: keyIndex, + keyIndex: keyIndex ?? 0, key: Uint8List.fromList(key.codeUnits), ); return _setKey(keyInfo); @@ -98,4 +134,9 @@ class BaseKeyProvider implements KeyProvider { key: keyInfo.key, ); } + + @override + Future setSifTrailer(Uint8List trailer) async { + return _keyProvider.setSifTrailer(trailer: trailer); + } } diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index cae54572e..2298311f0 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -199,20 +199,20 @@ class LocalParticipant extends Participant { publishOptions.backupCodec!.codec != publishOptions.videoCodec) { simulcastCodecs = [ lk_rtc.SimulcastCodec( - codec: publishOptions.videoCodec, - cid: track.getCid(), - enableSimulcastLayers: true), + codec: publishOptions.videoCodec, + cid: track.getCid(), + ), lk_rtc.SimulcastCodec( - codec: publishOptions.backupCodec!.codec.toLowerCase(), - cid: '', - enableSimulcastLayers: publishOptions.backupCodec!.simulcast), + codec: publishOptions.backupCodec!.codec.toLowerCase(), + cid: '', + ), ]; } else { simulcastCodecs = [ lk_rtc.SimulcastCodec( - codec: publishOptions.videoCodec, - cid: track.getCid(), - enableSimulcastLayers: publishOptions.simulcast), + codec: publishOptions.videoCodec, + cid: track.getCid(), + ), ]; } @@ -618,9 +618,9 @@ class LocalParticipant extends Participant { sid: publication.sid, simulcastCodecs: [ lk_rtc.SimulcastCodec( - codec: backupCodec.toLowerCase(), - cid: cid, - enableSimulcastLayers: backupCodecOpts.simulcast), + codec: backupCodec.toLowerCase(), + cid: cid, + ), ]); await room.engine.negotiate(); diff --git a/macos/livekit_client.podspec b/macos/livekit_client.podspec index f0e7a2545..5ac0eecfd 100644 --- a/macos/livekit_client.podspec +++ b/macos/livekit_client.podspec @@ -16,5 +16,5 @@ Pod::Spec.new do |s| s.static_framework = true s.dependency 'FlutterMacOS' - s.dependency 'WebRTC-SDK', '114.5735.02' + s.dependency 'WebRTC-SDK', '114.5735.06' end diff --git a/pubspec.yaml b/pubspec.yaml index fe719a3be..aa3184ebb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,12 +38,12 @@ dependencies: uuid: ^3.0.6 synchronized: ^3.0.0+3 protobuf: ^3.0.0 - flutter_webrtc: 0.9.41 + flutter_webrtc: 0.9.42 flutter_window_close: ^0.2.2 device_info_plus: ^9.0.0 js: ^0.6.4 platform_detect: ^2.0.7 - dart_webrtc: 1.1.2 + dart_webrtc: 1.1.3 dev_dependencies: flutter_test: