Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion livekit-rtc/livekit/rtc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from ._proto import stats_pb2 as stats
from ._proto.e2ee_pb2 import EncryptionState, EncryptionType
from ._proto.participant_pb2 import ParticipantKind, DisconnectReason
from ._proto.participant_pb2 import ParticipantKind, ParticipantState, DisconnectReason
from ._proto.room_pb2 import (
ConnectionQuality,
ConnectionState,
Expand Down Expand Up @@ -145,6 +145,7 @@
"LocalParticipant",
"Participant",
"ParticipantKind",
"ParticipantState",
"DisconnectReason",
"RemoteParticipant",
"ConnectError",
Expand Down
15 changes: 15 additions & 0 deletions livekit-rtc/livekit/rtc/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import ctypes
import asyncio
import datetime
import os
import mimetypes
import aiofiles
Expand Down Expand Up @@ -126,6 +127,20 @@ def kind(self) -> proto_participant.ParticipantKind.ValueType:
"""Participant's kind (e.g., regular participant, ingress, egress, sip, agent)."""
return self._info.kind

@property
def state(self) -> proto_participant.ParticipantState.ValueType:
"""Participant's connection state (joining, joined, active, disconnected)."""
return self._info.state

@property
def joined_at(self) -> datetime.datetime | None:
"""Timestamp of when the participant joined the room, or None if not yet joined."""
if self._info.joined_at == 0:
return None
return datetime.datetime.fromtimestamp(
self._info.joined_at / 1000, tz=datetime.timezone.utc
)

@property
def permissions(self) -> proto_participant.ParticipantPermission:
"""The participant's permissions within the room."""
Expand Down
10 changes: 9 additions & 1 deletion livekit-rtc/livekit/rtc/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
EventTypes = Literal[
"participant_connected",
"participant_disconnected",
"participant_active",
"local_track_published",
"local_track_unpublished",
"local_track_subscribed",
Expand Down Expand Up @@ -339,6 +340,8 @@ def on(self, event: EventTypes, callback: Optional[Callable] = None) -> Callable
- Arguments: `participant` (RemoteParticipant)
- **"participant_disconnected"**: Called when a participant leaves the room.
- Arguments: `participant` (RemoteParticipant)
- **"participant_active"**: Called when a remote participant becomes active and is ready to receive data messages.
- Arguments: `participant` (RemoteParticipant)
- **"local_track_published"**: Called when a local track is published.
- Arguments: `publication` (LocalTrackPublication), `track` (Track)
- **"local_track_unpublished"**: Called when a local track is unpublished.
Expand Down Expand Up @@ -581,7 +584,7 @@ def unregister_text_stream_handler(self, topic: str):
self._text_stream_handlers.pop(topic)

async def disconnect(
self, *, reason: DisconnectReason = DisconnectReason.CLIENT_INITIATED
self, *, reason: DisconnectReason.ValueType = DisconnectReason.CLIENT_INITIATED
) -> None:
"""Disconnects from the room."""
if not self.isconnected():
Expand Down Expand Up @@ -667,6 +670,11 @@ def _on_room_event(self, event: proto_room.RoomEvent):
rparticipant = self._remote_participants.pop(identity)
rparticipant._info.disconnect_reason = event.participant_disconnected.disconnect_reason
self.emit("participant_disconnected", rparticipant)
elif which == "participant_active":
rp = self._retrieve_remote_participant(event.participant_active.participant_identity)
if rp:
rp._info.state = proto_participant.PARTICIPANT_STATE_ACTIVE
self.emit("participant_active", rp)
elif which == "local_track_published":
sid = event.local_track_published.track_sid
lpublication = self.local_participant.track_publications[sid]
Expand Down
Loading