1use crate::block::Block;
9use crate::block_processor_metrics::BlockProcessorMetrics;
10use crate::common::{BLOCK_SIZE_MS, num_bands_for_rate, valid_full_band_rate};
11use crate::config::EchoCanceller3Config;
12use crate::delay_estimate::DelayEstimate;
13use crate::echo_path_variability::{DelayAdjustment, EchoPathVariability};
14use crate::echo_remover::EchoRemover;
15use crate::render_delay_buffer::{BufferingEvent, RenderDelayBuffer};
16use crate::render_delay_controller::RenderDelayController;
17use sonora_simd::SimdBackend;
18
19#[derive(Debug)]
21pub struct BlockProcessor {
22 config: EchoCanceller3Config,
23 capture_properly_started: bool,
24 render_properly_started: bool,
25 sample_rate_hz: usize,
26 render_buffer: RenderDelayBuffer,
27 delay_controller: Option<RenderDelayController>,
28 echo_remover: EchoRemover,
29 metrics: BlockProcessorMetrics,
30 render_event: BufferingEvent,
31 capture_call_counter: usize,
32 estimated_delay: Option<DelayEstimate>,
33}
34
35#[derive(Debug, Clone, Copy, Default)]
37pub struct BlockProcessorMetricsOutput {
38 pub echo_return_loss: f64,
40 pub echo_return_loss_enhancement: f64,
42 pub delay_ms: i32,
44}
45
46impl BlockProcessor {
47 pub fn new(
48 config: &EchoCanceller3Config,
49 sample_rate_hz: usize,
50 num_render_channels: usize,
51 num_capture_channels: usize,
52 ) -> Self {
53 let backend = sonora_simd::detect_backend();
54 Self::with_backend(
55 backend,
56 config,
57 sample_rate_hz,
58 num_render_channels,
59 num_capture_channels,
60 )
61 }
62
63 pub fn with_backend(
65 backend: SimdBackend,
66 config: &EchoCanceller3Config,
67 sample_rate_hz: usize,
68 num_render_channels: usize,
69 num_capture_channels: usize,
70 ) -> Self {
71 debug_assert!(valid_full_band_rate(sample_rate_hz));
72
73 let render_buffer = RenderDelayBuffer::new(config, sample_rate_hz, num_render_channels);
74
75 let delay_controller = if !config.delay.use_external_delay_estimator {
76 Some(RenderDelayController::new(
77 backend,
78 config,
79 num_capture_channels,
80 ))
81 } else {
82 None
83 };
84
85 let echo_remover = EchoRemover::new(
86 backend,
87 config,
88 sample_rate_hz,
89 num_render_channels,
90 num_capture_channels,
91 );
92
93 Self {
94 config: config.clone(),
95 capture_properly_started: false,
96 render_properly_started: false,
97 sample_rate_hz,
98 render_buffer,
99 delay_controller,
100 echo_remover,
101 metrics: BlockProcessorMetrics::new(),
102 render_event: BufferingEvent::None,
103 capture_call_counter: 0,
104 estimated_delay: None,
105 }
106 }
107
108 pub fn get_metrics(&self) -> BlockProcessorMetricsOutput {
110 let echo_metrics = self.echo_remover.get_metrics();
111 BlockProcessorMetricsOutput {
112 echo_return_loss: echo_metrics.echo_return_loss,
113 echo_return_loss_enhancement: echo_metrics.echo_return_loss_enhancement,
114 delay_ms: self.render_buffer.delay() as i32 * BLOCK_SIZE_MS as i32,
115 }
116 }
117
118 pub fn set_audio_buffer_delay(&mut self, delay_ms: i32) {
120 self.render_buffer.set_audio_buffer_delay(delay_ms);
121 }
122
123 pub fn process_capture(
125 &mut self,
126 echo_path_gain_change: bool,
127 capture_signal_saturation: bool,
128 linear_output: Option<&mut Block>,
129 capture_block: &mut Block,
130 ) {
131 debug_assert_eq!(
132 num_bands_for_rate(self.sample_rate_hz),
133 capture_block.num_bands()
134 );
135
136 self.capture_call_counter += 1;
137
138 if self.render_properly_started {
139 if !self.capture_properly_started {
140 self.capture_properly_started = true;
141 self.render_buffer.reset();
142 if let Some(ref mut dc) = self.delay_controller {
143 dc.reset(true);
144 }
145 }
146 } else {
147 self.render_buffer.handle_skipped_capture_processing();
149 return;
150 }
151
152 let mut echo_path_variability =
153 EchoPathVariability::new(echo_path_gain_change, DelayAdjustment::None, false);
154
155 if self.render_event == BufferingEvent::RenderOverrun && self.render_properly_started {
156 echo_path_variability.delay_change = DelayAdjustment::BufferFlush;
157 if let Some(ref mut dc) = self.delay_controller {
158 dc.reset(true);
159 }
160 }
161 self.render_event = BufferingEvent::None;
162
163 let buffer_event = self.render_buffer.prepare_capture_processing();
165 if buffer_event == BufferingEvent::RenderUnderrun
167 && let Some(ref mut dc) = self.delay_controller
168 {
169 dc.reset(false);
170 }
171
172 let has_delay_estimator = !self.config.delay.use_external_delay_estimator;
173 if has_delay_estimator {
174 let dc = self
175 .delay_controller
176 .as_mut()
177 .expect("delay controller must exist when not using external delay estimator");
178 self.estimated_delay = dc.get_delay(
180 self.render_buffer.get_downsampled_render_buffer(),
181 self.render_buffer.delay(),
182 capture_block,
183 );
184
185 if let Some(ref estimated_delay) = self.estimated_delay {
186 let delay_change = self.render_buffer.align_from_delay(estimated_delay.delay);
187 if delay_change {
188 echo_path_variability.delay_change = DelayAdjustment::NewDetectedDelay;
189 }
190 }
191
192 echo_path_variability.clock_drift = dc.has_clockdrift();
193 } else {
194 self.render_buffer.align_from_external_delay();
195 }
196
197 if has_delay_estimator || self.render_buffer.has_received_buffer_delay() {
199 let render_buffer = self.render_buffer.get_render_buffer();
200 self.echo_remover.process_capture(
201 echo_path_variability,
202 capture_signal_saturation,
203 &self.estimated_delay,
204 &render_buffer,
205 linear_output,
206 capture_block,
207 );
208 }
209
210 self.metrics.update_capture(false);
212 }
213
214 pub fn buffer_render(&mut self, block: &Block) {
216 debug_assert_eq!(num_bands_for_rate(self.sample_rate_hz), block.num_bands());
217
218 self.render_event = self.render_buffer.insert(block);
219
220 self.metrics
221 .update_render(self.render_event != BufferingEvent::None);
222
223 self.render_properly_started = true;
224 }
225
226 pub fn update_echo_leakage_status(&mut self, leakage_detected: bool) {
228 self.echo_remover
229 .update_echo_leakage_status(leakage_detected);
230 }
231
232 pub fn set_capture_output_usage(&mut self, capture_output_used: bool) {
234 self.echo_remover
235 .set_capture_output_usage(capture_output_used);
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242 use crate::common::NUM_BLOCKS_PER_SECOND;
243
244 #[test]
245 fn basic_setup_and_api_calls() {
246 for &rate in &[16000, 32000, 48000] {
247 let config = EchoCanceller3Config::default();
248 let mut block_processor = BlockProcessor::new(&config, rate, 1, 1);
249 let block = Block::new_with_value(num_bands_for_rate(rate), 1, 1000.0);
250 let mut capture = block.clone();
251 for _ in 0..1 {
252 block_processor.buffer_render(&block);
253 block_processor.process_capture(false, false, None, &mut capture);
254 block_processor.update_echo_leakage_status(false);
255 }
256 }
257 }
258
259 #[test]
260 fn test_longer_call() {
261 let config = EchoCanceller3Config::default();
262 let mut block_processor = BlockProcessor::new(&config, 16000, 1, 1);
263 let block = Block::new_with_value(1, 1, 1000.0);
264 let mut capture = block.clone();
265 for _ in 0..20 * NUM_BLOCKS_PER_SECOND {
266 block_processor.buffer_render(&block);
267 block_processor.process_capture(false, false, None, &mut capture);
268 block_processor.update_echo_leakage_status(false);
269 }
270 }
271
272 #[test]
273 fn get_metrics_returns_values() {
274 let config = EchoCanceller3Config::default();
275 let block_processor = BlockProcessor::new(&config, 16000, 1, 1);
276 let metrics = block_processor.get_metrics();
277 assert!(metrics.delay_ms >= 0);
279 assert_eq!(metrics.delay_ms % 4, 0);
280 }
281
282 #[test]
283 fn set_audio_buffer_delay() {
284 let config = EchoCanceller3Config::default();
285 let mut block_processor = BlockProcessor::new(&config, 16000, 1, 1);
286 block_processor.set_audio_buffer_delay(20);
288 }
289
290 #[test]
291 fn set_capture_output_usage() {
292 let config = EchoCanceller3Config::default();
293 let mut block_processor = BlockProcessor::new(&config, 16000, 1, 1);
294 block_processor.set_capture_output_usage(false);
295 block_processor.set_capture_output_usage(true);
296 }
297}