# Poor Voice Isolation

> Diagnose and fix noisy, clipped, or echoey caller audio: browser noise suppression, first-syllable clipping, and speakerphone echo on telephony legs.

If ASR misfires, the agent talks over the caller, or transcripts are full of
half-words, the problem is almost always **input audio quality at the capture
edge**, not the model. FirstByte Voice cleans audio where it is captured
(browser/app), not in the server media plane. So the fix depends on which leg
the noisy audio comes in on.

Work through the symptom table first. Then use the diagnostic steps to confirm
which edge is at fault before you change anything.

## Symptom → cause → fix

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Constant hiss/hum, HVAC or fan in transcripts, ASR word errors on a **browser/app** caller | Noise suppression was disabled on capture, or a raw/BYO track was passed | Enable `noiseSuppression` again (and `echoCancellation`/`autoGainControl`) in `captureMicrophone()` |
| The first syllable of each caller turn is missing ("...es, that's right" instead of "Yes, that's right") | The turn detector's `prefix_padding_ms` is too low. The speech-start marker trims real onset before it reaches ASR | Raise `prefix_padding_ms` on the agent's `turn_detection` |
| The **agent's own voice** returns as caller audio. The agent cancels itself / stutters. The caller is on **speakerphone** or a raw SIP/PSTN leg | The media plane has no server-side echo canceller. The browser AEC is bypassed or absent | Route through browser AEC where possible. On telephony, keep the barge gate conservative, and ask the caller to use a handset |
| Level pumping — the audio swings loud/quiet, and quiet talkers get lost | There is no server-side automatic gain control, and capture-side AGC is off | Enable `autoGainControl` on browser capture. On telephony, rely on carrier/handset gain |
| A loud caller clips (distortion) even with a clean network. MOS looks fine | The input was already clipped upstream (handset/PBX gain staging) before it reached us | The server cannot recover it. Fix it at the source device/PBX |

> **NOTE:**
> FirstByte Voice does **not** run echo cancellation (AEC), automatic gain
>   control (AGC), or a server-side denoise stage in the media plane. That plane
>   is a codec/timing path by design. Cleanup lives at the capture edge. See
>   [/modalities/voice/concepts/voice-isolation](/modalities/voice/concepts/voice-isolation)
>   for why, and for what *is* built.

## Narrow it down first

  1. **Identify the leg**
Is the noisy caller on a **browser/app** connection or a **SIP/PSTN**
    trunk? Browser/app legs can be cleaned client-side. Telephony legs cannot
    be cleaned by us at all. Their cleanup is entirely on the carrier/handset
    side.
  2. **Listen to the recording, split by channel**
Call recordings are written **stereo — caller on the left channel, agent
    on the right**. Solo the left channel. If the noise/echo is there, it
    entered on the inbound leg (capture or carrier). If the agent's voice
    bleeds into the *left* channel, you have echo, not a source-noise problem.
    See
    [/modalities/voice/observability/call-traces](/modalities/voice/observability/call-traces).
  3. **Check the media-quality score**
The media plane derives a per-call MOS estimate from packet loss and
    jitter. A *good* MOS with *bad-sounding* audio means the transport is
    correct, and the problem is signal quality at the source, not the network.
    Do not chase jitter buffers. A poor MOS points you at
    [/modalities/voice/troubleshooting/high-latency](/modalities/voice/troubleshooting/high-latency)
    and packet loss instead.
  4. **Confirm the capture settings (browser/app only)**
In the browser, inspect the active audio track's constraints.
    `track.getSettings()` must report `echoCancellation`, `noiseSuppression`,
    and `autoGainControl` as `true`, unless you intentionally disabled them.

## Fix: noise suppression is off on browser capture

`captureMicrophone()` enables echo cancellation, automatic gain control, and
noise suppression by default. Noisy browser input almost always means those
defaults were overridden, or a pre-captured track was passed that never went
through the device pipeline.

  
    ```ts
    import { captureMicrophone } from "clutchcall_connect/moqt";

    // All three processors ON (this is the default).
    const cap = await captureMicrophone(publication);
    ```
  
  
    ```ts
    const cap = await captureMicrophone(publication, {
      audioConstraints: {
        echoCancellation: true,
        autoGainControl: true,
        noiseSuppression: true,
      },
    });
    ```
  

> **WARNING:**
> If you pass your own `{ track }`, FirstByte Voice sends it **as-is**. The
>   browser processors do not run again on an external track. Clean the track
>   before you hand it over, or let `captureMicrophone()` capture the mic
>   itself.

Full capture reference:
[/modalities/voice/transport-web/browser-audio-capture](/modalities/voice/transport-web/browser-audio-capture).

## Fix: first syllables are being clipped

Sometimes callers' openings ("Yes", "No", a digit) arrive truncated at ASR.
The turn detector marks speech-start slightly *after* the real onset.
`prefix_padding_ms` is the amount of pre-speech audio kept ahead of that
marker. Raise it to preserve the onset.

```json Agent turn_detection
{
  "entry_node": "ASR",
  "pipeline": { "ASR": { }, "LLM": { }, "TTS": { } },
  "turn_detection": {
    "type": "silero",
    "prefix_padding_ms": 500,
    "silence_duration_ms": 500
  }
}
```

- **`prefix_padding_ms`** (`number`, default `300`) — Milliseconds of audio kept **ahead** of the detected speech-start marker.   Raise it (for example, 400–600) if the ASR clips first syllables. The cost   is a little extra leading audio per turn. This is the same setting   documented in   [turn detection](/modalities/voice/concepts/turn-detection).

Set it from the Contact Center console at `agent.firstbyte.fast`, or push it through
the control-plane API. See
[/modalities/voice/runtime/configuration](/modalities/voice/runtime/configuration).

## Fix: echo on speakerphone (no server AEC)

There is **no echo canceller in the media plane**. On a browser/app leg, the
device's own AEC removes the agent's voice before it is encoded. On a raw
SIP/PSTN leg — especially a caller on **speakerphone** — nothing on our side
cancels that echo. The agent's text-to-speech can loop back into the inbound
audio and trigger a false interruption.

  1. **Prefer an AEC-capable path**
Where you control the client, keep callers on the browser/app SDK (device
    AEC on), not on a bare SIP endpoint. A handset or headset beats a
    speakerphone in an open room every time.
  2. **Keep the barge-in gate conservative on non-AEC legs**
Because the agent's own audio can bleed back on a no-AEC leg, the barge-in
    gate is **not** lowered while the agent speaks on telephony. If the agent
    cuts itself off, do not lower that gate on the PSTN path. The
    interruption-gate behavior is covered in
    [/modalities/voice/concepts/turn-detection](/modalities/voice/concepts/turn-detection)
    and
    [/modalities/voice/troubleshooting/barge-in](/modalities/voice/troubleshooting/barge-in).
  3. **Rule out real echo vs. self-interruption**
Solo the caller (left) channel of the recording. Faint agent voice on that
    channel = acoustic echo from the caller's room → fix the device/handset.
    No echo on the channel, but the agent still stops mid-sentence = a
    barge-in tuning problem, not isolation → see the barge-in page above.

> **NOTE:**
> Speaker identification, voiceprint/biometrics, and acoustic diarization are
>   **not built**. Do not reach for them to separate the caller from the agent.
>   You already get clean per-party separation structurally: the two legs are
>   distinct streams, and recordings are stereo (caller left / agent right).

## What you can and can't fix here

| If the audio is… | Fixable by you? | Where |
| --- | --- | --- |
| Noisy on a browser/app caller | Yes | Enable capture-side noise suppression again |
| Clipped at the start of turns | Yes | Raise `prefix_padding_ms` |
| Echoey on a browser/app caller | Yes | Check that device AEC is on (do not disable `echoCancellation`) |
| Echoey on a speakerphone SIP/PSTN caller | Only at the source | There is no server AEC. Move to a handset / keep the barge gate high |
| Already clipped/distorted before it reached us | No | Fix the upstream device or PBX gain staging |

  - **[Voice isolation concepts](/modalities/voice/concepts/voice-isolation)** — Where AEC/AGC/NS run, and why the media plane has no APM stage.
  - **[Turn detection & barge-in](/modalities/voice/concepts/turn-detection)** — `prefix_padding_ms`, the interruption gate, and why it stays high on telephony.
  - **[Browser audio capture](/modalities/voice/transport-web/browser-audio-capture)** — The capture constraints that control browser-side cleanup.
  - **[High latency](/modalities/voice/troubleshooting/high-latency)** — When a poor MOS points at the network, not signal quality.
