Echoff
Echo off. Clean microphone on.
echoff is a small Python library for real-time acoustic echo cancellation.
It captures the audio rendered by the computer and the microphone on separate
streams, aligns their timelines, and feeds matched 10 ms frame pairs to WebRTC's
Audio Processing Module (APM).
The package deliberately does not contain voice activity detection, speech recognition, text-to-speech, or conversation policy. Applications receive clean microphone frames and decide what to do with them.
Current platform support
| Platform | Status | Capture backend |
|---|---|---|
| Windows | Supported | WASAPI loopback and microphone through PyAudioWPatch, with WDM-KS microphone fallback |
| Linux | Planned | PipeWire sink monitor and microphone source |
The WebRTC processor and timestamp aligner are platform-neutral. Only the device capture adapters are platform-specific.
Install
Echoff is published on PyPI and currently supports live device capture on Windows with Python 3.11 or newer:
python -m pip install echoff
The WebRTC processor and alignment components are platform-neutral; additional capture backends will be published as they receive physical hardware testing.
Install for development on Windows
git clone https://github.com/KoljaB/echoff D:\Projekte\echoff
cd D:\Projekte\echoff
py -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
Five-minute hardware check
List devices:
echoff devices
Record system audio, the raw microphone, and the AEC-cleaned microphone:
python examples\record_aec_session.py --duration 20 --log-level INFO
While it runs, play any speech or music through the normal speakers. You may also speak into the microphone. The output directory contains:
computer_audio.wav
microphone_raw.wav
microphone_aec.wav
events.jsonl
config.json
summary.json
run.log
For a repeatable loudspeaker stimulus, provide a WAV file:
python examples\record_aec_session.py `
--play-wav D:\audio\speech.wav `
--repetitions 3 `
--output D:\Temp\aec-probe
See Capture artifacts for the exact meaning of each file and Hardware probe for a repeatable test.
Library API
import time
from pathlib import Path
from echoff import AecCapture, AecConfig, AecFrame
def consume(frame: AecFrame) -> None:
# 48 kHz mono floating-point samples in [-1.0, 1.0].
send_to_your_audio_pipeline(frame.microphone_clean)
config = AecConfig(stream_delay_ms=50)
with AecCapture(
config,
on_frame=consume,
output_dir=Path("capture-artifacts"),
) as capture:
time.sleep(20)
print(capture.status())
For applications that already own their audio devices, use only the processor:
from echoff import AecConfig, WebRtcAecProcessor
processor = WebRtcAecProcessor(AecConfig())
clean_microphone = processor.process_pair(reference_samples, microphone_samples)
process_pair() is intentionally atomic: the far-end reference is always
submitted immediately before its matching microphone frame.
Deterministic replay pipelines with one shared clock may use
StreamingWebRtcAecProcessor to submit continuous reference and microphone
streams separately. Physical device capture should always use AecCapture so
timestamp alignment remains active.
Design guarantees
- One worker owns reference/microphone pairing and APM call order.
- Capture blocks carry monotonic end timestamps.
- Startup phase differences and later discontinuities are realigned instead of silently pairing stale frames.
- Every realignment starts a fresh AEC epoch exactly once.
- The echo-path readiness signal advances only on paired, active far-end audio.
- Libraries never configure the process-wide root logger.
- Raw and processed audio can be recorded for every run.
Read Architecture and Integration before adding a new backend.
Development
python -m unittest discover -s tests -v
ruff check .
mypy src
python -m build
Hardware tests are deliberately separate from unit tests. Unit tests must not open devices or play audio.
License
No distribution license has been selected yet. Until the repository owner adds one, the source is provided without a grant to copy, modify, or redistribute it.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file echoff-0.1.1.tar.gz.
File metadata
- Download URL: echoff-0.1.1.tar.gz
- Upload date:
- Size: 35.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9102ccc4ef269e22e8193481f1d31c61009201cbcfbb7c5c1810dc3178f6bbf2
|
|
| MD5 |
981b4e6af1570be08d7b7dc43e8616c1
|
|
| BLAKE2b-256 |
351d00d29e06da45b1a28a3654c1d4c35db128c84d0b28fc66772be45cc56037
|
File details
Details for the file echoff-0.1.1-py3-none-any.whl.
File metadata
- Download URL: echoff-0.1.1-py3-none-any.whl
- Upload date:
- Size: 32.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8fe03b3e4778968ad4afa7514aa6b5fb79c683c2b70f7c984e51e72e64c6ed2
|
|
| MD5 |
dc908f7fb3c4744197d171ed54640f8e
|
|
| BLAKE2b-256 |
230133183feeea0947911530b81899cf4459d917e2a7eff09407f7e95b3d81a2
|