diff --git a/example/lib/pages/connect.dart b/example/lib/pages/connect.dart index 0dc82a2..8ff76f7 100644 --- a/example/lib/pages/connect.dart +++ b/example/lib/pages/connect.dart @@ -24,6 +24,7 @@ class _ConnectPageState extends State { static const _storeKeySimulcast = 'simulcast'; static const _storeKeyAdaptiveStream = 'adaptive-stream'; static const _storeKeyDynacast = 'dynacast'; + static const _storeKeyFastConnect = 'fast-connect'; final _uriCtrl = TextEditingController(); final _tokenCtrl = TextEditingController(); @@ -31,6 +32,7 @@ class _ConnectPageState extends State { bool _adaptiveStream = true; bool _dynacast = true; bool _busy = false; + bool _fastConnect = false; @override void initState() { @@ -58,6 +60,7 @@ class _ConnectPageState extends State { _simulcast = prefs.getBool(_storeKeySimulcast) ?? true; _adaptiveStream = prefs.getBool(_storeKeyAdaptiveStream) ?? true; _dynacast = prefs.getBool(_storeKeyDynacast) ?? true; + _fastConnect = prefs.getBool(_storeKeyFastConnect) ?? false; }); } @@ -69,6 +72,7 @@ class _ConnectPageState extends State { await prefs.setBool(_storeKeySimulcast, _simulcast); await prefs.setBool(_storeKeyAdaptiveStream, _adaptiveStream); await prefs.setBool(_storeKeyDynacast, _dynacast); + await prefs.setBool(_storeKeyFastConnect, _fastConnect); } Future _connect(BuildContext ctx) async { @@ -84,24 +88,36 @@ class _ConnectPageState extends State { print('Connecting with url: ${_uriCtrl.text}, ' 'token: ${_tokenCtrl.text}...'); - // Try to connect to a room + //create new room + final room = Room(); + + // Create a Listener before connecting + final listener = room.createListener(); + + // Try to connect to the room // This will throw an Exception if it fails for any reason. - final room = await LiveKitClient.connect( + await room.connect( _uriCtrl.text, _tokenCtrl.text, roomOptions: RoomOptions( - adaptiveStream: _adaptiveStream, - dynacast: _dynacast, - defaultVideoPublishOptions: VideoPublishOptions( - simulcast: _simulcast, - ), - defaultScreenShareCaptureOptions: const ScreenShareCaptureOptions( - useiOSBroadcastExtension: true)), + adaptiveStream: _adaptiveStream, + dynacast: _dynacast, + defaultVideoPublishOptions: VideoPublishOptions( + simulcast: _simulcast, + ), + defaultScreenShareCaptureOptions: + const ScreenShareCaptureOptions(useiOSBroadcastExtension: true), + ), + fastConnectOptions: _fastConnect + ? FastConnectOptions( + microphone: const TrackOption(enabled: true), + camera: const TrackOption(enabled: true), + ) + : null, ); - await Navigator.push( ctx, - MaterialPageRoute(builder: (_) => RoomPage(room)), + MaterialPageRoute(builder: (_) => RoomPage(room, listener)), ); } catch (error) { print('Could not connect $error'); @@ -134,6 +150,13 @@ class _ConnectPageState extends State { }); } + void _setFastConnect(bool? value) async { + if (value == null || _fastConnect == value) return; + setState(() { + _fastConnect = value; + }); + } + @override Widget build(BuildContext context) => Scaffold( body: Container( @@ -195,6 +218,19 @@ class _ConnectPageState extends State { ], ), ), + Padding( + padding: const EdgeInsets.only(bottom: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('Fast Connect'), + Switch( + value: _fastConnect, + onChanged: (value) => _setFastConnect(value), + ), + ], + ), + ), Padding( padding: const EdgeInsets.only(bottom: 25), child: Row( diff --git a/example/lib/pages/room.dart b/example/lib/pages/room.dart index 4bd2d10..781c6bb 100644 --- a/example/lib/pages/room.dart +++ b/example/lib/pages/room.dart @@ -11,9 +11,11 @@ import '../widgets/participant.dart'; class RoomPage extends StatefulWidget { // final Room room; + final EventsListener listener; const RoomPage( - this.room, { + this.room, + this.listener, { Key? key, }) : super(key: key); @@ -24,16 +26,19 @@ class RoomPage extends StatefulWidget { class _RoomPageState extends State { // List participants = []; - late final EventsListener _listener = widget.room.createListener(); - + EventsListener get _listener => widget.listener; + bool get fastConnection => widget.room.engine.fastConnectOptions != null; @override void initState() { super.initState(); widget.room.addListener(_onRoomDidUpdate); _setUpListeners(); _sortParticipants(); - WidgetsBindingCompatible.instance - ?.addPostFrameCallback((_) => _askPublish()); + WidgetsBindingCompatible.instance?.addPostFrameCallback((_) { + if (!fastConnection) { + _askPublish(); + } + }); } @override diff --git a/lib/src/core/engine.dart b/lib/src/core/engine.dart index 7d6f586..4961eb5 100644 --- a/lib/src/core/engine.dart +++ b/lib/src/core/engine.dart @@ -64,6 +64,7 @@ class Engine extends Disposable with EventsEmittable { ConnectOptions connectOptions; RoomOptions roomOptions; + FastConnectOptions? fastConnectOptions; bool _subscriberPrimary = false; @@ -100,12 +101,14 @@ class Engine extends Disposable with EventsEmittable { String token, { ConnectOptions? connectOptions, RoomOptions? roomOptions, + FastConnectOptions? fastConnectOptions, }) async { this.url = url; this.token = token; // update new options (if exists) this.connectOptions = connectOptions ?? this.connectOptions; this.roomOptions = roomOptions ?? this.roomOptions; + this.fastConnectOptions = fastConnectOptions; _updateConnectionState(ConnectionState.connecting); diff --git a/lib/src/core/room.dart b/lib/src/core/room.dart index b914d26..64ef845 100644 --- a/lib/src/core/room.dart +++ b/lib/src/core/room.dart @@ -14,6 +14,8 @@ import '../participant/remote.dart'; import '../proto/livekit_models.pb.dart' as lk_models; import '../proto/livekit_rtc.pb.dart' as lk_rtc; import '../support/disposable.dart'; +import '../track/local/audio.dart'; +import '../track/local/video.dart'; import '../track/track.dart'; import '../types/other.dart'; import 'engine.dart'; @@ -117,12 +119,14 @@ class Room extends DisposableChangeNotifier with EventsEmittable { String token, { ConnectOptions? connectOptions, RoomOptions? roomOptions, + FastConnectOptions? fastConnectOptions, }) => engine.connect( url, token, connectOptions: connectOptions, roomOptions: roomOptions, + fastConnectOptions: fastConnectOptions, ); void _setUpSignalListeners() => _signalListener @@ -141,6 +145,32 @@ class Room extends DisposableChangeNotifier with EventsEmittable { info: event.response.participant, ); + if (connectOptions.protocolVersion.index >= ProtocolVersion.v8.index && + engine.fastConnectOptions != null) { + var options = engine.fastConnectOptions!; + + var audio = options.microphone; + if (audio.enabled != null && audio.enabled == true) { + _localParticipant!.setMicrophoneEnabled(true); + } else if (audio.track != null) { + _localParticipant!.publishAudioTrack(audio.track as LocalAudioTrack); + } + + var video = options.camera; + if (video.enabled != null && video.enabled == true) { + _localParticipant!.setCameraEnabled(true); + } else if (video.track != null) { + _localParticipant!.publishVideoTrack(video.track as LocalVideoTrack); + } + + var screen = options.screen; + if (screen.enabled != null && screen.enabled == true) { + _localParticipant!.setScreenShareEnabled(true); + } else if (screen.track != null) { + _localParticipant!.publishVideoTrack(screen.track as LocalVideoTrack); + } + } + for (final info in event.response.otherParticipants) { logger.fine('Creating RemoteParticipant: ${info.sid}(${info.identity}) ' 'tracks:${info.tracks.map((e) => e.sid)}'); diff --git a/lib/src/extensions.dart b/lib/src/extensions.dart index c0de8da..0e8ae8b 100644 --- a/lib/src/extensions.dart +++ b/lib/src/extensions.dart @@ -45,6 +45,7 @@ extension ProtocolVersionExt on ProtocolVersion { ProtocolVersion.v5: '5', ProtocolVersion.v6: '6', ProtocolVersion.v7: '7', + ProtocolVersion.v8: '8', }[this]!; } diff --git a/lib/src/livekit.dart b/lib/src/livekit.dart index cd5b670..3189eea 100644 --- a/lib/src/livekit.dart +++ b/lib/src/livekit.dart @@ -1,5 +1,6 @@ import 'core/room.dart'; import 'options.dart'; +import 'types/other.dart'; /// Main entry point to connect to a room. /// {@category Room} @@ -9,6 +10,8 @@ class LiveKitClient { /// Convenience method for connecting to a LiveKit server. /// Returns a [Room] upon a successful connect or throws when it fails. /// Alternatively, it is possible to instantiate [Room] and call [Room.connect] directly. + @Deprecated( + 'Use `Room.connect` instead, This method is deprecated above Protocol v8.') static Future connect( String url, String token, { @@ -16,11 +19,19 @@ class LiveKitClient { RoomOptions? roomOptions, }) async { final room = Room(); + ConnectOptions copyOptions = ConnectOptions( + autoSubscribe: + connectOptions != null ? connectOptions.autoSubscribe : true, + rtcConfiguration: connectOptions != null + ? connectOptions.rtcConfiguration + : const RTCConfiguration(), + protocolVersion: ProtocolVersion.v7, + ); try { await room.connect( url, token, - connectOptions: connectOptions, + connectOptions: copyOptions, roomOptions: roomOptions, ); return room; diff --git a/lib/src/options.dart b/lib/src/options.dart index 9a6cc3c..c2b61c0 100644 --- a/lib/src/options.dart +++ b/lib/src/options.dart @@ -8,6 +8,23 @@ import 'types/other.dart'; import 'types/video_encoding.dart'; import 'types/video_parameters.dart'; +class TrackOption { + final E? enabled; + final T? track; + const TrackOption({this.enabled, this.track}); +} + +class FastConnectOptions { + FastConnectOptions({ + this.microphone = const TrackOption(enabled: false), + this.camera = const TrackOption(enabled: false), + this.screen = const TrackOption(enabled: false), + }); + final TrackOption microphone; + final TrackOption camera; + final TrackOption screen; +} + /// Options used when connecting to the server. class ConnectOptions { /// Auto-subscribe to existing and new [RemoteTrackPublication]s after @@ -24,7 +41,7 @@ class ConnectOptions { const ConnectOptions({ this.autoSubscribe = true, this.rtcConfiguration = const RTCConfiguration(), - this.protocolVersion = ProtocolVersion.v7, + this.protocolVersion = ProtocolVersion.v8, }); } diff --git a/lib/src/types/other.dart b/lib/src/types/other.dart index 369d82c..572e2fb 100644 --- a/lib/src/types/other.dart +++ b/lib/src/types/other.dart @@ -14,6 +14,7 @@ enum ProtocolVersion { v5, v6, // Session migration v7, // Remote unpublish + v8, } /// Connection state type used throughout the SDK.