Create room without connecting (#49)

* initial commit

* fix example compile

* format

* clean up

* fix check

* missing import
This commit is contained in:
Hiroshi Horie
2021-12-07 17:02:58 +07:00
committed by GitHub
parent c4e56af4c0
commit 0f5a758cd4
5 changed files with 73 additions and 87 deletions
+15 -10
View File
@@ -68,13 +68,13 @@ class _RoomPageState extends State<RoomPage> {
if (result != true) return; if (result != true) return;
// video will fail when running in ios simulator // video will fail when running in ios simulator
try { try {
await widget.room.localParticipant.setCameraEnabled(true); await widget.room.localParticipant?.setCameraEnabled(true);
} catch (error) { } catch (error) {
print('could not publish video: $error'); print('could not publish video: $error');
await context.showErrorDialog(error); await context.showErrorDialog(error);
} }
try { try {
await widget.room.localParticipant.setMicrophoneEnabled(true); await widget.room.localParticipant?.setMicrophoneEnabled(true);
} catch (error) { } catch (error) {
print('could not publish audio: $error'); print('could not publish audio: $error');
await context.showErrorDialog(error); await context.showErrorDialog(error);
@@ -117,10 +117,13 @@ class _RoomPageState extends State<RoomPage> {
b.joinedAt.millisecondsSinceEpoch; b.joinedAt.millisecondsSinceEpoch;
}); });
if (participants.length > 1) { final localParticipant = widget.room.localParticipant;
participants.insert(1, widget.room.localParticipant); if (localParticipant != null) {
} else { if (participants.length > 1) {
participants.add(widget.room.localParticipant); participants.insert(1, localParticipant);
} else {
participants.add(localParticipant);
}
} }
setState(() { setState(() {
this.participants = participants; this.participants = participants;
@@ -147,10 +150,12 @@ class _RoomPageState extends State<RoomPage> {
), ),
), ),
), ),
SafeArea( if (widget.room.localParticipant != null)
top: false, SafeArea(
child: ControlsWidget(widget.room), top: false,
), child:
ControlsWidget(widget.room, widget.room.localParticipant!),
),
], ],
), ),
); );
+5 -5
View File
@@ -14,11 +14,11 @@ class ControlsWidget extends StatefulWidget {
final Room room; final Room room;
final LocalParticipant participant; final LocalParticipant participant;
ControlsWidget( const ControlsWidget(
this.room, { this.room,
this.participant, {
Key? key, Key? key,
}) : participant = room.localParticipant, }) : super(key: key);
super(key: key);
@override @override
State<StatefulWidget> createState() => _ControlsWidgetState(); State<StatefulWidget> createState() => _ControlsWidgetState();
@@ -132,7 +132,7 @@ class _ControlsWidgetState extends State<ControlsWidget> {
void _onTapSendData() async { void _onTapSendData() async {
final result = await context.showSendDataDialog(); final result = await context.showSendDataDialog();
if (result == true) { if (result == true) {
await widget.room.localParticipant.publishData( await widget.participant.publishData(
utf8.encode('This is a sample data message'), utf8.encode('This is a sample data message'),
); );
} }
+10 -2
View File
@@ -11,10 +11,18 @@ class LiveKitClient {
String url, String url,
String token, { String token, {
ConnectOptions? options, ConnectOptions? options,
}) => }) async {
Room.connect( final room = Room();
try {
await room.connect(
url, url,
token, token,
options: options, options: options,
); );
return room;
} catch (error) {
await room.dispose();
rethrow;
}
}
} }
+39 -67
View File
@@ -42,13 +42,13 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
UnmodifiableMapView(_participants); UnmodifiableMapView(_participants);
/// the current participant /// the current participant
late final LocalParticipant localParticipant; LocalParticipant? localParticipant;
/// name of the room /// name of the room
final String name; String? name;
/// sid of the room /// sid of the room
final String sid; String? sid;
List<Participant> _activeSpeakers = []; List<Participant> _activeSpeakers = [];
@@ -61,29 +61,13 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// suppport for multiple event listeners // suppport for multiple event listeners
late final _engineListener = engine.createListener(); late final _engineListener = engine.createListener();
/// internal use Room({
/// {@nodoc} RTCEngine? engine,
Room._({
required this.engine,
required lk_rtc.JoinResponse joinResponse,
ConnectOptions? connectOptions, ConnectOptions? connectOptions,
}) : sid = joinResponse.room.sid, }) : engine = engine ?? RTCEngine() {
name = joinResponse.room.name {
// //
_setUpListeners(); _setUpListeners();
localParticipant = LocalParticipant(
engine: engine,
info: joinResponse.participant,
defaultVideoPublishOptions: connectOptions?.defaultVideoPublishOptions,
defaultAudioPublishOptions: connectOptions?.defaultAudioPublishOptions,
roomEvents: events,
);
for (final info in joinResponse.otherParticipants) {
_getOrCreateRemoteParticipant(info.sid, info);
}
// Any event emitted will trigger ChangeNotifier // Any event emitted will trigger ChangeNotifier
events.listen((event) { events.listen((event) {
logger.fine('[RoomEvent] $event, will notifyListeners()'); logger.fine('[RoomEvent] $event, will notifyListeners()');
@@ -94,63 +78,51 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// dispose events // dispose events
await events.dispose(); await events.dispose();
// dispose local participant // dispose local participant
await localParticipant.dispose(); await localParticipant?.dispose();
// dispose all listeners for RTCEngine // dispose all listeners for RTCEngine
await _engineListener.dispose(); await _engineListener.dispose();
// dispose the engine // dispose the engine
await engine.dispose(); await this.engine.dispose();
}); });
} }
static Future<Room> connect( Future<void> connect(
String url, String url,
String token, { String token, {
ConnectOptions? options, ConnectOptions? options,
RTCConfiguration? rtcConfig, RTCConfiguration? rtcConfig,
}) async { }) async {
// //
final engine = RTCEngine( final joinResponse = await engine.join(
rtcConfig, url,
token,
connectOptions: options,
); );
Room? room; sid = joinResponse.room.sid;
name = joinResponse.room.name;
try { logger.fine(
final joinResponse = await engine.join( 'Connected to LiveKit server, version: ${joinResponse.serverVersion}');
url,
token,
connectOptions: options,
);
logger.fine( logger.fine('Waiting to engine connect...');
'Connected to LiveKit server, version: ${joinResponse.serverVersion}');
// create Room first to listen to events // wait until engine is connected
room = Room._( await _engineListener.waitFor<EngineConnectedEvent>(
engine: engine, duration: Timeouts.connection,
joinResponse: joinResponse, onTimeout: () => throw ConnectException(),
connectOptions: options, );
);
logger.fine('Waiting to engine connect...'); localParticipant = LocalParticipant(
engine: engine,
info: joinResponse.participant,
defaultVideoPublishOptions: options?.defaultVideoPublishOptions,
defaultAudioPublishOptions: options?.defaultAudioPublishOptions,
roomEvents: events,
);
// wait until engine is connected for (final info in joinResponse.otherParticipants) {
await room._engineListener.waitFor<EngineConnectedEvent>( _getOrCreateRemoteParticipant(info.sid, info);
duration: Timeouts.connection,
onTimeout: () => throw ConnectException(),
);
return room;
// catch any exception
} catch (_) {
// dispose engine if there was any exception while connecting
if (room != null) {
// room.dispose will also dispose engine
await room.dispose();
} else {
await engine.dispose();
}
rethrow;
} }
} }
@@ -178,7 +150,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
(event) => _onSignalConnectionQualityUpdateEvent(event.updates)) (event) => _onSignalConnectionQualityUpdateEvent(event.updates))
..on<EngineDataPacketReceivedEvent>(_onDataMessageEvent) ..on<EngineDataPacketReceivedEvent>(_onDataMessageEvent)
..on<EngineRemoteMuteChangedEvent>((event) async { ..on<EngineRemoteMuteChangedEvent>((event) async {
final publication = localParticipant.trackPublications[event.sid]; final publication = localParticipant?.trackPublications[event.sid];
if (event.muted) { if (event.muted) {
await publication?.mute(); await publication?.mute();
} else { } else {
@@ -266,7 +238,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
_participants.clear(); _participants.clear();
// clean up LocalParticipant // clean up LocalParticipant
await localParticipant.unpublishAllTracks(); await localParticipant?.unpublishAllTracks();
// clean up engine // clean up engine
await engine.close(); await engine.close();
@@ -285,8 +257,8 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// trigger change notifier only if list of participants membership is changed // trigger change notifier only if list of participants membership is changed
var hasChanged = false; var hasChanged = false;
for (final info in updates) { for (final info in updates) {
if (localParticipant.sid == info.sid) { if (localParticipant?.sid == info.sid) {
localParticipant.updateFromInfo(info); localParticipant?.updateFromInfo(info);
continue; continue;
} }
@@ -320,7 +292,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
for (final speaker in speakers) { for (final speaker in speakers) {
Participant? p = _participants[speaker.sid]; Participant? p = _participants[speaker.sid];
if (speaker.sid == localParticipant.sid) p = localParticipant; if (speaker.sid == localParticipant?.sid) p = localParticipant;
if (p == null) continue; if (p == null) continue;
p.audioLevel = speaker.level; p.audioLevel = speaker.level;
@@ -346,7 +318,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// localParticipant & remote participants // localParticipant & remote participants
final allParticipants = <String, Participant>{ final allParticipants = <String, Participant>{
localParticipant.sid: localParticipant, if (localParticipant != null) localParticipant!.sid: localParticipant!,
..._participants, ..._participants,
}; };
@@ -376,7 +348,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
List<lk_rtc.ConnectionQualityInfo> updates) { List<lk_rtc.ConnectionQualityInfo> updates) {
for (final entry in updates) { for (final entry in updates) {
Participant? participant; Participant? participant;
if (entry.participantSid == localParticipant.sid) { if (entry.participantSid == localParticipant?.sid) {
participant = localParticipant; participant = localParticipant;
} else { } else {
participant = _participants[entry.participantSid]; participant = _participants[entry.participantSid];
+4 -3
View File
@@ -29,7 +29,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
final SignalClient signalClient; final SignalClient signalClient;
// config for RTCPeerConnection // config for RTCPeerConnection
final RTCConfiguration? rtcConfig; RTCConfiguration? rtcConfig;
ConnectOptions connectOptions = const ConnectOptions(); ConnectOptions connectOptions = const ConnectOptions();
@@ -71,8 +71,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
final delays = CancelableDelayManager(); final delays = CancelableDelayManager();
RTCEngine( RTCEngine({
this.rtcConfig, {
SignalClient? signalClient, SignalClient? signalClient,
}) : signalClient = signalClient ?? SignalClient() { }) : signalClient = signalClient ?? SignalClient() {
if (kDebugMode) { if (kDebugMode) {
@@ -94,11 +93,13 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
Future<lk_rtc.JoinResponse> join( Future<lk_rtc.JoinResponse> join(
String url, String url,
String token, { String token, {
RTCConfiguration? rtcConfig,
ConnectOptions? connectOptions, ConnectOptions? connectOptions,
}) async { }) async {
this.url = url; this.url = url;
this.token = token; this.token = token;
this.rtcConfig = rtcConfig;
if (connectOptions != null) { if (connectOptions != null) {
this.connectOptions = connectOptions; this.connectOptions = connectOptions;
} }