@@ -65,6 +65,7 @@ def __init__(
6565 num_channels : int = 1 ,
6666 frame_size_ms : int | None = None ,
6767 noise_cancellation : Optional [NoiseCancellationOptions | FrameProcessor [AudioFrame ]] = None ,
68+ auto_close_noise_cancellation : bool = True ,
6869 ** kwargs : Any ,
6970 ) -> None :
7071 """Initialize an `AudioStream` instance.
@@ -81,6 +82,9 @@ def __init__(
8182 noise_cancellation (Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame]], optional):
8283 If noise cancellation is used, pass a `NoiseCancellationOptions` or `FrameProcessor[AudioFrame]` instance
8384 created by the noise cancellation module.
85+ auto_close_noise_cancellation (bool):
86+ When the audio stream closes, should the FrameProcessor's close method be run? If
87+ False, then the frame processor can be reused with another AudioStream.
8488
8589 Example:
8690 ```python
@@ -113,11 +117,13 @@ def __init__(
113117 self ._audio_filter_module : str | None = None
114118 self ._audio_filter_options : dict [str , Any ] | None = None
115119 self ._processor : FrameProcessor [AudioFrame ] | None = None
120+ self ._processor_auto_close = True
116121 if isinstance (noise_cancellation , NoiseCancellationOptions ):
117122 self ._audio_filter_module = noise_cancellation .module_id
118123 self ._audio_filter_options = noise_cancellation .options
119124 elif isinstance (noise_cancellation , FrameProcessor ):
120125 self ._processor = noise_cancellation
126+ self ._processor_auto_close = auto_close_noise_cancellation
121127
122128 self ._task = self ._loop .create_task (self ._run ())
123129 self ._task .add_done_callback (task_done_logger )
@@ -132,6 +138,9 @@ def __init__(
132138 self ._ffi_handle = FfiHandle (stream .handle .id )
133139 self ._info = stream .info
134140
141+ if self ._track is not None :
142+ self ._track ._register_audio_stream (self )
143+
135144 @classmethod
136145 def from_participant (
137146 cls ,
@@ -144,6 +153,7 @@ def from_participant(
144153 num_channels : int = 1 ,
145154 frame_size_ms : int | None = None ,
146155 noise_cancellation : Optional [NoiseCancellationOptions | FrameProcessor [AudioFrame ]] = None ,
156+ auto_close_noise_cancellation : bool = True ,
147157 ) -> AudioStream :
148158 """Create an `AudioStream` from a participant's audio track.
149159
@@ -179,8 +189,9 @@ def from_participant(
179189 track = None , # type: ignore
180190 sample_rate = sample_rate ,
181191 num_channels = num_channels ,
182- noise_cancellation = noise_cancellation ,
183192 frame_size_ms = frame_size_ms ,
193+ noise_cancellation = noise_cancellation ,
194+ auto_close_noise_cancellation = auto_close_noise_cancellation ,
184195 )
185196
186197 @classmethod
@@ -194,6 +205,7 @@ def from_track(
194205 num_channels : int = 1 ,
195206 frame_size_ms : int | None = None ,
196207 noise_cancellation : Optional [NoiseCancellationOptions | FrameProcessor [AudioFrame ]] = None ,
208+ auto_close_noise_cancellation : bool = False ,
197209 ) -> AudioStream :
198210 """Create an `AudioStream` from an existing audio track.
199211
@@ -203,9 +215,12 @@ def from_track(
203215 capacity (int, optional): The capacity of the internal frame queue. Defaults to 0 (unbounded).
204216 sample_rate (int, optional): The sample rate for the audio stream in Hz. Defaults to 48000.
205217 num_channels (int, optional): The number of audio channels. Defaults to 1.
206- noise_cancellation (Optional[NoiseCancellationOptions], optional):
207- If noise cancellation is used, pass a `NoiseCancellationOptions` instance
218+ noise_cancellation (Optional[NoiseCancellationOptions | FrameProcessor[AudioFrame] ], optional):
219+ If noise cancellation is used, pass a `NoiseCancellationOptions` or `FrameProcessor[AudioFrame]` instance
208220 created by the noise cancellation module.
221+ auto_close_noise_cancellation (bool):
222+ When the audio stream closes, leaves the FrameProcessor in an unclosed state so it
223+ can be used with another AudioStream.
209224
210225 Returns:
211226 AudioStream: An instance of `AudioStream` that can be used to receive audio frames.
@@ -225,8 +240,9 @@ def from_track(
225240 capacity = capacity ,
226241 sample_rate = sample_rate ,
227242 num_channels = num_channels ,
228- noise_cancellation = noise_cancellation ,
229243 frame_size_ms = frame_size_ms ,
244+ noise_cancellation = noise_cancellation ,
245+ auto_close_noise_cancellation = auto_close_noise_cancellation ,
230246 )
231247
232248 def __del__ (self ) -> None :
@@ -303,8 +319,12 @@ async def aclose(self) -> None:
303319 This method cleans up resources associated with the audio stream and waits for
304320 any pending operations to complete.
305321 """
322+ if self ._track is not None :
323+ self ._track ._unregister_audio_stream (self )
306324 self ._ffi_handle .dispose ()
307325 await self ._task
326+ if self ._processor is not None and self ._processor_auto_close :
327+ self ._processor ._close ()
308328
309329 def _is_event (self , e : proto_ffi .FfiEvent ) -> bool :
310330 return e .audio_stream_event .stream_handle == self ._ffi_handle .handle
0 commit comments