---
title: Microphone calibration for voice barge-in (tune sensitivity per mic)
---

# Microphone calibration for voice barge-in (tune sensitivity per mic)

## What it is

Voice barge-in lets you interrupt the AI mid-sentence by talking over it, so a
spoken read-back stops the moment you start speaking. To decide "the user is
talking now," Omniscio listens to your microphone and asks a small on-device model
how speech-like each moment of audio is. Whether a given level counts as "you
talking" versus "background noise" depends heavily on your specific microphone
and room. A laptop mic in a quiet office, a USB headset next to a loud fan, and
a phone propped across the desk all produce very different baselines.

**Microphone calibration** is a short guided test that measures your mic and
room once, then tunes the barge-in sensitivity to them. It exists to solve two
opposite failure modes at the same time:

- Without tuning, a sensitive setup treats background noise (a fan, a keyboard,
  an air conditioner) as speech and falsely interrupts the AI.
- An over-cautious setting does the reverse: a quiet talker speaks but never
  registers, so barge-in never fires.

Calibration finds a threshold that sits comfortably above your room's normal
background noise yet below your normal speaking voice, so real speech reliably
interrupts and ambient noise does not.

## Where to find it

Open **Settings -> Voice Control**. Voice Control is a top-level Settings
section with accordion cards; the relevant one is **Voice Report Back**. Expand
it and turn on **Enable Voice Report Back** to reveal the inner controls.

Inside that card, when the Lab flag is enabled you see, in order:

1. **Enable barge-in (Lab)** toggle - the `voiceBargeInLabFlag` switch described
   above, with the description "Interrupt the AI mid-sentence by speaking.
   Internal testing flag." This is intentionally not searchable in Settings
   search; you reach it only by scrolling this card.
2. **A first-toggle nudge** - the first time you turn the Lab flag on while your
   current microphone has never been calibrated, a small highlighted banner
   appears reading "Calibrate your microphone for best results" with two
   buttons, **Calibrate now** and **Skip for now**. It is a discoverability
   prompt, not a wall: you can ignore it.
3. **A "Calibrate microphone" row** - always available whenever the Lab flag is
   on (independent of the nudge), with a **Calibrate** button on the right. This
   is how you re-run calibration any time, including after the nudge is gone.

The nudge disappears on its own once the current mic has been calibrated, and
immediately if you click "Skip for now." (If you skip, the nudge can reappear in
a later session until you actually calibrate that mic; calibrating it makes the
nudge stop for good for that mic.)

## How it behaves

### Current status (experimental / Lab flag, OFF by default)

This is an internal, experimental feature. It is hidden behind a Lab flag named
`voiceBargeInLabFlag` that is **off by default**. Nothing about calibration is
visible until you turn that Lab flag on, and barge-in itself does not run for
most users yet.

This honesty matters: in this release (Slice 2.2) calibration is a dogfooding /
internal-testing capability, not a finished setting that ships to everyone. The
general-availability switch that turns barge-in on for all users
(`voiceBargeInEnabled`) arrives in a later release (Slice 2.4). Until then,
calibration is reachable only by enabling the Lab flag.

### The calibration flow (what you actually do)

Clicking **Calibrate now** or **Calibrate** opens a small dialog. The whole test
takes about 15 seconds and runs in two short steps:

1. **Stay quiet.** A 3-2-1 countdown ("Get ready to stay quiet...") leads into
   roughly 5 seconds where you simply say nothing. A microphone icon, a live
   level meter, and a countdown show that Omniscio is listening. This measures your
   room's background noise.
2. **Read one sentence.** A second 3-2-1 countdown ("Now get ready to read out
   loud...") leads into roughly 5 seconds where you read one fixed sentence at a
   normal speaking volume:

   > The quick brown fox jumps over the lazy dog.

   (It is a pangram chosen because it covers a broad range of speech sounds and
   is short enough to read inside the window.) This measures your normal
   speaking voice.

After the two samples, Omniscio shows a brief "Working out your settings..." step,
then a success screen: a green check, "Microphone calibrated," the note
"Barge-in is tuned for this mic. You can recalibrate any time from this screen,"
and a plain-language **Sensitivity: low / medium / high** label (no raw numbers,
which would only confuse). Click **Done** to save.

While the two samples and the countdowns are running, the dialog cannot be
closed (no X, no Escape, no click-outside) so a half-finished measurement can
never be saved. Before you start, and on the success or error screens, you can
close it freely.

### "Skip for now" and the uncalibrated default

You never have to calibrate. If you click **Skip for now** (on the nudge or on a
recoverable error screen), or you simply never open the wizard, Omniscio uses a
sensible built-in default sensitivity and **saves nothing**. That default is
deliberately identical to the single fixed sensitivity barge-in used before
calibration existed, so skipping changes nothing about how barge-in behaves
compared to before this feature. Calibration is an opt-in improvement on top of
a working default, not a prerequisite.

### It is per-microphone

Calibration is stored **per microphone**, keyed to the specific input device.
Each mic you use is calibrated once; the result is remembered and reused every
time that mic is the active one. If you switch microphones (plug in a headset,
move to a different machine, change your default input), the new mic starts
uncalibrated and uses the default until you calibrate it too. There is no global
"recalibrate everything" - you tune each mic when you first use it, and the
saved values persist across restarts.

### Edge cases you might hit

Calibration is honest about failure: if it cannot measure cleanly, it blocks
with a clear message and **saves nothing** (your previous setting, or the
default, stays in effect). It never silently writes a bad result. Each case
below shows a short explanation plus either a "Try again" button, a "Skip for
now" button (use the default), or a "Close" button, as appropriate:

- **No microphone.** "No microphone detected. Connect a mic and try again."
  Nothing is saved.
- **Microphone access blocked.** "Microphone access is blocked. Allow mic access
  in your system settings, then try again." Grant permission, then retry.
- **Too much background noise.** "There is too much background noise to
  calibrate reliably. Move somewhere quieter and try again, or skip for now to
  use the default settings." A reading taken in a noisy room would push the
  threshold so high that your real speech might never register, so a bad
  calibration is worse than the default.
- **Speech too quiet.** "We could not hear clear speech. Read the sentence at a
  normal volume and try again." Too little clear speech makes the measurement
  unreliable.
- **Calibration could not start.** A generic failure (for example the on-device
  speech model failed to load): "Calibration could not start. Please restart Omniscio
  and try again."

In every failure case you can retry or, where it makes sense, skip to keep the
default. You are never left in a broken state, and you can always reopen the
wizard later from the "Calibrate microphone" row.

## For agents

### How it works (code references)

Everything here runs in the renderer; there is no separate background service
and no new IPC channel for calibration. The saved values ride on the existing
settings save path.

- **Saved data.** Calibration results live in a single AppSettings field,
  `vadThresholdsByDeviceId`, a map keyed by the microphone's device id. Each
  entry holds two numbers, `silenceFloor` and `speechThreshold`, both
  voiced-probability values in the range 0 to 1 produced by the speech model.
  An absent entry means "uncalibrated" and resolves to the built-in default at
  read time; "Skip for now" writes nothing. The field defaults to an empty
  object and is validated by the settings Zod schema; saving merges the new
  device entry into the existing map via the normal `SETTINGS_UPDATE` settings
  write (no dedicated calibrate channel).
- **The math.** The pure, dependency-free measurement logic lives in
  `src/renderer/src/features/voice/barge-in-calibration.ts`
  (`computeVadProfile`, `percentile`, `DEFAULT_VAD_PROFILE`, `SAFETY_MARGIN`).
  The silence floor is the 95th percentile of the quiet sample (deliberately not
  the average, so one stray noise spike cannot drag the floor down). The speech
  threshold is the average voiced level during the spoken regions minus a safety
  margin, then clamped so it always sits a minimum distance above the floor and
  leaves headroom at the top. `DEFAULT_VAD_PROFILE.speechThreshold` is `0.75` -
  byte-identical to the fixed sensitivity barge-in used before calibration, so
  an uncalibrated mic behaves exactly as it did before.
- **The wizard UI.** `src/renderer/src/features/voice/BargeInCalibrationWizard.tsx`
  is the 2-step dialog (built on `DialogShell`), lazy-loaded because it pulls in
  the on-device speech model. Each 5-second sample is captured inside its own
  short-lived `AudioContext` (a deliberate discipline; a shared/singleton context
  was tried and reverted because it stopped delivering audio after a few cycles).
- **The nudge.** `src/renderer/src/features/voice/BargeInFirstToggleNudge.tsx`
  is the inline banner; all "should it show" logic lives in its parent so it can
  later be re-pointed at the general-availability toggle with no change.
- **Where it attaches + the live read.** The Lab toggle, nudge, and Calibrate
  row live in
  `src/renderer/src/features/settings/sections/voice/VoiceReportBackSettings.tsx`.
  The live barge-in detector in `src/renderer/src/components/ui/VoiceInput.tsx`
  reads `vadThresholdsByDeviceId[currentDeviceId]?.speechThreshold` (falling back
  to the default) so the calibrated value actually drives the interrupt
  decision; the stored `silenceFloor` is calibration-time only and does not feed
  the live comparison.

### Spec and contract

- Design spec (rationale, algorithm detail, edge-case table, sign-off history):
  [`docs/superpowers/specs/2026-05-29-voice-barge-in-2-2-calibration-design.md`](../superpowers/specs/2026-05-29-voice-barge-in-2-2-calibration-design.md).
- Feature contract (test-locked invariants, safe-change checklist):
  [`.claude/memory/contracts/voice-barge-in-calibration-contract.md`](../../.claude/memory/contracts/voice-barge-in-calibration-contract.md).

## Related

- [voice-report-back.md](voice-report-back.md) - the read-back feature barge-in
  is meant to interrupt; the calibration controls live inside its Settings card.
- [voice-and-tts.md](voice-and-tts.md) - the underlying Voice Control, dictation,
  and TTS stack.

> **Public help-site note:** this feature is still behind a Lab flag, so the
> public help site (`docs.omniscio.com`) is intentionally not updated yet.
> Public coverage lands when barge-in reaches general availability (Slice 2.4).
