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
2 changes: 1 addition & 1 deletion livekit-rtc/livekit/rtc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
DisconnectReason,
)
from ._proto.room_pb2 import (
ConnectionQuality,
ConnectionState,
ContinualGatheringPolicy,
DataPacketKind,
Expand Down Expand Up @@ -58,6 +57,7 @@
KeyProviderOptions,
)
from .participant import (
ConnectionQuality,
LocalParticipant,
Participant,
RemoteParticipant,
Expand Down
33 changes: 33 additions & 0 deletions livekit-rtc/livekit/rtc/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import ctypes
import asyncio
import datetime
import enum
import os
import mimetypes
import aiofiles
Expand All @@ -29,6 +30,9 @@
from ._proto.room_pb2 import (
TrackPublishOptions,
)
from ._proto.room_pb2 import (
ConnectionQuality as ProtoConnectionQuality,
)
from ._proto.room_pb2 import (
TranscriptionSegment as ProtoTranscriptionSegment,
)
Expand Down Expand Up @@ -89,10 +93,29 @@ def __init__(self, message: str) -> None:
self.message = message


class ConnectionQuality(enum.IntEnum):
"""Connection quality reported for a participant."""

QUALITY_UNKNOWN = -1
"""No connection-quality update has been reported yet (no proto equivalent)."""
QUALITY_POOR = ProtoConnectionQuality.QUALITY_POOR
QUALITY_GOOD = ProtoConnectionQuality.QUALITY_GOOD
QUALITY_EXCELLENT = ProtoConnectionQuality.QUALITY_EXCELLENT
QUALITY_LOST = ProtoConnectionQuality.QUALITY_LOST


def _connection_quality_from_proto(value: int) -> ConnectionQuality:
try:
return ConnectionQuality(value)
except ValueError:
return ConnectionQuality.QUALITY_UNKNOWN


class Participant(ABC):
def __init__(self, owned_info: proto_participant.OwnedParticipant) -> None:
self._info = owned_info.info
self._ffi_handle = FfiHandle(owned_info.handle.id)
self._connection_quality = ConnectionQuality.QUALITY_UNKNOWN

@property
@abstractmethod
Expand Down Expand Up @@ -152,6 +175,16 @@ def permissions(self) -> proto_participant.ParticipantPermission:
"""The participant's permissions within the room."""
return self._info.permission

@property
def connection_quality(self) -> ConnectionQuality:
"""The participant's most recently reported connection quality.

Returns ``ConnectionQuality.QUALITY_UNKNOWN`` until the first
connection-quality update is received. Updated automatically whenever a
``connection_quality_changed`` event fires for this participant.
"""
return self._connection_quality

@property
def disconnect_reason(
self,
Expand Down
13 changes: 10 additions & 3 deletions livekit-rtc/livekit/rtc/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@
from ._proto.rpc_pb2 import RpcMethodInvocationEvent
from ._utils import BroadcastQueue
from .e2ee import E2EEManager, E2EEOptions
from .participant import LocalParticipant, Participant, RemoteParticipant
from .participant import (
LocalParticipant,
Participant,
RemoteParticipant,
_connection_quality_from_proto,
)
from .track import RemoteAudioTrack, RemoteVideoTrack
from .track_publication import RemoteTrackPublication, TrackPublication
from .transcription import TranscriptionSegment
Expand Down Expand Up @@ -897,12 +902,14 @@ def _on_room_event(self, event: proto_room.RoomEvent) -> None:
)
elif which == "connection_quality_changed":
identity = event.connection_quality_changed.participant_identity
# TODO: pass participant identity
participant = self._retrieve_participant(identity)
quality = _connection_quality_from_proto(event.connection_quality_changed.quality)
if participant:
participant._connection_quality = quality
self.emit(
"connection_quality_changed",
participant,
event.connection_quality_changed.quality,
quality,
)
elif which == "transcription_received":
transcription = event.transcription_received
Expand Down
29 changes: 29 additions & 0 deletions tests/rtc/test_connection_quality.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Unit tests for the local ConnectionQuality enum and the participant property."""

from livekit import rtc
from livekit.rtc._proto import participant_pb2 as proto_participant
from livekit.rtc._proto import room_pb2 as proto_room
from livekit.rtc.participant import _connection_quality_from_proto


def test_enum_values_align_with_proto() -> None:
CQ = rtc.ConnectionQuality
assert CQ.QUALITY_UNKNOWN == -1
assert CQ.QUALITY_POOR == proto_room.ConnectionQuality.QUALITY_POOR
assert CQ.QUALITY_GOOD == proto_room.ConnectionQuality.QUALITY_GOOD
assert CQ.QUALITY_EXCELLENT == proto_room.ConnectionQuality.QUALITY_EXCELLENT
assert CQ.QUALITY_LOST == proto_room.ConnectionQuality.QUALITY_LOST
# backward compat: still int-comparable like the old proto enum export
assert CQ.QUALITY_GOOD == 1


def test_from_proto_mapping() -> None:
assert _connection_quality_from_proto(1) is rtc.ConnectionQuality.QUALITY_GOOD
assert _connection_quality_from_proto(99) is rtc.ConnectionQuality.QUALITY_UNKNOWN


def test_participant_default_quality_is_unknown() -> None:
owned = proto_participant.OwnedParticipant()
owned.info.identity = "test"
participant = rtc.RemoteParticipant(owned)
assert participant.connection_quality is rtc.ConnectionQuality.QUALITY_UNKNOWN
Loading