Skip to content

Commit af28c6a

Browse files
authored
feat: expose participant_active event and joined_at, state fields (#593)
1 parent ba19f00 commit af28c6a

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

livekit-rtc/livekit/rtc/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from ._proto import stats_pb2 as stats
2222
from ._proto.e2ee_pb2 import EncryptionState, EncryptionType
23-
from ._proto.participant_pb2 import ParticipantKind, DisconnectReason
23+
from ._proto.participant_pb2 import ParticipantKind, ParticipantState, DisconnectReason
2424
from ._proto.room_pb2 import (
2525
ConnectionQuality,
2626
ConnectionState,
@@ -145,6 +145,7 @@
145145
"LocalParticipant",
146146
"Participant",
147147
"ParticipantKind",
148+
"ParticipantState",
148149
"DisconnectReason",
149150
"RemoteParticipant",
150151
"ConnectError",

livekit-rtc/livekit/rtc/participant.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import ctypes
1818
import asyncio
19+
import datetime
1920
import os
2021
import mimetypes
2122
import aiofiles
@@ -126,6 +127,20 @@ def kind(self) -> proto_participant.ParticipantKind.ValueType:
126127
"""Participant's kind (e.g., regular participant, ingress, egress, sip, agent)."""
127128
return self._info.kind
128129

130+
@property
131+
def state(self) -> proto_participant.ParticipantState.ValueType:
132+
"""Participant's connection state (joining, joined, active, disconnected)."""
133+
return self._info.state
134+
135+
@property
136+
def joined_at(self) -> datetime.datetime | None:
137+
"""Timestamp of when the participant joined the room, or None if not yet joined."""
138+
if self._info.joined_at == 0:
139+
return None
140+
return datetime.datetime.fromtimestamp(
141+
self._info.joined_at / 1000, tz=datetime.timezone.utc
142+
)
143+
129144
@property
130145
def permissions(self) -> proto_participant.ParticipantPermission:
131146
"""The participant's permissions within the room."""

livekit-rtc/livekit/rtc/room.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
EventTypes = Literal[
5050
"participant_connected",
5151
"participant_disconnected",
52+
"participant_active",
5253
"local_track_published",
5354
"local_track_unpublished",
5455
"local_track_subscribed",
@@ -339,6 +340,8 @@ def on(self, event: EventTypes, callback: Optional[Callable] = None) -> Callable
339340
- Arguments: `participant` (RemoteParticipant)
340341
- **"participant_disconnected"**: Called when a participant leaves the room.
341342
- Arguments: `participant` (RemoteParticipant)
343+
- **"participant_active"**: Called when a remote participant becomes active and is ready to receive data messages.
344+
- Arguments: `participant` (RemoteParticipant)
342345
- **"local_track_published"**: Called when a local track is published.
343346
- Arguments: `publication` (LocalTrackPublication), `track` (Track)
344347
- **"local_track_unpublished"**: Called when a local track is unpublished.
@@ -581,7 +584,7 @@ def unregister_text_stream_handler(self, topic: str):
581584
self._text_stream_handlers.pop(topic)
582585

583586
async def disconnect(
584-
self, *, reason: DisconnectReason = DisconnectReason.CLIENT_INITIATED
587+
self, *, reason: DisconnectReason.ValueType = DisconnectReason.CLIENT_INITIATED
585588
) -> None:
586589
"""Disconnects from the room."""
587590
if not self.isconnected():
@@ -667,6 +670,11 @@ def _on_room_event(self, event: proto_room.RoomEvent):
667670
rparticipant = self._remote_participants.pop(identity)
668671
rparticipant._info.disconnect_reason = event.participant_disconnected.disconnect_reason
669672
self.emit("participant_disconnected", rparticipant)
673+
elif which == "participant_active":
674+
rp = self._retrieve_remote_participant(event.participant_active.participant_identity)
675+
if rp:
676+
rp._info.state = proto_participant.PARTICIPANT_STATE_ACTIVE
677+
self.emit("participant_active", rp)
670678
elif which == "local_track_published":
671679
sid = event.local_track_published.track_sid
672680
lpublication = self.local_participant.track_publications[sid]

0 commit comments

Comments
 (0)