Skip to content

Commit fddf41d

Browse files
committed
Expose custom configuration of internal AEC3
1 parent 57f7602 commit fddf41d

File tree

5 files changed

+109
-7
lines changed

5 files changed

+109
-7
lines changed

src/config.rs

+22
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,28 @@ impl From<HighPassFilter> for ffi::AudioProcessing_Config_HighPassFilter {
101101
}
102102
}
103103

104+
/// [Highly Experimental] Configurations of internal AEC3 implementation.
105+
/// TODO(skywhale): Add more parameters from:
106+
/// https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/blob/master/webrtc/api/audio/echo_canceller3_config.h
107+
#[derive(Debug, Clone, PartialEq)]
108+
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
109+
pub struct EchoCanceller3Config {
110+
/// Number of linear filters to apply.
111+
pub num_filters: usize,
112+
}
113+
114+
impl Default for EchoCanceller3Config {
115+
fn default() -> Self {
116+
Self { num_filters: 5 }
117+
}
118+
}
119+
120+
impl From<EchoCanceller3Config> for ffi::EchoCanceller3ConfigOverride {
121+
fn from(other: EchoCanceller3Config) -> Self {
122+
Self { num_filters: other.num_filters as i32 }
123+
}
124+
}
125+
104126
/// AEC (acoustic echo cancellation) configuration.
105127
#[derive(Debug, Clone, PartialEq)]
106128
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]

src/lib.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
mod config;
99
mod stats;
1010

11-
use std::{error, fmt, sync::Arc};
11+
use std::{error, fmt, ptr::null, sync::Arc};
1212
use webrtc_audio_processing_sys as ffi;
1313

1414
pub use config::*;
@@ -49,7 +49,15 @@ impl Processor {
4949
/// instantiation, however new configs can be be passed to `set_config()`
5050
/// at any time during processing.
5151
pub fn new(config: &InitializationConfig) -> Result<Self, Error> {
52-
let inner = Arc::new(AudioProcessing::new(config)?);
52+
Self::with_aec3_config(config, None)
53+
}
54+
55+
/// Creates a new `Processor` with custom AEC3 configuration.
56+
pub fn with_aec3_config(
57+
config: &InitializationConfig,
58+
aec3_config: Option<EchoCanceller3Config>,
59+
) -> Result<Self, Error> {
60+
let inner = Arc::new(AudioProcessing::new(config, aec3_config)?);
5361
let num_samples = inner.num_samples_per_frame();
5462
Ok(Self {
5563
inner,
@@ -64,6 +72,13 @@ impl Processor {
6472
})
6573
}
6674

75+
/// Initializes internal states, while retaining all user settings. This should be called before
76+
/// beginning to process a new audio stream. However, it is not necessary to call before processing
77+
/// the first stream after creation.
78+
pub fn initialize(&mut self) {
79+
self.inner.initialize()
80+
}
81+
6782
/// Processes and modifies the audio frame from a capture device by applying
6883
/// signal processing as specified in the config. `frame` should hold an
6984
/// interleaved f32 audio frame, with NUM_SAMPLES_PER_FRAME samples.
@@ -182,13 +197,23 @@ struct AudioProcessing {
182197
}
183198

184199
impl AudioProcessing {
185-
fn new(config: &InitializationConfig) -> Result<Self, Error> {
200+
fn new(
201+
config: &InitializationConfig,
202+
aec3_config: Option<EchoCanceller3Config>,
203+
) -> Result<Self, Error> {
204+
let aec3_config = if let Some(aec3_config) = aec3_config {
205+
&aec3_config.into() as *const ffi::EchoCanceller3ConfigOverride
206+
} else {
207+
null()
208+
};
209+
186210
let mut code = 0;
187211
let inner = unsafe {
188212
ffi::audio_processing_create(
189213
config.num_capture_channels as i32,
190214
config.num_render_channels as i32,
191215
config.sample_rate_hz as i32,
216+
aec3_config,
192217
&mut code,
193218
)
194219
};
@@ -199,6 +224,10 @@ impl AudioProcessing {
199224
}
200225
}
201226

227+
fn initialize(&self) {
228+
unsafe { ffi::initialize(self.inner) }
229+
}
230+
202231
fn process_capture_frame(&self, frame: &mut Vec<Vec<f32>>) -> Result<(), Error> {
203232
let mut frame_ptr = frame.iter_mut().map(|v| v.as_mut_ptr()).collect::<Vec<*mut f32>>();
204233
unsafe {
@@ -412,8 +441,8 @@ mod tests {
412441
..InitializationConfig::default()
413442
};
414443
let mut ap = Processor::new(&config).unwrap();
415-
416-
// tweak params outside of config
444+
445+
// tweak params outside of config
417446
ap.set_output_will_be_muted(true);
418447
ap.set_stream_key_pressed(true);
419448

@@ -427,5 +456,4 @@ mod tests {
427456

428457
// it shouldn't crash
429458
}
430-
431459
}

webrtc-audio-processing-sys/build.rs

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ fn out_dir() -> PathBuf {
77
std::env::var("OUT_DIR").expect("OUT_DIR environment var not set.").into()
88
}
99

10+
fn src_dir() -> PathBuf {
11+
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR environment var not set.").into()
12+
}
13+
1014
#[cfg(not(feature = "bundled"))]
1115
mod webrtc {
1216
use super::*;
@@ -62,6 +66,7 @@ mod webrtc {
6266
let mut include_paths = vec![
6367
out_dir().join("include"),
6468
out_dir().join("include").join("webrtc-audio-processing-1"),
69+
src_dir().join("webrtc-audio-processing").join("webrtc"),
6570
];
6671
let mut lib_paths = vec![out_dir().join("lib")];
6772

webrtc-audio-processing-sys/src/wrapper.cpp

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
#include "wrapper.hpp"
22

3+
// These definitions shouldn't affect the implementation of AEC3.
4+
// We are defining them to work around some build-time assertions
5+
// when including the internal header file of echo_canceller3.h
6+
#define WEBRTC_APM_DEBUG_DUMP 0
7+
#define WEBRTC_POSIX
8+
#include <modules/audio_processing/aec3/echo_canceller3.h>
9+
310
#include <algorithm>
411
#include <memory>
512

@@ -29,6 +36,32 @@ OptionalBool from_absl_optional(const absl::optional<bool>& optional) {
2936
return rv;
3037
}
3138

39+
webrtc::EchoCanceller3Config build_aec3_config(const EchoCanceller3ConfigOverride& override) {
40+
webrtc::EchoCanceller3Config config;
41+
config.delay.num_filters = override.num_filters;
42+
return config;
43+
}
44+
45+
class EchoCanceller3Factory : public webrtc::EchoControlFactory {
46+
public:
47+
explicit EchoCanceller3Factory(const webrtc::EchoCanceller3Config& config)
48+
: config_(config) {}
49+
50+
std::unique_ptr<webrtc::EchoControl> Create(
51+
int sample_rate_hz,
52+
int num_render_channels,
53+
int num_capture_channels) override {
54+
return std::unique_ptr<webrtc::EchoControl>(new webrtc::EchoCanceller3(
55+
config_,
56+
sample_rate_hz,
57+
num_render_channels,
58+
num_capture_channels));
59+
}
60+
61+
private:
62+
webrtc::EchoCanceller3Config config_;
63+
};
64+
3265
} // namespace
3366

3467
struct AudioProcessing {
@@ -43,9 +76,16 @@ AudioProcessing* audio_processing_create(
4376
int num_capture_channels,
4477
int num_render_channels,
4578
int sample_rate_hz,
79+
const EchoCanceller3ConfigOverride* aec3_config_override,
4680
int* error) {
4781
AudioProcessing* ap = new AudioProcessing;
48-
ap->processor.reset(webrtc::AudioProcessingBuilder().Create());
82+
83+
webrtc::AudioProcessingBuilder builder;
84+
if (aec3_config_override != nullptr) {
85+
auto* factory = new EchoCanceller3Factory(build_aec3_config(*aec3_config_override));
86+
builder.SetEchoControlFactory(std::unique_ptr<webrtc::EchoControlFactory>(factory));
87+
}
88+
ap->processor.reset(builder.Create());
4989

5090
const bool has_keyboard = false;
5191
ap->capture_stream_config = webrtc::StreamConfig(

webrtc-audio-processing-sys/src/wrapper.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,18 @@ struct Stats {
4141
OptionalInt delay_ms;
4242
};
4343

44+
// A slimmed-down version of webrtc::EchoCanceller3Config.
45+
// We can not just expose the webrtc variant as the binding loses all the default values.
46+
struct EchoCanceller3ConfigOverride {
47+
int num_filters;
48+
};
49+
4450
// Creates a new instance of AudioProcessing.
4551
AudioProcessing* audio_processing_create(
4652
int num_capture_channels,
4753
int num_render_channels,
4854
int sample_rate_hz,
55+
const EchoCanceller3ConfigOverride* aec3_config_override,
4956
int* error);
5057

5158
// Processes and modifies the audio frame from a capture device.

0 commit comments

Comments
 (0)