From e23131fbbf91f5563be00321db42f0c75d9dd42d Mon Sep 17 00:00:00 2001 From: Hiroshi Horie <548776+hiroshihorie@users.noreply.github.com> Date: Tue, 26 Apr 2022 02:57:24 +0900 Subject: [PATCH] Pass `adaptive_stream` when connecting (#109) * impl * ignore fvm files * Update pubspec.lock * comment --- .gitignore | 5 +++- lib/src/core/engine.dart | 18 ++++++++++---- lib/src/core/room.dart | 41 ++++++++++++++----------------- lib/src/core/signal_client.dart | 5 +++- lib/src/participant/local.dart | 15 ++++++----- lib/src/publication/remote.dart | 3 +-- lib/src/utils.dart | 6 ++--- pubspec.lock | 12 ++++----- test/core/signal_client_test.dart | 25 ++++++++++++++++--- test/mock/e2e_container.dart | 6 ++++- 10 files changed, 84 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index bf53aca..622ffa4 100644 --- a/.gitignore +++ b/.gitignore @@ -79,4 +79,7 @@ build/ *.code-workspace # Windows -_build \ No newline at end of file +_build + +# FVM +.fvm/ diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index c811743..3bf087b 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -61,7 +61,9 @@ class Engine extends Disposable with EventsEmittable { // remember url and token for reconnect String? url; String? token; - ConnectOptions? connectOptions; + + ConnectOptions connectOptions; + RoomOptions roomOptions; bool _subscriberPrimary = false; @@ -71,6 +73,8 @@ class Engine extends Disposable with EventsEmittable { late final _signalListener = signalClient.createListener(synchronized: true); Engine({ + required this.connectOptions, + required this.roomOptions, SignalClient? signalClient, PeerConnectionCreate? peerConnectionCreate, }) : signalClient = signalClient ?? SignalClient(LiveKitWebSocket.connect), @@ -93,12 +97,15 @@ class Engine extends Disposable with EventsEmittable { Future connect( String url, - String token, + String token, { ConnectOptions? connectOptions, - ) async { + RoomOptions? roomOptions, + }) async { this.url = url; this.token = token; - this.connectOptions = connectOptions ?? const ConnectOptions(); + // update new options (if exists) + this.connectOptions = connectOptions ?? this.connectOptions; + this.roomOptions = roomOptions ?? this.roomOptions; _updateConnectionState(ConnectionState.connecting); @@ -108,6 +115,7 @@ class Engine extends Disposable with EventsEmittable { url, token, connectOptions: this.connectOptions, + roomOptions: this.roomOptions, ); // wait for join response @@ -262,6 +270,7 @@ class Engine extends Disposable with EventsEmittable { url!, token!, connectOptions: connectOptions, + roomOptions: roomOptions, reconnect: true, ); @@ -320,7 +329,6 @@ class Engine extends Disposable with EventsEmittable { // RTCConfiguration? config; // use server-provided iceServers if not provided by user - final connectOptions = this.connectOptions ?? const ConnectOptions(); final serverIceServers = _serverProvidedIceServers.map((e) => e.toSDKType()).toList(); diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index 1fd102e..c41a759 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -27,8 +27,11 @@ import 'engine.dart'; /// * active speakers are different /// {@category Room} class Room extends DisposableChangeNotifier with EventsEmittable { + // expose engine's params /// connection state of the room ConnectionState get connectionState => engine.connectionState; + ConnectOptions get connectOptions => engine.connectOptions; + RoomOptions get roomOptions => engine.roomOptions; /// map of SID to RemoteParticipant UnmodifiableMapView get participants => @@ -64,12 +67,6 @@ class Room extends DisposableChangeNotifier with EventsEmittable { UnmodifiableListView(_activeSpeakers); List _activeSpeakers = []; - ConnectOptions? get connectOptions => _connectOptions; - ConnectOptions? _connectOptions; - - RoomOptions? get roomOptions => _roomOptions; - RoomOptions? _roomOptions; - final Engine engine; // suppport for multiple event listeners late final EventsListener _engineListener; @@ -77,12 +74,15 @@ class Room extends DisposableChangeNotifier with EventsEmittable { late final EventsListener _signalListener; Room({ - ConnectOptions? connectOptions, - RoomOptions? roomOptions, + ConnectOptions connectOptions = const ConnectOptions(), + RoomOptions roomOptions = const RoomOptions(), Engine? engine, - }) : _connectOptions = connectOptions, - _roomOptions = roomOptions, - engine = engine ?? Engine() { + }) : engine = engine ?? + Engine( + connectOptions: connectOptions, + roomOptions: roomOptions, + ) { + // _engineListener = this.engine.createListener(); _setUpEngineListeners(); @@ -116,13 +116,13 @@ class Room extends DisposableChangeNotifier with EventsEmittable { String token, { ConnectOptions? connectOptions, RoomOptions? roomOptions, - }) async { - // update options if provided - _connectOptions = connectOptions ?? _connectOptions; - _roomOptions = roomOptions ?? this.roomOptions; - - return engine.connect(url, token, this.connectOptions); - } + }) => + engine.connect( + url, + token, + connectOptions: connectOptions, + roomOptions: roomOptions, + ); void _setUpSignalListeners() => _signalListener ..on((event) { @@ -157,10 +157,8 @@ class Room extends DisposableChangeNotifier with EventsEmittable { ..on( (event) => _onSignalStreamStateUpdateEvent(event.updates)) ..on((event) { - // Signal for Dynacast - final options = roomOptions ?? const RoomOptions(); // Dynacast is off or is unsupported - if (!options.dynacast || _serverVersion == '0.15.1') { + if (!roomOptions.dynacast || _serverVersion == '0.15.1') { logger.fine('Received subscribed quality update' ' but Dynacast is off or server version is not supported.'); return; @@ -456,7 +454,6 @@ class Room extends DisposableChangeNotifier with EventsEmittable { } Future _sendSyncState() async { - final connectOptions = this.connectOptions ?? const ConnectOptions(); final sendUnSub = connectOptions.autoSubscribe; final participantTracks = participants.values.map((e) => e.participantTracks()); diff --git a/lib/src/core/signal_client.dart b/lib/src/core/signal_client.dart index 1454a1c..8c932d9 100644 --- a/lib/src/core/signal_client.dart +++ b/lib/src/core/signal_client.dart @@ -45,13 +45,15 @@ class SignalClient extends Disposable with EventsEmittable { Future connect( String uriString, String token, { - ConnectOptions? connectOptions, + required ConnectOptions connectOptions, + required RoomOptions roomOptions, bool reconnect = false, }) async { final rtcUri = await Utils.buildUri( uriString, token: token, connectOptions: connectOptions, + roomOptions: roomOptions, reconnect: reconnect, ); @@ -85,6 +87,7 @@ class SignalClient extends Disposable with EventsEmittable { uriString, token: token, connectOptions: connectOptions, + roomOptions: roomOptions, validate: true, forceSecure: rtcUri.isSecureScheme, ); diff --git a/lib/src/participant/local.dart b/lib/src/participant/local.dart index b1d5bff..e1ba405 100644 --- a/lib/src/participant/local.dart +++ b/lib/src/participant/local.dart @@ -50,14 +50,14 @@ class LocalParticipant extends Participant { // Use defaultPublishOptions if options is null publishOptions = - publishOptions ?? room.roomOptions?.defaultAudioPublishOptions; + publishOptions ?? room.roomOptions.defaultAudioPublishOptions; final trackInfo = await room.engine.addTrack( cid: track.getCid(), name: track.name, kind: track.kind, source: track.source.toPBType(), - dtx: publishOptions?.dtx, + dtx: publishOptions.dtx, ); await track.start(); @@ -105,7 +105,7 @@ class LocalParticipant extends Participant { // Use defaultPublishOptions if options is null publishOptions = - publishOptions ?? room.roomOptions?.defaultVideoPublishOptions; + publishOptions ?? room.roomOptions.defaultVideoPublishOptions; // use constraints passed to getUserMedia by default VideoDimensions dimensions = track.currentOptions.params.dimensions; @@ -202,8 +202,7 @@ class LocalParticipant extends Participant { final track = pub.track; if (track != null) { - final roomOptions = room.roomOptions ?? const RoomOptions(); - if (roomOptions.stopLocalTrackOnUnpublish) { + if (room.roomOptions.stopLocalTrackOnUnpublish) { await track.stop(); } @@ -304,15 +303,15 @@ class LocalParticipant extends Participant { } else if (enabled) { if (source == TrackSource.camera) { final track = await LocalVideoTrack.createCameraTrack( - room.roomOptions?.defaultCameraCaptureOptions); + room.roomOptions.defaultCameraCaptureOptions); return await publishVideoTrack(track); } else if (source == TrackSource.microphone) { final track = await LocalAudioTrack.create( - room.roomOptions?.defaultAudioCaptureOptions); + room.roomOptions.defaultAudioCaptureOptions); return await publishAudioTrack(track); } else if (source == TrackSource.screenShareVideo) { final track = await LocalVideoTrack.createScreenShareTrack( - room.roomOptions?.defaultScreenShareCaptureOptions); + room.roomOptions.defaultScreenShareCaptureOptions); return await publishVideoTrack(track); } } diff --git a/lib/src/publication/remote.dart b/lib/src/publication/remote.dart index 193d16c..fccc33e 100644 --- a/lib/src/publication/remote.dart +++ b/lib/src/publication/remote.dart @@ -10,7 +10,6 @@ import '../core/signal_client.dart'; import '../events.dart'; import '../extensions.dart'; import '../logger.dart'; -import '../options.dart'; import '../participant/remote.dart'; import '../proto/livekit_models.pb.dart' as lk_models; import '../proto/livekit_rtc.pb.dart' as lk_rtc; @@ -187,7 +186,7 @@ class RemoteTrackPublication _cancelPendingTrackSettingsUpdateRequest?.call(); _visibilityTimer?.cancel(); - final roomOptions = participant.room.roomOptions ?? const RoomOptions(); + final roomOptions = participant.room.roomOptions; if (roomOptions.adaptiveStream && newValue is RemoteVideoTrack) { // Start monitoring visibility _visibilityTimer = Timer.periodic( diff --git a/lib/src/utils.dart b/lib/src/utils.dart index e44fe73..9979a60 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -141,13 +141,12 @@ class Utils { static Future buildUri( String uriString, { required String token, - ConnectOptions? connectOptions, + required ConnectOptions connectOptions, + required RoomOptions roomOptions, bool reconnect = false, bool validate = false, bool forceSecure = false, }) async { - connectOptions ??= const ConnectOptions(); - final Uri uri = Uri.parse(uriString); final useSecure = uri.isSecureScheme || forceSecure; @@ -173,6 +172,7 @@ class Utils { queryParameters: { 'access_token': token, 'auto_subscribe': connectOptions.autoSubscribe ? '1' : '0', + 'adaptive_stream': roomOptions.adaptiveStream ? '1' : '0', if (reconnect) 'reconnect': '1', 'protocol': connectOptions.protocolVersion.toStringValue(), 'sdk': 'flutter', diff --git a/pubspec.lock b/pubspec.lock index 0e4bbbc..e469f5c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,7 +42,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.3.0" built_collection: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.1.4" + version: "8.2.0" characters: dependency: transitive description: @@ -112,7 +112,7 @@ packages: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "2.2.3" dart_webrtc: dependency: "direct main" description: @@ -126,7 +126,7 @@ packages: name: device_info_plus url: "https://pub.dartlang.org" source: hosted - version: "3.2.2" + version: "3.2.3" device_info_plus_linux: dependency: transitive description: @@ -140,7 +140,7 @@ packages: name: device_info_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "2.2.3" device_info_plus_platform_interface: dependency: transitive description: @@ -405,7 +405,7 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" source_span: dependency: transitive description: diff --git a/test/core/signal_client_test.dart b/test/core/signal_client_test.dart index 87ea452..978c1d6 100644 --- a/test/core/signal_client_test.dart +++ b/test/core/signal_client_test.dart @@ -12,6 +12,9 @@ import '../mock/test_data.dart'; import '../mock/websocket_mock.dart'; void main() { + const connectOptions = ConnectOptions(); + const roomOptions = RoomOptions(); + late SignalClient client; late MockWebSocketConnector connector; setUp(() async { @@ -29,7 +32,12 @@ void main() { predicate( (event) => event.newState == ConnectionState.connected), ])); - await client.connect(exampleUri, token); + await client.connect( + exampleUri, + token, + connectOptions: connectOptions, + roomOptions: roomOptions, + ); }); test('reconnect', () async { expect( @@ -41,13 +49,24 @@ void main() { event.newState == ConnectionState.connected && event.didReconnect == true), ])); - await client.connect(exampleUri, token, reconnect: true); + await client.connect( + exampleUri, + token, + connectOptions: connectOptions, + roomOptions: roomOptions, + reconnect: true, + ); }); }); group('messaging', () { test('join', () async { - await client.connect(exampleUri, token); + await client.connect( + exampleUri, + token, + connectOptions: connectOptions, + roomOptions: roomOptions, + ); expect(client.events.streamCtrl.stream, emits(isA())); connector.handlers?.onData!(joinResponse.writeToBuffer()); diff --git a/test/mock/e2e_container.dart b/test/mock/e2e_container.dart index ea2d2b8..91a1e27 100644 --- a/test/mock/e2e_container.dart +++ b/test/mock/e2e_container.dart @@ -15,7 +15,11 @@ class E2EContainer { wsConnector = MockWebSocketConnector(); client = SignalClient(wsConnector.connect); engine = Engine( - signalClient: client, peerConnectionCreate: MockPeerConnection.create); + signalClient: client, + peerConnectionCreate: MockPeerConnection.create, + connectOptions: const ConnectOptions(), + roomOptions: const RoomOptions(), + ); room = Room(engine: engine); }