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>
55 lines
2.4 KiB
Docker
55 lines
2.4 KiB
Docker
# =============================================================================
|
|
# WZ Phone — Linux x86_64 Tauri desktop build image
|
|
#
|
|
# Thin extension of wzp-android-builder that adds the GTK3 + WebKit2GTK 4.1 +
|
|
# libsoup-3.0 + AppIndicator dev packages needed to build the Tauri desktop
|
|
# app for Linux. Everything else (Rust, Node.js, cmake, pkg-config, cpal
|
|
# libasound deps, tauri-cli) is inherited from the base image.
|
|
#
|
|
# Build:
|
|
# docker build -t wzp-linux-desktop-builder -f Dockerfile.linux-desktop-builder .
|
|
#
|
|
# Run: driven by scripts/build-linux-desktop-docker.sh (see that file).
|
|
# =============================================================================
|
|
FROM wzp-android-builder
|
|
|
|
USER root
|
|
|
|
# Tauri 2.x Linux dependencies.
|
|
# - libwebkit2gtk-4.1-dev: the WebView backend. Tauri 2.x uses 4.1 (not 4.0).
|
|
# - libsoup-3.0-dev: HTTP client used by webkit2gtk. Must match its major.
|
|
# - libgtk-3-dev: GTK3 headers (webkit2gtk still uses GTK3).
|
|
# - libayatana-appindicator3-dev: system tray / status icon. Optional at
|
|
# runtime but tauri-build's feature-detection includes it.
|
|
# - librsvg2-dev: SVG rendering in the menu/icon code.
|
|
# - libglib2.0-dev: GObject introspection headers (transitive, but explicit).
|
|
# - patchelf: used by the tauri bundler to rewrite rpaths in the final binary.
|
|
# - file: already in the base, but tauri-build checks for it by name.
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
libwebkit2gtk-4.1-dev \
|
|
libsoup-3.0-dev \
|
|
libgtk-3-dev \
|
|
libayatana-appindicator3-dev \
|
|
librsvg2-dev \
|
|
libglib2.0-dev \
|
|
patchelf \
|
|
meson \
|
|
ninja-build \
|
|
python3 \
|
|
clang \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# ── webrtc-audio-processing build requirements ──────────────────────────────
|
|
# The `webrtc-audio-processing` Rust crate with the `bundled` feature vendors
|
|
# the PulseAudio webrtc-audio-processing C++ library and builds it via meson
|
|
# + ninja at `cargo build` time. That avoids Debian Bookworm's stale
|
|
# libwebrtc-audio-processing-dev 0.3-1 package (which predates AEC3) and gives
|
|
# us a self-contained static link — no runtime .so dependency, same algorithm
|
|
# on every Linux distro regardless of what apt ships.
|
|
#
|
|
# apt deps for the bundled build: meson, ninja-build, python3, clang,
|
|
# build-essential (already present via android-builder base).
|
|
|
|
USER builder
|
|
WORKDIR /build/source
|