Create room without connecting (#49)
* initial commit * fix example compile * format * clean up * fix check * missing import
This commit is contained in:
+15
-10
@@ -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!),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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];
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user