Room to extend ChangeNotifier

This commit is contained in:
David Zhao
2021-07-25 00:05:48 -07:00
parent 0bd2679e94
commit a47c50c3c1
2 changed files with 52 additions and 19 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ class Participant {
Participant(this.sid, this.identity); Participant(this.sid, this.identity);
set isSpeaking(bool speaking) { set isSpeaking(bool speaking) {
if (_isSpeaking != speaking) { if (_isSpeaking == speaking) {
return; return;
} }
_isSpeaking = speaking; _isSpeaking = speaking;
+51 -18
View File
@@ -1,4 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@@ -48,11 +51,24 @@ mixin RoomDelegate {
RemoteParticipant participant, String sid, String? message) {} RemoteParticipant participant, String sid, String? message) {}
} }
class Room with ParticipantDelegate { /// Room is the main entrypoint to working with LiveKit. It provides
RoomState state = RoomState.Disconnected; /// updates to its state via two ways, by assigning a delegate, or using
/// it as a provider.
/// Room will trigger a change update when
/// * state changes
/// * participant membership changes
/// * active speakers are different
class Room extends ChangeNotifier with ParticipantDelegate {
RoomState _state = RoomState.Disconnected;
/// connection state of the room
RoomState get state => _state;
Map<String, RemoteParticipant> _participants = {};
/// map of SID to RemoteParticipant /// map of SID to RemoteParticipant
Map<String, RemoteParticipant> participants = {}; UnmodifiableMapView<String, RemoteParticipant> get participants =>
UnmodifiableMapView(_participants);
/// the current participant /// the current participant
late LocalParticipant localParticipant; late LocalParticipant localParticipant;
@@ -63,8 +79,11 @@ class Room with ParticipantDelegate {
/// sid of the room /// sid of the room
late String sid; late String sid;
List<Participant> _activeSpeakers = [];
/// a list of participants that are actively speaking, including local participant. /// a list of participants that are actively speaking, including local participant.
List<Participant> activeSpeakers = []; UnmodifiableListView<Participant> get activeSpeakers =>
UnmodifiableListView<Participant>(_activeSpeakers);
/// delegate for room events /// delegate for room events
RoomDelegate? delegate; RoomDelegate? delegate;
@@ -93,7 +112,6 @@ class Room with ParticipantDelegate {
logger.fine( logger.fine(
'connected to LiveKit server, version: ${joinResponse.serverVersion}'); 'connected to LiveKit server, version: ${joinResponse.serverVersion}');
state = RoomState.Connected;
localParticipant = new LocalParticipant( localParticipant = new LocalParticipant(
engine: _engine, engine: _engine,
info: joinResponse.participant, info: joinResponse.participant,
@@ -109,10 +127,12 @@ class Room with ParticipantDelegate {
// room is not ready until ICE is connected. so we would return a completer for now // room is not ready until ICE is connected. so we would return a completer for now
// if it times out, we'll fail the completer // if it times out, we'll fail the completer
// Timer(Duration(seconds: 5), () { Timer(Duration(seconds: 5), () {
// _connectCompleter?.completeError(ConnectError()); _state = RoomState.Disconnected;
// _connectCompleter = null; _connectCompleter?.completeError(ConnectError());
// }); _connectCompleter = null;
notifyListeners();
});
return completer.future; return completer.future;
} }
@@ -143,14 +163,16 @@ class Room with ParticipantDelegate {
_handleICEConnected() { _handleICEConnected() {
_connectCompleter?.complete(this); _connectCompleter?.complete(this);
_connectCompleter = null; _connectCompleter = null;
_state = RoomState.Connected;
notifyListeners();
} }
_handleDisconnect() { _handleDisconnect() {
if (state == RoomState.Disconnected) { if (_state == RoomState.Disconnected) {
return; return;
} }
for (var p in participants.values) { for (var p in _participants.values) {
for (var pub in p.tracks.values) { for (var pub in p.tracks.values) {
p.unpublishTrack(pub.sid); p.unpublishTrack(pub.sid);
} }
@@ -160,13 +182,16 @@ class Room with ParticipantDelegate {
} }
_engine.close(); _engine.close();
participants.clear(); _participants.clear();
activeSpeakers.clear(); _activeSpeakers.clear();
state = RoomState.Disconnected; _state = RoomState.Disconnected;
notifyListeners();
delegate?.onDisconnected(); delegate?.onDisconnected();
} }
_handleParticipantUpdate(List<ParticipantInfo> updates) { _handleParticipantUpdate(List<ParticipantInfo> updates) {
// trigger change notifier only if list of participants membership is changed
var hasChanged = false;
for (var info in updates) { for (var info in updates) {
if (localParticipant.sid == info.sid) { if (localParticipant.sid == info.sid) {
localParticipant.updateFromInfo(info); localParticipant.updateFromInfo(info);
@@ -174,19 +199,25 @@ class Room with ParticipantDelegate {
} }
if (info.state == ParticipantInfo_State.DISCONNECTED) { if (info.state == ParticipantInfo_State.DISCONNECTED) {
hasChanged = true;
_handleParticipantDisconnect(info.sid); _handleParticipantDisconnect(info.sid);
continue; continue;
} }
var isNew = !participants.containsKey(info.sid); var isNew = !_participants.containsKey(info.sid);
var participant = _getOrCreateRemoteParticipant(info.sid, info); var participant = _getOrCreateRemoteParticipant(info.sid, info);
if (isNew) { if (isNew) {
hasChanged = true;
delegate?.onParticipantConnected(participant); delegate?.onParticipantConnected(participant);
} else { } else {
participant.updateFromInfo(info); participant.updateFromInfo(info);
} }
} }
if (hasChanged) {
notifyListeners();
}
} }
_handleSpeakerUpdate(List<SpeakerInfo> speakers) { _handleSpeakerUpdate(List<SpeakerInfo> speakers) {
@@ -215,14 +246,16 @@ class Room with ParticipantDelegate {
localParticipant.audioLevel = 0; localParticipant.audioLevel = 0;
localParticipant.isSpeaking = false; localParticipant.isSpeaking = false;
} }
for (var participant in participants.values) { for (var participant in _participants.values) {
if (!seenSids.contains(participant.sid)) { if (!seenSids.contains(participant.sid)) {
participant.audioLevel = 0; participant.audioLevel = 0;
participant.isSpeaking = false; participant.isSpeaking = false;
} }
} }
activeSpeakers = newSpeakers;
_activeSpeakers = newSpeakers;
delegate?.onActiveSpeakersChanged(newSpeakers); delegate?.onActiveSpeakersChanged(newSpeakers);
notifyListeners();
} }
_handleDataPacket(UserPacket packet, DataPacket_Kind kind) { _handleDataPacket(UserPacket packet, DataPacket_Kind kind) {
@@ -254,7 +287,7 @@ class Room with ParticipantDelegate {
} }
_handleParticipantDisconnect(String sid) { _handleParticipantDisconnect(String sid) {
var participant = participants.remove(sid); var participant = _participants.remove(sid);
if (participant == null) { if (participant == null) {
return; return;
} }