@@ -817,10 +817,19 @@ def _on_room_event(self, event: proto_room.RoomEvent) -> None:
817817 lpublication ._first_subscription .set_result (None )
818818 self .emit ("local_track_subscribed" , lpublication .track )
819819 elif which == "track_published" :
820- rparticipant = self ._remote_participants [event .track_published .participant_identity ]
821- rpublication = RemoteTrackPublication (event .track_published .publication )
822- rparticipant ._track_publications [rpublication .sid ] = rpublication
823- self .emit ("track_published" , rpublication , rparticipant )
820+ # The participant may already have been removed by a racing
821+ # disconnect or a duplicate event, so the lookup is done defensively
822+ # and the emit is skipped when the participant is gone, mirroring the
823+ # track_unpublished handler, instead of raising a KeyError that
824+ # _listen_task logs as an error.
825+ identity = event .track_published .participant_identity
826+ published_participant = self ._remote_participants .get (identity )
827+ if published_participant is not None :
828+ published = RemoteTrackPublication (event .track_published .publication )
829+ published_participant ._track_publications [published .sid ] = published
830+ self .emit ("track_published" , published , published_participant )
831+ else :
832+ logger .debug ("track_published for untracked participant %s" , identity )
824833 elif which == "track_unpublished" :
825834 # The participant or publication may already have been removed by a
826835 # racing disconnect or a duplicate event, so both lookups are done
@@ -839,41 +848,85 @@ def _on_room_event(self, event: proto_room.RoomEvent) -> None:
839848 else :
840849 logger .debug ("track_unpublished for untracked participant %s" , identity )
841850 elif which == "track_subscribed" :
851+ # The participant or publication may already have been removed by a
852+ # racing disconnect or unpublish, so both lookups are done
853+ # defensively and the emit is skipped when either entry is gone,
854+ # mirroring the track_unpublished handler, instead of raising a
855+ # KeyError that _listen_task logs as an error.
842856 owned_track_info = event .track_subscribed .track
843857 track_info = owned_track_info .info
844- rparticipant = self ._remote_participants [event .track_subscribed .participant_identity ]
845- rpublication = rparticipant .track_publications [track_info .sid ]
846- rpublication ._subscribed = True
847- if track_info .kind == TrackKind .KIND_VIDEO :
848- remote_video_track = RemoteVideoTrack (owned_track_info )
849- remote_video_track ._set_room (self )
850- rpublication ._track = remote_video_track
851- self .emit ("track_subscribed" , remote_video_track , rpublication , rparticipant )
852- elif track_info .kind == TrackKind .KIND_AUDIO :
853- remote_audio_track = RemoteAudioTrack (owned_track_info )
854- remote_audio_track ._set_room (self )
855- rpublication ._track = remote_audio_track
856- self .emit ("track_subscribed" , remote_audio_track , rpublication , rparticipant )
858+ identity = event .track_subscribed .participant_identity
859+ subscribed_participant = self ._remote_participants .get (identity )
860+ subscribed = (
861+ subscribed_participant .track_publications .get (track_info .sid )
862+ if subscribed_participant is not None
863+ else None
864+ )
865+ if subscribed_participant is not None and subscribed is not None :
866+ subscribed ._subscribed = True
867+ if track_info .kind == TrackKind .KIND_VIDEO :
868+ remote_video_track = RemoteVideoTrack (owned_track_info )
869+ remote_video_track ._set_room (self )
870+ subscribed ._track = remote_video_track
871+ self .emit (
872+ "track_subscribed" , remote_video_track , subscribed , subscribed_participant
873+ )
874+ elif track_info .kind == TrackKind .KIND_AUDIO :
875+ remote_audio_track = RemoteAudioTrack (owned_track_info )
876+ remote_audio_track ._set_room (self )
877+ subscribed ._track = remote_audio_track
878+ self .emit (
879+ "track_subscribed" , remote_audio_track , subscribed , subscribed_participant
880+ )
881+ else :
882+ logger .debug (
883+ "track_subscribed for untracked participant %s or publication %s" ,
884+ identity ,
885+ track_info .sid ,
886+ )
857887 elif which == "track_unsubscribed" :
888+ # The participant or publication may already have been removed by a
889+ # racing disconnect or unpublish, so both lookups are done
890+ # defensively and the emit is skipped when either entry is gone,
891+ # mirroring the track_unpublished handler, instead of raising a
892+ # KeyError that _listen_task logs as an error.
858893 identity = event .track_unsubscribed .participant_identity
859- rparticipant = self ._remote_participants [identity ]
860- rpublication = rparticipant .track_publications [event .track_unsubscribed .track_sid ]
861- rtrack = rpublication .track
862- if rtrack is not None :
863- rtrack ._set_room (None )
864- rpublication ._track = None
865- rpublication ._subscribed = False
866- self .emit ("track_unsubscribed" , rtrack , rpublication , rparticipant )
894+ unsubscribed_participant = self ._remote_participants .get (identity )
895+ unsubscribed = (
896+ unsubscribed_participant .track_publications .get (event .track_unsubscribed .track_sid )
897+ if unsubscribed_participant is not None
898+ else None
899+ )
900+ if unsubscribed_participant is not None and unsubscribed is not None :
901+ rtrack = unsubscribed .track
902+ if rtrack is not None :
903+ rtrack ._set_room (None )
904+ unsubscribed ._track = None
905+ unsubscribed ._subscribed = False
906+ self .emit ("track_unsubscribed" , rtrack , unsubscribed , unsubscribed_participant )
907+ else :
908+ logger .debug (
909+ "track_unsubscribed for untracked participant %s or publication %s" ,
910+ identity ,
911+ event .track_unsubscribed .track_sid ,
912+ )
867913 elif which == "track_subscription_failed" :
914+ # The participant may already have been removed by a racing
915+ # disconnect, so the lookup is done defensively and the emit is
916+ # skipped when the participant is gone, instead of raising a KeyError
917+ # that _listen_task logs as an error.
868918 identity = event .track_subscription_failed .participant_identity
869- rparticipant = self ._remote_participants [identity ]
870- error = event .track_subscription_failed .error
871- self .emit (
872- "track_subscription_failed" ,
873- rparticipant ,
874- event .track_subscription_failed .track_sid ,
875- error ,
876- )
919+ failed_participant = self ._remote_participants .get (identity )
920+ if failed_participant is not None :
921+ error = event .track_subscription_failed .error
922+ self .emit (
923+ "track_subscription_failed" ,
924+ failed_participant ,
925+ event .track_subscription_failed .track_sid ,
926+ error ,
927+ )
928+ else :
929+ logger .debug ("track_subscription_failed for untracked participant %s" , identity )
877930 elif which == "track_muted" :
878931 identity = event .track_muted .participant_identity
879932 # TODO: pass participant identity
0 commit comments