Skip to content

Commit 60ce71f

Browse files
committed
Add frame processor support for audio streams
1 parent 37ec826 commit 60ce71f

File tree

2 files changed

+45
-4
lines changed

2 files changed

+45
-4
lines changed

livekit-rtc/livekit/rtc/audio_stream.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .audio_frame import AudioFrame
2828
from .participant import Participant
2929
from .track import Track
30+
from .frame_processor import SyncFrameProcessor
3031

3132

3233
@dataclass
@@ -62,7 +63,9 @@ def __init__(
6263
sample_rate: int = 48000,
6364
num_channels: int = 1,
6465
frame_size_ms: int | None = None,
65-
noise_cancellation: Optional[NoiseCancellationOptions] = None,
66+
noise_cancellation: Optional[
67+
NoiseCancellationOptions | SyncFrameProcessor[AudioFrame]
68+
] = None,
6669
**kwargs,
6770
) -> None:
6871
"""Initialize an `AudioStream` instance.
@@ -76,8 +79,8 @@ def __init__(
7679
sample_rate (int, optional): The sample rate for the audio stream in Hz.
7780
Defaults to 48000.
7881
num_channels (int, optional): The number of audio channels. Defaults to 1.
79-
noise_cancellation (Optional[NoiseCancellationOptions], optional):
80-
If noise cancellation is used, pass a `NoiseCancellationOptions` instance
82+
noise_cancellation (Optional[NoiseCancellationOptions | SyncFrameProcessor[AudioFrame]], optional):
83+
If noise cancellation is used, pass a `NoiseCancellationOptions` or `SyncFrameProcessor[AudioFrame]` instance
8184
created by the noise cancellation module.
8285
8386
Example:
@@ -105,9 +108,12 @@ def __init__(
105108

106109
self._audio_filter_module = None
107110
self._audio_filter_options = None
108-
if noise_cancellation is not None:
111+
if isinstance(noise_cancellation, NoiseCancellationOptions):
109112
self._audio_filter_module = noise_cancellation.module_id
110113
self._audio_filter_options = noise_cancellation.options
114+
elif isinstance(noise_cancellation, SyncFrameProcessor):
115+
self._processor = noise_cancellation
116+
111117
self._task = self._loop.create_task(self._run())
112118
self._task.add_done_callback(task_done_logger)
113119

@@ -268,6 +274,8 @@ async def _run(self):
268274
if audio_event.HasField("frame_received"):
269275
owned_buffer_info = audio_event.frame_received.frame
270276
frame = AudioFrame._from_owned_info(owned_buffer_info)
277+
if self._processor is not None:
278+
frame = self._processor._process(frame)
271279
event = AudioFrameEvent(frame)
272280
self._queue.put(event)
273281
elif audio_event.HasField("eos"):
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from abc import ABC, abstractmethod
2+
from typing import TYPE_CHECKING, Generic, TypeVar, Union
3+
4+
if TYPE_CHECKING:
5+
from .audio_frame import AudioFrame
6+
from .video_frame import VideoFrame
7+
8+
9+
T = TypeVar("T", bound=Union[AudioFrame, VideoFrame])
10+
11+
12+
class SyncFrameProcessor(Generic[T], ABC):
13+
@property
14+
@abstractmethod
15+
def is_enabled(self) -> bool: ...
16+
17+
@abstractmethod
18+
def set_enabled(self, enable: bool): ...
19+
20+
@abstractmethod
21+
def _set_context(
22+
self,
23+
*,
24+
room_name: str,
25+
participant_identity: str,
26+
publication_sid: str,
27+
): ...
28+
29+
@abstractmethod
30+
def _process(self, frame: T) -> T: ...
31+
32+
@abstractmethod
33+
def _close(self): ...

0 commit comments

Comments
 (0)