@@ -54,6 +54,7 @@ import '../types/rpc.dart';
5454import '../types/transcription_segment.dart' ;
5555import '../utils.dart' show unpackStreamId;
5656import 'engine.dart' ;
57+ import 'participant_collection.dart' ;
5758import 'pending_track_queue.dart' ;
5859
5960/// Room is the primary construct for LiveKit conferences. It contains a
@@ -72,10 +73,9 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
7273 ConnectOptions get connectOptions => engine.connectOptions;
7374 RoomOptions get roomOptions => engine.roomOptions;
7475
75- /// map of identity: [[RemoteParticipant] ]
76- UnmodifiableMapView <String , RemoteParticipant > get remoteParticipants => UnmodifiableMapView (_remoteParticipants);
77- final _remoteParticipants = < String , RemoteParticipant > {};
78- final Map <String , String > _sidToIdentity = < String , String > {};
76+ final ParticipantCollection <RemoteParticipant > _remoteParticipants = ParticipantCollection ();
77+ UnmodifiableMapView <String , RemoteParticipant > get remoteParticipants =>
78+ UnmodifiableMapView (_remoteParticipants.byIdentity);
7979
8080 /// the current participant
8181 LocalParticipant ? get localParticipant => _localParticipant;
@@ -375,7 +375,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
375375 'allowed:${event .allowed }' );
376376
377377 // find participant
378- final participant = _getRemoteParticipantBySid ( event.participantSid) ;
378+ final participant = _remoteParticipants.bySid[ event.participantSid] ;
379379 if (participant == null ) {
380380 return ;
381381 }
@@ -522,10 +522,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
522522 events.emit (const RoomReconnectingEvent ());
523523
524524 // clean up RemoteParticipants
525- final copy = _remoteParticipants.values.toList ();
526-
527- _remoteParticipants.clear ();
528- _sidToIdentity.clear ();
525+ final copy = _remoteParticipants.removeAll ().toList ();
529526 _activeSpeakers.clear ();
530527 // reset params
531528 _name = null ;
@@ -544,7 +541,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
544541 // re-publish all tracks
545542 await localParticipant? .rePublishAllTracks ();
546543
547- for (var participant in remoteParticipants.values ) {
544+ for (var participant in _remoteParticipants ) {
548545 for (var pub in participant.trackPublications.values) {
549546 if (pub.subscribed) {
550547 pub.sendUpdateTrackSettings ();
@@ -603,7 +600,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
603600 trackSid = streamId;
604601 }
605602
606- final participant = _getRemoteParticipantBySid ( participantSid) ;
603+ final participant = _remoteParticipants.bySid[ participantSid] ;
607604 try {
608605 if (trackSid == null || trackSid.isEmpty) {
609606 throw TrackSubscriptionExceptionEvent (
@@ -667,23 +664,15 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
667664 if (_localParticipant? .identity == identity) {
668665 return _localParticipant;
669666 }
670- return remoteParticipants[identity];
671- }
672-
673- RemoteParticipant ? _getRemoteParticipantBySid (String sid) {
674- final identity = _sidToIdentity[sid];
675- if (identity != null ) {
676- return remoteParticipants[identity];
677- }
678- return null ;
667+ return _remoteParticipants.byIdentity[identity];
679668 }
680669
681670 Future <ParticipantCreationResult > _getOrCreateRemoteParticipant (lk_models.ParticipantInfo info) async {
682671 if (! info.hasIdentity () || ! info.hasSid ()) {
683672 throw Exception ('ParticipantInfo must have identity and sid' );
684673 }
685674
686- final participant = _remoteParticipants[info.identity];
675+ final participant = _remoteParticipants.byIdentity [info.identity];
687676 if (participant != null ) {
688677 // Return existing participant with no new publications; caller handles updates.
689678 return ParticipantCreationResult (
@@ -697,8 +686,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
697686 info: info,
698687 );
699688
700- _remoteParticipants[result.participant.identity] = result.participant;
701- _sidToIdentity[result.participant.sid] = result.participant.identity;
689+ _remoteParticipants.set (result.participant);
702690 events.emit (InternalParticipantAvailableEvent (participant: result.participant));
703691 return result;
704692 }
@@ -720,7 +708,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
720708 continue ;
721709 }
722710
723- final isNew = ! _remoteParticipants.containsKey (info.identity);
711+ final isNew = ! _remoteParticipants.containsIdentity (info.identity);
724712
725713 if (info.state == lk_models.ParticipantInfo_State .DISCONNECTED ) {
726714 hasChanged = await _handleParticipantDisconnect (info.identity);
@@ -743,12 +731,12 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
743731 [result.participant.events, events].emit (event);
744732 }
745733 }
746- _sidToIdentity[info.sid] = info.identity ;
734+ _remoteParticipants. set (result.participant) ;
747735 events.emit (InternalParticipantAvailableEvent (participant: result.participant));
748736 } else {
749737 final wasUpdated = await result.participant.updateFromInfo (info);
750738 if (wasUpdated) {
751- _sidToIdentity[info.sid] = info.identity ;
739+ _remoteParticipants. set (result.participant) ;
752740 events.emit (InternalParticipantAvailableEvent (participant: result.participant));
753741 }
754742 }
@@ -765,7 +753,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
765753 };
766754
767755 for (final speaker in speakers) {
768- Participant ? p = _getRemoteParticipantBySid ( speaker.sid) ;
756+ Participant ? p = _remoteParticipants.bySid[ speaker.sid] ;
769757 if (speaker.sid == localParticipant? .sid) p = localParticipant;
770758 if (p == null ) continue ;
771759
@@ -788,7 +776,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
788776 isConnected: connectionState == ConnectionState .connected,
789777 participantSid: participant? .sid,
790778 subscriber: (pending) async {
791- final target = participant ?? _getRemoteParticipantBySid ( pending.participantSid) ;
779+ final target = participant ?? _remoteParticipants.bySid[ pending.participantSid] ;
792780 if (target == null ) return false ;
793781 try {
794782 await target.addSubscribedMediaTrack (
@@ -818,7 +806,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
818806 // localParticipant & remote participants
819807 final allParticipants = < String , Participant > {
820808 if (localParticipant != null ) localParticipant! .sid: localParticipant! ,
821- ..._remoteParticipants,
809+ ..._remoteParticipants.bySid ,
822810 };
823811
824812 for (final speaker in speakers) {
@@ -849,7 +837,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
849837 if (entry.participantSid == localParticipant? .sid) {
850838 participant = localParticipant;
851839 } else {
852- participant = _getRemoteParticipantBySid ( entry.participantSid) ;
840+ participant = _remoteParticipants.bySid[ entry.participantSid] ;
853841 }
854842
855843 if (participant != null ) {
@@ -861,13 +849,8 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
861849
862850 void _onSignalStreamStateUpdateEvent (List <lk_rtc.StreamStateInfo > updates) async {
863851 for (final update in updates) {
864- final identity = _sidToIdentity[update.participantSid];
865- if (identity == null ) {
866- logger.warning ('participant not found for sid ${update .participantSid }' );
867- continue ;
868- }
869852 // try to find RemoteParticipant
870- final participant = remoteParticipants[identity ];
853+ final participant = _remoteParticipants.bySid[update.participantSid ];
871854 if (participant == null ) continue ;
872855 // try to find RemoteTrackPublication
873856 final trackPublication = participant.trackPublications[update.trackSid];
@@ -935,10 +918,9 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
935918 }
936919
937920 Future <bool > _handleParticipantDisconnect (String identity) async {
938- final participant = _remoteParticipants.remove (identity);
939- if (participant == null ) {
940- return false ;
941- }
921+ final participant = _remoteParticipants.byIdentity[identity];
922+ final removed = _remoteParticipants.removeByIdentity (identity);
923+ if (! removed || participant == null ) return false ;
942924
943925 validateParticipantHasNoActiveDataStreams (identity);
944926
@@ -954,7 +936,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
954936 final trackSids = < String > [];
955937 final trackSidsDisabled = < String > [];
956938
957- for (var participant in remoteParticipants.values ) {
939+ for (var participant in _remoteParticipants ) {
958940 for (var track in participant.trackPublications.values) {
959941 if (track.subscribed != autoSubscribe) {
960942 trackSids.add (track.sid);
@@ -983,14 +965,12 @@ extension RoomPrivateMethods on Room {
983965 logger.fine ('[${objectId }] cleanUp()' );
984966
985967 // clean up RemoteParticipants
986- final participants = _remoteParticipants.values .toList ();
968+ final participants = _remoteParticipants.removeAll () .toList ();
987969 for (final participant in participants) {
988970 await participant.removeAllPublishedTracks (notify: false );
989971 // RemoteParticipant is responsible for disposing resources
990972 await participant.dispose ();
991973 }
992- _remoteParticipants.clear ();
993- _sidToIdentity.clear ();
994974
995975 // clean up LocalParticipant
996976 await localParticipant? .unpublishAllTracks ();
@@ -1102,11 +1082,11 @@ extension RoomHardwareManagementMethods on Room {
11021082 /// Set audio output device.
11031083 Future <void > setAudioOutputDevice (MediaDevice device) async {
11041084 if (lkPlatformIs (PlatformType .web)) {
1105- remoteParticipants. forEach ((_, participant) {
1106- for (var audioTrack in participant.audioTrackPublications) {
1085+ for ( final participant in _remoteParticipants ) {
1086+ for (final audioTrack in participant.audioTrackPublications) {
11071087 audioTrack.track? .setSinkId (device.deviceId);
11081088 }
1109- });
1089+ }
11101090 Hardware .instance.selectedAudioOutput = device;
11111091 } else {
11121092 await Hardware .instance.selectAudioOutput (device);
0 commit comments