Metadata-Version: 2.4
Name: echoff
Version: 0.1.1
Summary: Echo off: real-time AEC with synchronized system-audio and microphone capture
Project-URL: Documentation, https://github.com/KoljaB/echoff/tree/main/docs
Project-URL: Issues, https://github.com/KoljaB/echoff/issues
Project-URL: Repository, https://github.com/KoljaB/echoff
Keywords: audio,aec,echo-cancellation,webrtc,wasapi
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Multimedia :: Sound/Audio :: Capture/Recording
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: livekit<2,>=1.1.14
Requires-Dist: PyAudioWPatch==0.2.12.8; sys_platform == "win32"
Requires-Dist: sounddevice<1,>=0.5.5; sys_platform == "win32"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: mypy>=1.15; extra == "dev"
Requires-Dist: pytest>=8.3; extra == "dev"
Requires-Dist: pytest-cov>=6; extra == "dev"
Requires-Dist: ruff>=0.11; extra == "dev"

# 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](https://pypi.org/project/echoff/) and currently
supports live device capture on Windows with Python 3.11 or newer:

```powershell
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

```powershell
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:

```powershell
echoff devices
```

Record system audio, the raw microphone, and the AEC-cleaned microphone:

```powershell
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:

```text
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:

```powershell
python examples\record_aec_session.py `
  --play-wav D:\audio\speech.wav `
  --repetitions 3 `
  --output D:\Temp\aec-probe
```

See [Capture artifacts](docs/capture-artifacts.md) for the exact meaning of
each file and [Hardware probe](docs/hardware-probe.md) for a repeatable test.

## Library API

```python
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:

```python
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](docs/architecture.md) and [Integration](docs/integration.md)
before adding a new backend.

## Development

```powershell
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.
