Skip to main content

Real-time AEC, noise suppression, and VAD for voice agents — wraps SpeexDSP, RNNoise, and Silero VAD.

Project description

voiceclean

Real-time acoustic echo cancellation (AEC), noise suppression, and voice activity detection (VAD) for voice agents. Built for telephony (8 kHz PSTN audio), works at any sample rate.

Wraps three proven open-source libraries into a single Python package:

Feature Library What it does
AEC SpeexDSP Removes the bot's own speech from the caller's mic signal. Essential when the telephony provider doesn't do carrier-side echo cancellation.
Noise suppression RNNoise via pyrnnoise Neural noise reduction. Best at 48 kHz; for 8 kHz telephony, AEC alone is usually sufficient.
VAD Silero VAD Detects speech vs silence. <1 ms per chunk on CPU, 8 kHz native support, ~2 MB ONNX model.

Why this exists

Cloud telephony providers like Twilio perform echo cancellation on their infrastructure before delivering audio to your WebSocket. Others (like Exotel) don't — the bot's TTS output bleeds through the caller's mic and gets transcribed as user input, creating a self-conversation loop.

Commercial solutions like ai-coustics ($149/mo) provide noise suppression and VAD but not AEC. voiceclean fills that gap with open-source components.

Install

pip install voiceclean            # core (numpy + soxr only)
pip install voiceclean[all]       # AEC + noise suppression + VAD + Pipecat integration
pip install voiceclean[silero]    # VAD only
pip install voiceclean[rnnoise]   # noise suppression only

System dependency for AEC — libspeexdsp must be installed on the host:

# Debian / Ubuntu
sudo apt install libspeexdsp-dev

# macOS
brew install speexdsp

Quick start

Standalone

from voiceclean import VoiceClean

vc = VoiceClean(sample_rate=8000)

# Feed the bot's outgoing audio as AEC reference
vc.feed_reference(bot_pcm_bytes)

# Process the caller's mic audio
result = vc.process(mic_pcm_bytes)
result.audio        # cleaned PCM bytes (echo removed)
result.is_speech    # bool — is the caller speaking?
result.speech_prob  # float 0.0–1.0

Individual components

from voiceclean.aec import AEC
from voiceclean.denoise import Denoiser
from voiceclean.vad import VAD

# Echo cancellation
aec = AEC(sample_rate=8000, filter_length=4000)
aec.feed_reference(bot_audio)
clean = aec.process(mic_audio)

# Noise suppression (best at 48 kHz; resamples internally)
denoiser = Denoiser(sample_rate=8000)
clean = denoiser.process(noisy_audio)

# Voice activity detection
vad = VAD(sample_rate=8000, threshold=0.5)
result = vad.process(audio)  # result.is_speech, result.speech_prob

Pipecat integration

voiceclean plugs into Pipecat as a BaseAudioFilter + VADAnalyzer. The key design: a reference_collector FrameProcessor captures outgoing audio for the AEC reference signal.

from voiceclean.pipecat import VoiceCleanFilter

vc_filter = VoiceCleanFilter(sample_rate=8000)

# Wire as audio input filter on the transport
transport = FastAPIWebsocketTransport(
    websocket=websocket,
    params=FastAPIWebsocketParams(
        audio_in_filter=vc_filter,
        serializer=serializer,
    ),
)

# VAD for turn detection
vad_analyzer = vc_filter.create_vad_analyzer()

# Build pipeline — reference_collector MUST go before transport.output()
pipeline = Pipeline([
    transport.input(),
    stt,
    user_aggregator,
    llm,
    tts,
    # ... other processors ...
    vc_filter.reference_collector,   # captures outgoing audio for AEC
    transport.output(),
    assistant_aggregator,
])

How AEC works

Echo cancellation needs two audio streams:

  1. Reference signal — what the bot is sending to the speaker (outgoing TTS audio)
  2. Mic signal — what the caller's mic picks up (speech + echo of the bot)

SpeexDSP's adaptive filter learns the echo path (including network delay, acoustic coupling, codec artifacts) and subtracts the predicted echo from the mic signal. The async playback/capture API handles delay alignment internally — you don't need to time-synchronize the two streams.

Bot TTS audio ──► feed_reference() ──► SpeexDSP learns echo path
                                              │
Caller mic audio ──► process() ─────► SpeexDSP subtracts echo ──► clean audio

Filter length: Default 4000 samples = 500 ms at 8 kHz. This must cover the full echo round-trip delay (typically 100–500 ms on PSTN). Increase if you hear residual echo on high-latency paths.

Audio format

All audio is PCM int16 mono (signed 16-bit little-endian, single channel). This is the standard format for telephony audio and what Pipecat's frame processors use internally.

Notes on RNNoise

RNNoise operates at 48 kHz internally. For 8 kHz telephony audio, it resamples up and back (8k → 48k → 8k), which can degrade narrowband speech quality. In telephony applications, AEC alone is usually sufficient — the PSTN noise floor is low enough for STT accuracy. The Pipecat filter disables RNNoise by default for this reason.

RNNoise works well for wideband (16 kHz+) applications where the full frequency range benefits from neural denoising.

Credits

This package wraps open-source libraries by their respective authors:

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

voiceclean-0.3.0.tar.gz (14.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

voiceclean-0.3.0-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file voiceclean-0.3.0.tar.gz.

File metadata

  • Download URL: voiceclean-0.3.0.tar.gz
  • Upload date:
  • Size: 14.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for voiceclean-0.3.0.tar.gz
Algorithm Hash digest
SHA256 6cc274ff5bd231bbe75594e9787df49d093c659ad951d6dce266c0823fc52f59
MD5 af41903311f7baad5995fa447325ede4
BLAKE2b-256 8ab3587a07011cc98c9c90162f2956cf6fa4651f5626c38ae01f9129527a43c2

See more details on using hashes here.

File details

Details for the file voiceclean-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: voiceclean-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for voiceclean-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 edc0542624eef153d22f79077894d115d05fc79f20ac9596d483ef0c3cf99c3e
MD5 7ad3ceecfbc3cae73e3d862d040c66b3
BLAKE2b-256 23aaabccd11d33c3d824b84a4a32a069c29ab8c8925996ecdd8c670e4e521569

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page