Module livekit.agents.utils
Sub-modules
livekit.agents.utils.aio
livekit.agents.utils.audio
livekit.agents.utils.codecs
livekit.agents.utils.exp_filter
livekit.agents.utils.http_context
livekit.agents.utils.hw
livekit.agents.utils.images
livekit.agents.utils.log
livekit.agents.utils.misc
livekit.agents.utils.moving_average
Functions
def _compute_changes(old_list: list[~T], new_list: list[~T], key_fnc: Callable[[~T], str]) ‑> livekit.agents.utils._message_change.MessageChange[~T]
-
Compute minimum changes needed to transform old list into new list
def combine_frames(buffer: AudioFrame | list[AudioFrame]) ‑> AudioFrame
-
Combines one or more
rtc.AudioFrame
objects into a singlertc.AudioFrame
.This function concatenates the audio data from multiple frames, ensuring that all frames have the same sample rate and number of channels. It efficiently merges the data by preallocating the necessary memory and copying the frame data without unnecessary reallocations.
Args
buffer
- A single
rtc.AudioFrame
or a list ofrtc.AudioFrame
objects to be combined.
Returns
rtc.AudioFrame
- A new
rtc.AudioFrame
containing the combined audio data.
Raises
ValueError
- If the buffer is empty.
ValueError
- If frames have differing sample rates.
ValueError
- If frames have differing numbers of channels.
Example
>>> frame1 = rtc.AudioFrame( ... data=b"", sample_rate=48000, num_channels=2, samples_per_channel=1 ... ) >>> frame2 = rtc.AudioFrame( ... data=b"", sample_rate=48000, num_channels=2, samples_per_channel=1 ... ) >>> combined_frame = combine_audio_frames([frame1, frame2]) >>> combined_frame.data b'' >>> combined_frame.sample_rate 48000 >>> combined_frame.num_channels 2 >>> combined_frame.samples_per_channel 2
def log_exceptions(msg: str = '', logger: logging.Logger = <RootLogger root (WARNING)>) ‑> Callable[[Any], Any]
def merge_frames(buffer: AudioFrame | list[AudioFrame]) ‑> AudioFrame
-
Combines one or more
rtc.AudioFrame
objects into a singlertc.AudioFrame
.This function concatenates the audio data from multiple frames, ensuring that all frames have the same sample rate and number of channels. It efficiently merges the data by preallocating the necessary memory and copying the frame data without unnecessary reallocations.
Args
buffer
- A single
rtc.AudioFrame
or a list ofrtc.AudioFrame
objects to be combined.
Returns
rtc.AudioFrame
- A new
rtc.AudioFrame
containing the combined audio data.
Raises
ValueError
- If the buffer is empty.
ValueError
- If frames have differing sample rates.
ValueError
- If frames have differing numbers of channels.
Example
>>> frame1 = rtc.AudioFrame( ... data=b"", sample_rate=48000, num_channels=2, samples_per_channel=1 ... ) >>> frame2 = rtc.AudioFrame( ... data=b"", sample_rate=48000, num_channels=2, samples_per_channel=1 ... ) >>> combined_frame = combine_audio_frames([frame1, frame2]) >>> combined_frame.data b'' >>> combined_frame.sample_rate 48000 >>> combined_frame.num_channels 2 >>> combined_frame.samples_per_channel 2
def shortuuid(prefix: str = '') ‑> str
def time_ms() ‑> int
Classes
class EventEmitter
-
Abstract base class for generic types.
On Python 3.12 and newer, generic classes implicitly inherit from Generic when they declare a parameter list after the class's name::
class Mapping[KT, VT]: def __getitem__(self, key: KT) -> VT: ... # Etc.
On older versions of Python, however, generic classes have to explicitly inherit from Generic.
After a class has been declared to be generic, it can then be used as follows::
def lookup_name[KT, VT](mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default
Initialize a new instance of EventEmitter.
Expand source code
class EventEmitter(Generic[T_contra]): def __init__(self) -> None: """ Initialize a new instance of EventEmitter. """ self._events: Dict[T_contra, Set[Callable]] = dict() def emit(self, event: T_contra, *args) -> None: """ Trigger all callbacks associated with the given event. Args: event (T): The event to emit. *args: Positional arguments to pass to the callbacks. Example: Basic usage of emit: ```python emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.emit('greet', 'Alice') # Output: Hello, Alice! ``` """ if event in self._events: callables = self._events[event].copy() for callback in callables: try: sig = inspect.signature(callback) params = sig.parameters.values() has_varargs = any(p.kind == p.VAR_POSITIONAL for p in params) if has_varargs: callback(*args) else: positional_params = [ p for p in params if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD) ] num_params = len(positional_params) num_args = min(len(args), num_params) callback_args = args[:num_args] callback(*callback_args) except TypeError: raise except Exception: logger.exception(f"failed to emit event {event}") def once(self, event: T_contra, callback: Optional[Callable] = None) -> Callable: """ Register a callback to be called only once when the event is emitted. If a callback is provided, it registers the callback directly. If no callback is provided, it returns a decorator for use with function definitions. Args: event (T): The event to listen for. callback (Callable, optional): The callback to register. Defaults to None. Returns: Callable: The registered callback or a decorator if callback is None. Example: Using once with a direct callback: ```python emitter = EventEmitter[str]() def greet_once(name): print(f"Hello once, {name}!") emitter.once('greet', greet_once) emitter.emit('greet', 'Bob') # Output: Hello once, Bob! emitter.emit('greet', 'Bob') # No output, callback was removed after first call ``` Using once as a decorator: ```python emitter = EventEmitter[str]() @emitter.once('greet') def greet_once(name): print(f"Hello once, {name}!") emitter.emit('greet', 'Bob') # Output: Hello once, Bob! emitter.emit('greet', 'Bob') # No output ``` """ if callback is not None: def once_callback(*args, **kwargs): self.off(event, once_callback) callback(*args, **kwargs) return self.on(event, once_callback) else: def decorator(callback: Callable) -> Callable: self.once(event, callback) return callback return decorator def on(self, event: T_contra, callback: Optional[Callable] = None) -> Callable: """ Register a callback to be called whenever the event is emitted. If a callback is provided, it registers the callback directly. If no callback is provided, it returns a decorator for use with function definitions. Args: event (T): The event to listen for. callback (Callable, optional): The callback to register. Defaults to None. Returns: Callable: The registered callback or a decorator if callback is None. Example: Using on with a direct callback: ```python emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.emit('greet', 'Charlie') # Output: Hello, Charlie! ``` Using on as a decorator: ```python emitter = EventEmitter[str]() @emitter.on('greet') def greet(name): print(f"Hello, {name}!") emitter.emit('greet', 'Charlie') # Output: Hello, Charlie! ``` """ if callback is not None: if event not in self._events: self._events[event] = set() self._events[event].add(callback) return callback else: def decorator(callback: Callable) -> Callable: self.on(event, callback) return callback return decorator def off(self, event: T_contra, callback: Callable) -> None: """ Unregister a callback from an event. Args: event (T): The event to stop listening to. callback (Callable): The callback to remove. Example: Removing a callback: ```python emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.off('greet', greet) emitter.emit('greet', 'Dave') # No output, callback was removed ``` """ if event in self._events: self._events[event].remove(callback)
Ancestors
- typing.Generic
Subclasses
- ProcPool
- LLM
- AgentPlayout
- MultimodalAgent
- AgentPlayout
- HumanInput
- VoicePipelineAgent
- STT
- TTS
- VAD
- livekit.agents.worker.Worker
- RealtimeSession
- ChatManager
- Room
Methods
def emit(self, event: -T_contra, *args) ‑> None
-
Trigger all callbacks associated with the given event.
Args
event
:T
- The event to emit.
*args
- Positional arguments to pass to the callbacks.
Example
Basic usage of emit:
emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.emit('greet', 'Alice') # Output: Hello, Alice!
def off(self, event: -T_contra, callback: Callable) ‑> None
-
Unregister a callback from an event.
Args
event
:T
- The event to stop listening to.
callback
:Callable
- The callback to remove.
Example
Removing a callback:
emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.off('greet', greet) emitter.emit('greet', 'Dave') # No output, callback was removed
def on(self, event: -T_contra, callback: Optional[Callable] = None) ‑> Callable
-
Register a callback to be called whenever the event is emitted.
If a callback is provided, it registers the callback directly. If no callback is provided, it returns a decorator for use with function definitions.
Args
event
:T
- The event to listen for.
callback
:Callable
, optional- The callback to register. Defaults to None.
Returns
Callable
- The registered callback or a decorator if callback is None.
Example
Using on with a direct callback:
emitter = EventEmitter[str]() def greet(name): print(f"Hello, {name}!") emitter.on('greet', greet) emitter.emit('greet', 'Charlie') # Output: Hello, Charlie!
Using on as a decorator:
emitter = EventEmitter[str]() @emitter.on('greet') def greet(name): print(f"Hello, {name}!") emitter.emit('greet', 'Charlie') # Output: Hello, Charlie!
def once(self, event: -T_contra, callback: Optional[Callable] = None) ‑> Callable
-
Register a callback to be called only once when the event is emitted.
If a callback is provided, it registers the callback directly. If no callback is provided, it returns a decorator for use with function definitions.
Args
event
:T
- The event to listen for.
callback
:Callable
, optional- The callback to register. Defaults to None.
Returns
Callable
- The registered callback or a decorator if callback is None.
Example
Using once with a direct callback:
emitter = EventEmitter[str]() def greet_once(name): print(f"Hello once, {name}!") emitter.once('greet', greet_once) emitter.emit('greet', 'Bob') # Output: Hello once, Bob! emitter.emit('greet', 'Bob') # No output, callback was removed after first call
Using once as a decorator:
emitter = EventEmitter[str]() @emitter.once('greet') def greet_once(name): print(f"Hello once, {name}!") emitter.emit('greet', 'Bob') # Output: Hello once, Bob! emitter.emit('greet', 'Bob') # No output
class ExpFilter (alpha: float, max_val: float = -1.0)
-
Expand source code
class ExpFilter: def __init__(self, alpha: float, max_val: float = -1.0) -> None: self._alpha = alpha self._filtered = -1.0 self._max_val = max_val def reset(self, alpha: float = -1.0) -> None: if alpha != -1.0: self._alpha = alpha self._filtered = -1.0 def apply(self, exp: float, sample: float) -> float: if self._filtered == -1.0: self._filtered = sample else: a = self._alpha**exp self._filtered = a * self._filtered + (1 - a) * sample if self._max_val != -1.0 and self._filtered > self._max_val: self._filtered = self._max_val return self._filtered def filtered(self) -> float: return self._filtered def update_base(self, alpha: float) -> None: self._alpha = alpha
Methods
def apply(self, exp: float, sample: float) ‑> float
def filtered(self) ‑> float
def reset(self, alpha: float = -1.0) ‑> None
def update_base(self, alpha: float) ‑> None
class MovingAverage (window_size: int)
-
Expand source code
class MovingAverage: def __init__(self, window_size: int) -> None: self._hist: list[float] = [0] * window_size self._sum: float = 0 self._count: int = 0 def add_sample(self, sample: float) -> None: self._count += 1 index = self._count % len(self._hist) if self._count > len(self._hist): self._sum -= self._hist[index] self._sum += sample self._hist[index] = sample def get_avg(self) -> float: if self._count == 0: return 0 return self._sum / self.size() def reset(self): self._count = 0 self._sum = 0 def size(self) -> int: return min(self._count, len(self._hist))
Methods
def add_sample(self, sample: float) ‑> None
def get_avg(self) ‑> float
def reset(self)
def size(self) ‑> int