aec_rs/
lib.rs

1use std::os::raw::c_void;
2/// See https://www.speex.org/docs/api/speex-api-reference/speex__echo_8h.html
3
4#[derive(Debug, Clone)]
5pub struct AecConfig {
6    pub frame_size: usize,
7    pub filter_length: i32,
8    pub sample_rate: u32,
9    pub enable_preprocess: bool,
10}
11
12impl Default for AecConfig {
13    /// Default for 16khz
14    fn default() -> Self {
15        Self {
16            frame_size: 160,
17            filter_length: 1600,
18            sample_rate: 16000,
19            enable_preprocess: true,
20        }
21    }
22}
23
24pub struct Aec {
25    echo_state: *mut aec_rs_sys::SpeexEchoState,
26    preprocess_state: Option<*mut aec_rs_sys::SpeexPreprocessState>,
27}
28
29impl Aec {
30    pub fn new(config: &AecConfig) -> Self {
31        let echo_state = unsafe {
32            aec_rs_sys::speex_echo_state_init(config.frame_size as i32, config.filter_length)
33        };
34        let preprocess_state = if config.enable_preprocess {
35            unsafe {
36                let den = aec_rs_sys::speex_preprocess_state_init(
37                    config.frame_size as i32,
38                    config.sample_rate as _,
39                );
40                aec_rs_sys::speex_preprocess_ctl(
41                    den,
42                    aec_rs_sys::SPEEX_PREPROCESS_SET_ECHO_STATE as _,
43                    echo_state as *mut c_void,
44                );
45                Some(den)
46            }
47        } else {
48            None
49        };
50
51        Aec {
52            echo_state,
53            preprocess_state,
54        }
55    }
56
57    pub fn cancel_echo(&self, rec_buffer: &[i16], echo_buffer: &[i16], out_buffer: &mut [i16]) {
58        unsafe {
59            aec_rs_sys::speex_echo_cancellation(
60                self.echo_state,
61                rec_buffer.as_ptr(),
62                echo_buffer.as_ptr(),
63                out_buffer.as_mut_ptr(),
64            );
65            if let Some(preprocess_state) = self.preprocess_state {
66                aec_rs_sys::speex_preprocess_run(preprocess_state, out_buffer.as_mut_ptr());
67            }
68        }
69    }
70}
71
72impl Drop for Aec {
73    fn drop(&mut self) {
74        unsafe {
75            aec_rs_sys::speex_echo_state_destroy(self.echo_state);
76            if let Some(preprocess_state) = self.preprocess_state {
77                aec_rs_sys::speex_preprocess_state_destroy(preprocess_state);
78            }
79        }
80    }
81}