Module livekit.rtc.track
Classes
class LocalAudioTrack (info: proto_track.OwnedTrack)-
Expand source code
class LocalAudioTrack(Track): def __init__(self, info: proto_track.OwnedTrack): super().__init__(info) @staticmethod def create_audio_track( name: str, source: Union["AudioSource", "PlatformAudioSource"] ) -> "LocalAudioTrack": """Create a local audio track from an audio source. Args: name: The name of the track (e.g., "microphone", "audio-file"). source: Either an AudioSource (synthetic mode for manual frame capture) or a PlatformAudioSource (from PlatformAudio, uses WebRTC ADM). Returns: A LocalAudioTrack that can be published to a room. Example with PlatformAudio (recommended for most use cases): ```python platform_audio = rtc.PlatformAudio() source = platform_audio.create_audio_source() track = rtc.LocalAudioTrack.create_audio_track("microphone", source) ``` Example with AudioSource (synthetic mode for custom processing): ```python # Synthetic mode: You must manually capture frames source = rtc.AudioSource(sample_rate=48000, num_channels=1) track = rtc.LocalAudioTrack.create_audio_track("audio", source) # Then in a loop: await source.capture_frame(frame) ``` """ req = proto_ffi.FfiRequest() req.create_audio_track.name = name req.create_audio_track.source_handle = source._ffi_handle.handle resp = FfiClient.instance.request(req) return LocalAudioTrack(resp.create_audio_track.track) def mute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = True FfiClient.instance.request(req) self._info.muted = True def unmute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = False FfiClient.instance.request(req) self._info.muted = False def __repr__(self) -> str: return f"rtc.LocalAudioTrack(sid={self.sid}, name={self.name})"Ancestors
Static methods
def create_audio_track(name: str, source: "Union['AudioSource', 'PlatformAudioSource']") ‑> 'LocalAudioTrack'-
Expand source code
@staticmethod def create_audio_track( name: str, source: Union["AudioSource", "PlatformAudioSource"] ) -> "LocalAudioTrack": """Create a local audio track from an audio source. Args: name: The name of the track (e.g., "microphone", "audio-file"). source: Either an AudioSource (synthetic mode for manual frame capture) or a PlatformAudioSource (from PlatformAudio, uses WebRTC ADM). Returns: A LocalAudioTrack that can be published to a room. Example with PlatformAudio (recommended for most use cases): ```python platform_audio = rtc.PlatformAudio() source = platform_audio.create_audio_source() track = rtc.LocalAudioTrack.create_audio_track("microphone", source) ``` Example with AudioSource (synthetic mode for custom processing): ```python # Synthetic mode: You must manually capture frames source = rtc.AudioSource(sample_rate=48000, num_channels=1) track = rtc.LocalAudioTrack.create_audio_track("audio", source) # Then in a loop: await source.capture_frame(frame) ``` """ req = proto_ffi.FfiRequest() req.create_audio_track.name = name req.create_audio_track.source_handle = source._ffi_handle.handle resp = FfiClient.instance.request(req) return LocalAudioTrack(resp.create_audio_track.track)Create a local audio track from an audio source.
Args
name- The name of the track (e.g., "microphone", "audio-file").
source- Either an AudioSource (synthetic mode for manual frame capture) or a PlatformAudioSource (from PlatformAudio, uses WebRTC ADM).
Returns
A LocalAudioTrack that can be published to a room. Example with PlatformAudio (recommended for most use cases):
python platform_audio = rtc.PlatformAudio() source = platform_audio.create_audio_source() track = rtc.LocalAudioTrack.create_audio_track("microphone", source)Example with AudioSource (synthetic mode for custom processing):
python # Synthetic mode: You must manually capture frames source = rtc.AudioSource(sample_rate=48000, num_channels=1) track = rtc.LocalAudioTrack.create_audio_track("audio", source) # Then in a loop: await source.capture_frame(frame)
Methods
def mute(self) ‑> None-
Expand source code
def mute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = True FfiClient.instance.request(req) self._info.muted = True def unmute(self) ‑> None-
Expand source code
def unmute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = False FfiClient.instance.request(req) self._info.muted = False
class LocalVideoTrack (info: proto_track.OwnedTrack)-
Expand source code
class LocalVideoTrack(Track): def __init__(self, info: proto_track.OwnedTrack): super().__init__(info) @staticmethod def create_video_track(name: str, source: "VideoSource") -> "LocalVideoTrack": req = proto_ffi.FfiRequest() req.create_video_track.name = name req.create_video_track.source_handle = source._ffi_handle.handle resp = FfiClient.instance.request(req) return LocalVideoTrack(resp.create_video_track.track) def mute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = True FfiClient.instance.request(req) self._info.muted = True def unmute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = False FfiClient.instance.request(req) self._info.muted = False def __repr__(self) -> str: return f"rtc.LocalVideoTrack(sid={self.sid}, name={self.name})"Ancestors
Static methods
def create_video_track(name: str, source: "'VideoSource'") ‑> 'LocalVideoTrack'-
Expand source code
@staticmethod def create_video_track(name: str, source: "VideoSource") -> "LocalVideoTrack": req = proto_ffi.FfiRequest() req.create_video_track.name = name req.create_video_track.source_handle = source._ffi_handle.handle resp = FfiClient.instance.request(req) return LocalVideoTrack(resp.create_video_track.track)
Methods
def mute(self) ‑> None-
Expand source code
def mute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = True FfiClient.instance.request(req) self._info.muted = True def unmute(self) ‑> None-
Expand source code
def unmute(self) -> None: req = proto_ffi.FfiRequest() req.local_track_mute.track_handle = self._ffi_handle.handle req.local_track_mute.mute = False FfiClient.instance.request(req) self._info.muted = False
class RemoteAudioTrack (info: proto_track.OwnedTrack)-
Expand source code
class RemoteAudioTrack(Track): def __init__(self, info: proto_track.OwnedTrack): super().__init__(info) def __repr__(self) -> str: return f"rtc.RemoteAudioTrack(sid={self.sid}, name={self.name})"Ancestors
class RemoteVideoTrack (info: proto_track.OwnedTrack)-
Expand source code
class RemoteVideoTrack(Track): def __init__(self, info: proto_track.OwnedTrack): super().__init__(info) def __repr__(self) -> str: return f"rtc.RemoteVideoTrack(sid={self.sid}, name={self.name})"Ancestors
class Track (owned_info: proto_track.OwnedTrack)-
Expand source code
class Track: def __init__(self, owned_info: proto_track.OwnedTrack): self._info = owned_info.info self._ffi_handle = FfiHandle(owned_info.handle.id) self._room_ref: Optional[weakref.ref[Room]] = None self._audio_streams: weakref.WeakSet[AudioStream] = weakref.WeakSet() def _resolve_room(self) -> Optional[Room]: return self._room_ref() if self._room_ref is not None else None def _set_room(self, room: Optional[Room]) -> None: old_room = self._resolve_room() if old_room is None and room is None: # Already roomless — nothing to detach and nothing to re-clear. # Without this guard a second _set_room(None) (e.g. the unpublish / # local_track_unpublished race calling it from both paths) would # re-fire _on_*_cleared on every registered processor. return if old_room is not room: if old_room is not None: old_room.off("token_refreshed", self._on_room_token_refreshed) if room is not None: room.on("token_refreshed", self._on_room_token_refreshed) self._room_ref = weakref.ref(room) if room is not None else None for stream in self._audio_streams: self._push_processor_metadata_to_stream(stream, room) def _on_room_token_refreshed(self) -> None: room = self._resolve_room() if room is None or room._token is None or room._server_url is None: return for stream in self._audio_streams: if not stream._processor: continue stream._processor._on_credentials_updated(token=room._token, url=room._server_url) def _push_processor_metadata_to_stream(self, stream: AudioStream, room: Optional[Room]) -> None: if not stream._processor: return if room is None: # track left a room - clear processor's room context stream._processor._on_stream_info_cleared() stream._processor._on_credentials_cleared() return identity = "" pub_sid = "" track_sid = self.sid if track_sid: for participant in room.remote_participants.values(): publication = participant.track_publications.get(track_sid) if publication is not None: identity, pub_sid = participant.identity, publication.sid break else: local = room._local_participant if local is not None: for local_publication in local.track_publications.values(): if local_publication.sid == track_sid: identity, pub_sid = local.identity, local_publication.sid break stream._processor._on_stream_info_updated( room_name=room.name, participant_identity=identity, publication_sid=pub_sid, ) if room._token is not None and room._server_url is not None: stream._processor._on_credentials_updated(token=room._token, url=room._server_url) def _register_audio_stream(self, stream: AudioStream) -> None: self._audio_streams.add(stream) room = self._resolve_room() if room is not None: self._push_processor_metadata_to_stream(stream, room) def _unregister_audio_stream(self, stream: AudioStream) -> None: self._audio_streams.discard(stream) @property def sid(self) -> str: return self._info.sid @property def name(self) -> str: return self._info.name @property def kind(self) -> proto_track.TrackKind.ValueType: return self._info.kind @property def stream_state(self) -> proto_track.StreamState.ValueType: return self._info.stream_state @property def muted(self) -> bool: return self._info.muted async def get_stats(self) -> List[proto_stats.RtcStats]: req = proto_ffi.FfiRequest() req.get_stats.track_handle = self._ffi_handle.handle queue = FfiClient.instance.queue.subscribe() try: resp = FfiClient.instance.request(req) cb: proto_ffi.FfiEvent = await queue.wait_for( lambda e: e.get_stats.async_id == resp.get_stats.async_id ) finally: FfiClient.instance.queue.unsubscribe(queue) if cb.get_stats.error: raise Exception(cb.get_stats.error) return list(cb.get_stats.stats)Subclasses
Instance variables
prop kind : proto_track.TrackKind.ValueType-
Expand source code
@property def kind(self) -> proto_track.TrackKind.ValueType: return self._info.kind prop muted : bool-
Expand source code
@property def muted(self) -> bool: return self._info.muted prop name : str-
Expand source code
@property def name(self) -> str: return self._info.name prop sid : str-
Expand source code
@property def sid(self) -> str: return self._info.sid prop stream_state : proto_track.StreamState.ValueType-
Expand source code
@property def stream_state(self) -> proto_track.StreamState.ValueType: return self._info.stream_state
Methods
async def get_stats(self) ‑> List[stats_pb2.RtcStats]-
Expand source code
async def get_stats(self) -> List[proto_stats.RtcStats]: req = proto_ffi.FfiRequest() req.get_stats.track_handle = self._ffi_handle.handle queue = FfiClient.instance.queue.subscribe() try: resp = FfiClient.instance.request(req) cb: proto_ffi.FfiEvent = await queue.wait_for( lambda e: e.get_stats.async_id == resp.get_stats.async_id ) finally: FfiClient.instance.queue.unsubscribe(queue) if cb.get_stats.error: raise Exception(cb.get_stats.error) return list(cb.get_stats.stats)