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;
// video will fail when running in ios simulator
try {
await widget.room.localParticipant.setCameraEnabled(true);
await widget.room.localParticipant?.setCameraEnabled(true);
} catch (error) {
print('could not publish video: $error');
await context.showErrorDialog(error);
}
try {
await widget.room.localParticipant.setMicrophoneEnabled(true);
await widget.room.localParticipant?.setMicrophoneEnabled(true);
} catch (error) {
print('could not publish audio: $error');
await context.showErrorDialog(error);
@@ -117,10 +117,13 @@ class _RoomPageState extends State<RoomPage> {
b.joinedAt.millisecondsSinceEpoch;
});
if (participants.length > 1) {
participants.insert(1, widget.room.localParticipant);
} else {
participants.add(widget.room.localParticipant);
final localParticipant = widget.room.localParticipant;
if (localParticipant != null) {
if (participants.length > 1) {
participants.insert(1, localParticipant);
} else {
participants.add(localParticipant);
}
}
setState(() {
this.participants = participants;
@@ -147,10 +150,12 @@ class _RoomPageState extends State<RoomPage> {
),
),
),
SafeArea(
top: false,
child: ControlsWidget(widget.room),
),
if (widget.room.localParticipant != null)
SafeArea(
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 LocalParticipant participant;
ControlsWidget(
this.room, {
const ControlsWidget(
this.room,
this.participant, {
Key? key,
}) : participant = room.localParticipant,
super(key: key);
}) : super(key: key);
@override
State<StatefulWidget> createState() => _ControlsWidgetState();
@@ -132,7 +132,7 @@ class _ControlsWidgetState extends State<ControlsWidget> {
void _onTapSendData() async {
final result = await context.showSendDataDialog();
if (result == true) {
await widget.room.localParticipant.publishData(
await widget.participant.publishData(
utf8.encode('This is a sample data message'),
);
}
+10 -2
View File
@@ -11,10 +11,18 @@ class LiveKitClient {
String url,
String token, {
ConnectOptions? options,
}) =>
Room.connect(
}) async {
final room = Room();
try {
await room.connect(
url,
token,
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);
/// the current participant
late final LocalParticipant localParticipant;
LocalParticipant? localParticipant;
/// name of the room
final String name;
String? name;
/// sid of the room
final String sid;
String? sid;
List<Participant> _activeSpeakers = [];
@@ -61,29 +61,13 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// suppport for multiple event listeners
late final _engineListener = engine.createListener();
/// internal use
/// {@nodoc}
Room._({
required this.engine,
required lk_rtc.JoinResponse joinResponse,
Room({
RTCEngine? engine,
ConnectOptions? connectOptions,
}) : sid = joinResponse.room.sid,
name = joinResponse.room.name {
}) : engine = engine ?? RTCEngine() {
//
_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
events.listen((event) {
logger.fine('[RoomEvent] $event, will notifyListeners()');
@@ -94,63 +78,51 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// dispose events
await events.dispose();
// dispose local participant
await localParticipant.dispose();
await localParticipant?.dispose();
// dispose all listeners for RTCEngine
await _engineListener.dispose();
// dispose the engine
await engine.dispose();
await this.engine.dispose();
});
}
static Future<Room> connect(
Future<void> connect(
String url,
String token, {
ConnectOptions? options,
RTCConfiguration? rtcConfig,
}) async {
//
final engine = RTCEngine(
rtcConfig,
final joinResponse = await engine.join(
url,
token,
connectOptions: options,
);
Room? room;
sid = joinResponse.room.sid;
name = joinResponse.room.name;
try {
final joinResponse = await engine.join(
url,
token,
connectOptions: options,
);
logger.fine(
'Connected to LiveKit server, version: ${joinResponse.serverVersion}');
logger.fine(
'Connected to LiveKit server, version: ${joinResponse.serverVersion}');
logger.fine('Waiting to engine connect...');
// create Room first to listen to events
room = Room._(
engine: engine,
joinResponse: joinResponse,
connectOptions: options,
);
// wait until engine is connected
await _engineListener.waitFor<EngineConnectedEvent>(
duration: Timeouts.connection,
onTimeout: () => throw ConnectException(),
);
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
await room._engineListener.waitFor<EngineConnectedEvent>(
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;
for (final info in joinResponse.otherParticipants) {
_getOrCreateRemoteParticipant(info.sid, info);
}
}
@@ -178,7 +150,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
(event) => _onSignalConnectionQualityUpdateEvent(event.updates))
..on<EngineDataPacketReceivedEvent>(_onDataMessageEvent)
..on<EngineRemoteMuteChangedEvent>((event) async {
final publication = localParticipant.trackPublications[event.sid];
final publication = localParticipant?.trackPublications[event.sid];
if (event.muted) {
await publication?.mute();
} else {
@@ -266,7 +238,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
_participants.clear();
// clean up LocalParticipant
await localParticipant.unpublishAllTracks();
await localParticipant?.unpublishAllTracks();
// clean up engine
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
var hasChanged = false;
for (final info in updates) {
if (localParticipant.sid == info.sid) {
localParticipant.updateFromInfo(info);
if (localParticipant?.sid == info.sid) {
localParticipant?.updateFromInfo(info);
continue;
}
@@ -320,7 +292,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
for (final speaker in speakers) {
Participant? p = _participants[speaker.sid];
if (speaker.sid == localParticipant.sid) p = localParticipant;
if (speaker.sid == localParticipant?.sid) p = localParticipant;
if (p == null) continue;
p.audioLevel = speaker.level;
@@ -346,7 +318,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
// localParticipant & remote participants
final allParticipants = <String, Participant>{
localParticipant.sid: localParticipant,
if (localParticipant != null) localParticipant!.sid: localParticipant!,
..._participants,
};
@@ -376,7 +348,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
List<lk_rtc.ConnectionQualityInfo> updates) {
for (final entry in updates) {
Participant? participant;
if (entry.participantSid == localParticipant.sid) {
if (entry.participantSid == localParticipant?.sid) {
participant = localParticipant;
} else {
participant = _participants[entry.participantSid];
+4 -3
View File
@@ -29,7 +29,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
final SignalClient signalClient;
// config for RTCPeerConnection
final RTCConfiguration? rtcConfig;
RTCConfiguration? rtcConfig;
ConnectOptions connectOptions = const ConnectOptions();
@@ -71,8 +71,7 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
final delays = CancelableDelayManager();
RTCEngine(
this.rtcConfig, {
RTCEngine({
SignalClient? signalClient,
}) : signalClient = signalClient ?? SignalClient() {
if (kDebugMode) {
@@ -94,11 +93,13 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
Future<lk_rtc.JoinResponse> join(
String url,
String token, {
RTCConfiguration? rtcConfig,
ConnectOptions? connectOptions,
}) async {
this.url = url;
this.token = token;
this.rtcConfig = rtcConfig;
if (connectOptions != null) {
this.connectOptions = connectOptions;
}