Adds gold-standard Linux echo cancellation: in-app WebRTC AEC3 (Audio Processing Module) via the webrtc-audio-processing crate, using the same algorithm as Chrome WebRTC, Zoom, Teams, and Jitsi. Runs entirely in-process, so it works identically on ALSA / PulseAudio / PipeWire systems — no dependency on user-configured echo-cancel modules. Architecture: - New crates/wzp-client/src/audio_linux_aec.rs module (~470 lines). Contains LinuxAecCapture and LinuxAecPlayback, both using CPAL under the hood but routing samples through a shared Arc<webrtc_audio_processing::Processor>. The playback path tees each 20 ms frame into APM.process_render_frame as the echo reference BEFORE handing the samples to CPAL's output callback. The capture path runs APM.process_capture_frame on each mic frame in place before pushing to the audio ring buffer. This is the "tee the playback ring" approach that Zoom/Teams/Jitsi use. - New `linux-aec` feature in wzp-client pulling in the webrtc-audio-processing crate at v2.x with the `bundled` sub-feature. Bundled means the vendored PulseAudio WebRTC C++ sources are statically compiled via meson+ninja at cargo build time — no runtime .so dependency, avoids Debian Bookworm's stale libwebrtc-audio-processing-dev 0.3 package (which predates AEC3). Dep is target-gated to Linux, so enabling the feature on non-Linux is a no-op. - lib.rs re-exports LinuxAecCapture/LinuxAecPlayback as AudioCapture/AudioPlayback when `linux-aec` is on, otherwise falls back to the CPAL audio_io path. Shared public API (start/ring/stop/Drop) means downstream code is unchanged. - New `linux-aec` feature in wzp-desktop forwards to wzp-client/linux-aec so `cargo tauri build -- --features wzp-desktop/linux-aec` builds the AEC variant. APM configuration: - EchoCancellation: High suppression, delay-agnostic mode on, extended filter on, stream_delay_ms=60 initial hint - NoiseSuppression: High - HighPassFilter: on - AGC: off (can fight Opus encoder's own gain staging + adaptive quality controller; add later if users report low mic level) Frame size handling: - Pipeline uses 20 ms frames (960 samples @ 48 kHz mono) - APM requires strict 10 ms (480 samples) per call - Each 20 ms frame is split into two 480-sample halves, APM called twice, halves stitched back - Same pattern for render and capture sides - Carry-buffer logic handles the case where CPAL delivers samples in arbitrary chunk sizes that don't divide 960 Build infrastructure: - scripts/Dockerfile.linux-desktop-builder adds meson, ninja-build, python3, clang for the webrtc-audio-processing bundled build - scripts/build-linux-desktop-docker.sh takes a new --aec flag that enables the linux-aec feature and renames the output artifacts with an `-aec` suffix so noAEC and AEC variants can coexist on disk Task #30. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
97 lines
3.8 KiB
TOML
97 lines
3.8 KiB
TOML
[package]
|
|
name = "wzp-client"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
rust-version.workspace = true
|
|
description = "WarzonePhone client library — for Android (JNI) and Windows desktop"
|
|
|
|
[dependencies]
|
|
wzp-proto = { workspace = true }
|
|
wzp-codec = { workspace = true }
|
|
wzp-fec = { workspace = true }
|
|
wzp-crypto = { workspace = true }
|
|
wzp-transport = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true }
|
|
async-trait = { workspace = true }
|
|
bytes = { workspace = true }
|
|
anyhow = "1"
|
|
serde = { workspace = true }
|
|
serde_json = "1"
|
|
chrono = "0.4"
|
|
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
|
|
cpal = { version = "0.15", optional = true }
|
|
libc = "0.2"
|
|
|
|
# coreaudio-rs is Apple-framework-only; gate it to macOS so enabling
|
|
# the `vpio` feature from a non-macOS target builds cleanly instead of
|
|
# pulling in a crate that can only link against Apple frameworks.
|
|
[target.'cfg(target_os = "macos")'.dependencies]
|
|
coreaudio-rs = { version = "0.11", optional = true }
|
|
|
|
# Windows-only: direct WASAPI bindings for the `windows-aec` feature.
|
|
# `windows` is Microsoft's official Rust COM bindings crate. We pull in
|
|
# only the audio + COM subfeatures we need — the crate is organized as
|
|
# a massive optional-feature tree, so enabling just these keeps compile
|
|
# times reasonable (~5s for these features vs ~60s for the full crate).
|
|
[target.'cfg(target_os = "windows")'.dependencies]
|
|
windows = { version = "0.58", optional = true, features = [
|
|
"Win32_Foundation",
|
|
"Win32_Media_Audio",
|
|
"Win32_Security",
|
|
"Win32_System_Com",
|
|
"Win32_System_Com_StructuredStorage",
|
|
"Win32_System_Threading",
|
|
"Win32_System_Variant",
|
|
] }
|
|
|
|
# Linux-only: WebRTC AEC3 (Audio Processing Module) bindings for the
|
|
# `linux-aec` feature. The `bundled` sub-feature of webrtc-audio-processing
|
|
# statically compiles the vendored PulseAudio webrtc-audio-processing C++
|
|
# sources via meson + ninja at cargo build time, avoiding Debian Bookworm's
|
|
# stale system libwebrtc-audio-processing-dev 0.3 package (which predates
|
|
# AEC3). Produces a self-contained static link — no runtime .so dep, same
|
|
# algorithm on every Linux distro.
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
webrtc-audio-processing = { version = "2", optional = true, features = ["bundled"] }
|
|
|
|
[features]
|
|
default = []
|
|
audio = ["cpal"]
|
|
# vpio enables coreaudio-rs but that dep is itself gated to macOS above,
|
|
# so enabling this feature on Windows/Linux is a no-op (the audio_vpio
|
|
# module is also #[cfg(target_os = "macos")] in lib.rs).
|
|
vpio = ["dep:coreaudio-rs"]
|
|
# windows-aec enables a direct WASAPI capture backend that opens the
|
|
# microphone under AudioCategory_Communications, turning on Windows's
|
|
# OS-level communications audio processing (AEC + noise suppression +
|
|
# AGC). The `windows` dep is itself target-gated to Windows above, so
|
|
# enabling this feature on non-Windows targets is a no-op (the
|
|
# audio_wasapi module is also #[cfg(target_os = "windows")] in lib.rs).
|
|
windows-aec = ["dep:windows"]
|
|
# linux-aec enables a CPAL + WebRTC AEC3 capture/playback backend that
|
|
# runs the WebRTC Audio Processing Module (same algo as Chrome / Zoom /
|
|
# Teams) in-process, using the playback PCM as the reference signal for
|
|
# echo cancellation. The webrtc-audio-processing dep is target-gated to
|
|
# Linux above, so enabling this feature on non-Linux targets is a no-op
|
|
# (the audio_linux_aec module is also #[cfg(target_os = "linux")] in
|
|
# lib.rs).
|
|
linux-aec = ["dep:webrtc-audio-processing"]
|
|
|
|
[[bin]]
|
|
name = "wzp-client"
|
|
path = "src/cli.rs"
|
|
|
|
[[bin]]
|
|
name = "wzp-bench"
|
|
path = "src/bench_cli.rs"
|
|
|
|
[dev-dependencies]
|
|
tokio = { workspace = true }
|
|
wzp-relay = { path = "../wzp-relay" }
|
|
wzp-crypto = { workspace = true }
|
|
wzp-proto = { workspace = true }
|
|
async-trait = { workspace = true }
|