|
| 1 | +use livekit::webrtc::native::apm::AudioProcessingModule; |
| 2 | +use log::warn; |
| 3 | +use std::sync::Mutex; |
| 4 | + |
| 5 | +const APM_STREAM_DELAY_MS: i32 = 50; |
| 6 | + |
| 7 | +pub struct SharedAudioProcessing { |
| 8 | + apm: Mutex<AudioProcessingModule>, |
| 9 | + sample_rate: u32, |
| 10 | + num_channels: i32, |
| 11 | +} |
| 12 | + |
| 13 | +impl SharedAudioProcessing { |
| 14 | + pub fn new(sample_rate: u32, num_channels: i32) -> Self { |
| 15 | + let mut apm = AudioProcessingModule::new( |
| 16 | + true, // echo cancellation |
| 17 | + false, // AGC disabled by request |
| 18 | + true, // high-pass filter |
| 19 | + true, // noise suppression |
| 20 | + ); |
| 21 | + if let Err(err) = apm.set_stream_delay_ms(APM_STREAM_DELAY_MS) { |
| 22 | + warn!("APM set_stream_delay_ms failed: {err}"); |
| 23 | + } |
| 24 | + |
| 25 | + Self { apm: Mutex::new(apm), sample_rate, num_channels } |
| 26 | + } |
| 27 | + |
| 28 | + pub fn process_capture(&self, data: &mut [i16]) { |
| 29 | + if data.is_empty() { |
| 30 | + return; |
| 31 | + } |
| 32 | + |
| 33 | + if let Err(err) = self.apm.lock().unwrap().process_stream( |
| 34 | + data, |
| 35 | + self.sample_rate as i32, |
| 36 | + self.num_channels, |
| 37 | + ) { |
| 38 | + warn!("APM process_stream failed: {err}"); |
| 39 | + } |
| 40 | + } |
| 41 | + |
| 42 | + pub fn process_render(&self, data: &mut [i16]) { |
| 43 | + if data.is_empty() { |
| 44 | + return; |
| 45 | + } |
| 46 | + |
| 47 | + if let Err(err) = self.apm.lock().unwrap().process_reverse_stream( |
| 48 | + data, |
| 49 | + self.sample_rate as i32, |
| 50 | + self.num_channels, |
| 51 | + ) { |
| 52 | + warn!("APM process_reverse_stream failed: {err}"); |
| 53 | + } |
| 54 | + } |
| 55 | +} |
0 commit comments