Metadata-Version: 2.5
Name: livekit-plugins-murf-bvc
Version: 0.1.1
Summary: Murf background voice cancellation for LiveKit Agents
Requires-Python: >=3.10
Requires-Dist: livekit-agents>=1.2
Requires-Dist: livekit>=1.0.12
Requires-Dist: numpy
Description-Content-Type: text/markdown

# Murf BVC for LiveKit Agents

Background voice cancellation for voice agents. Murf BVC keeps the person talking to your agent and
removes everyone and everything else (TV, other people in the room, street and office noise) before
your agent's VAD, turn detection and speech-to-text see the audio. Fewer false interruptions, fewer
transcripts of someone else's words.

It runs on CPU inside your agent process, like LiveKit's own noise-cancellation plugin. No GPU, no
network calls, no extra services.

## Requirements

- Python 3.10+ and `livekit-agents` 1.2+
- Linux (glibc 2.28+: Ubuntu 20.04+, Debian 10+, RHEL/Rocky/Alma 8+, Amazon Linux 2023) on x86_64 or
  aarch64, or macOS 11+ (Apple Silicon) / 10.15+ (Intel)
- x86_64 CPUs need AVX2 and FMA (Intel Haswell / 2013 or newer, any AMD Zen); on ARM, AWS Graviton2 or
  newer, or any Apple Silicon Mac
- A Murf BVC license key (contact Murf)

## Install

```bash
pip install livekit-plugins-murf-bvc
```

## Quick start

1. Set your license key where the agent runs:

   ```bash
   export MURF_BVC_LICENSE="mbvc1...."
   ```

2. Pass `murf_bvc.BVC()` as the noise cancellation for the room's audio input:

   ```python
   from livekit.agents import Agent, AgentSession, JobContext, WorkerOptions, cli, room_io
   from livekit.plugins import murf_bvc


   async def entrypoint(ctx: JobContext):
       session = AgentSession(...)  # your STT, LLM, TTS, VAD, turn detection

       await session.start(
           room=ctx.room,
           agent=Agent(instructions="You are a helpful assistant."),
           room_options=room_io.RoomOptions(
               audio_input=room_io.AudioInputOptions(noise_cancellation=murf_bvc.BVC()),
           ),
       )


   if __name__ == "__main__":
       cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
   ```

That's all most agents need. The defaults are what we recommend for production.

## Options: when to change them

```python
murf_bvc.BVC(restore=True, normalize=True, license_key=None, native=True)
```

| Option | Default | Change it when |
| --- | --- | --- |
| `license_key` | read from `MURF_BVC_LICENSE` | You load secrets in code (from a secrets manager, say) rather than the environment. |
| `restore` | `True` | Leave on. While only the caller is talking, it gives back anything the model removed, so the caller's own voice is never thinned and STT accuracy holds up on clean calls. It runs a speaker check every 0.5 s of speech. Set `False` only if you'd rather have maximum removal at all times, or need to save that bit of CPU. |
| `normalize` | `True` | Leave on. It levels quiet and loud callers before the model so both get the same quality. There is no production reason to turn it off. |
| `native` | `True` | Leave on. It runs BVC inside LiveKit's audio pipeline. It falls back to a Python processor on its own if your `livekit` version predates audio-filter plugins, so you only set `False` when debugging. |

### Rooms with several participants

Nothing to change: one `BVC()` value serves every participant, each with its own independent state.

If you use `native=False` (or `BVCProcessor` directly), each processor handles one track, so pass a
selector instead:

```python
noise_cancellation=lambda params: murf_bvc.BVC(native=False)
```

## What to expect

- **Latency:** 10 ms at 16 kHz, about 13.6 ms at 24 or 48 kHz (resampling included).
- **CPU:** about 3% of one core per active participant on an AWS AMD EPYC instance, plus a speaker
  check every 0.5 s of speech while caller restore is on. Processing is single-threaded per stream, so
  it scales with the number of concurrent calls.
- **Audio:** any sample rate LiveKit delivers (8–96 kHz); stereo input is mixed to mono.

## License behaviour

The license is checked offline (signature and expiry), once per process. Without a valid license BVC
does not stop your agent: it logs an error and passes audio through unchanged, delayed by the same few
milliseconds, so calls keep working and a license expiring mid-call never knocks audio out of sync.

Check it at startup:

```python
murf_bvc.set_license(key)   # raises ValueError with the reason if the key is invalid
assert murf_bvc.licensed()
```

## Troubleshooting

| You see | Meaning |
| --- | --- |
| `murf_bvc: no license ...; audio passes through unprocessed` | `MURF_BVC_LICENSE` isn't set in the agent's environment and no `license_key` was passed. |
| `murf_bvc: license for '...' has expired` | Renew the key with Murf. |
| `this license does not carry a model key; reissue it` | An older-format key; ask Murf for a reissued one. |
| `Illegal instruction` when the agent starts | The CPU lacks AVX2/FMA (very old x86, or some emulated/virtualized CPUs). Use a newer instance type. |
| `pip` finds no matching distribution | Python older than 3.10, an unsupported platform, or glibc older than 2.28. |
