A debugging case study · real audio evidence

When AirPods Eat Your Words

The same app, the same person, the same one-word answers — through two microphones. One session worked almost perfectly. One produced garbage. The recordings explain everything.

AirPods · Bluetooth mic 2.2 s captured

Waveform: almost entirely silence, with one very short 0.35 second spike of audio.

He said
“six”
App heard Moonshine
“Dex”
Ground truth Parakeet
“Sex.”
0.35 s of speech survived — a spoken “six” needs about half a second. Shave the onset off “six” and phonetically you get… what Parakeet heard.
OBSBOT Tiny2 · USB mic 2.1 s captured

Waveform: a full, wide word-shaped envelope with a clear beginning and end.

He said
“three”
App heard Moonshine
“Three”
Ground truth Parakeet
“Three.”
Same app, same speaker, same kind of word, a USB microphone. The whole word arrives: onset, vowel, tail. Both models agree effortlessly.

All waveforms on this page are drawn at the same absolute scale. Press play — hear exactly what the app heard.

The setup

A flashcard web app drills mental math. You see a card, you say the answer (“seven”, “twelve”), and an on-device speech model — Moonshine — checks you. A silence gate decides when an answer starts and stops; the browser hands the app whichever microphone is the system default.

On a Mac with AirPods connected, recognition fell apart: 44 seconds, four rounds, zero usable answers. Same app, same person, same drill with a USB desk mic (an OBSBOT Tiny2): nearly flawless.

Bad model? Bad app? Bad luck? The app exports its real recordings in a debug bundle, so every capture could be re-transcribed by an independent, much larger ASR model — NVIDIA Parakeet — acting as the referee. The referee’s verdict: the recognizer wasn’t the problem. The audio itself was.

Exhibit A — the AirPods session

44 ssession
4rounds
0usable answers
4 wordsparakeet salvaged
AirPods · first capture 3.7 s captured

Waveform: bursts of audio slammed flat against the top and bottom of the scale; clipped regions highlighted in red.

He said
“nine”
App heard Moonshine
“13”
Ground truth Parakeet
refused — unintelligible
The first capture after the Bluetooth mic path woke up arrived digitally clipped — peaks flat-topped at 0.0 dBFS (marked red). Moonshine hallucinated “13”; Parakeet declined to transcribe it at all.
AirPods 1.4 s captured

Waveform: a single brief spike of audio, roughly a third of a second, surrounded by silence.

He said
“twelve”
App heard Moonshine
“O”
Ground truth Parakeet
“Of”
He said “twelve” twice; both times only a ~0.3 s tail fragment survived. Two independent models agree the recording literally contains “of” — the “twel-” onset never made it out of the AirPods.

The other rounds went the same way. “Eight”, said twice, came through as 0.24–0.26 s blips — Moonshine guessed “A” and “E”; Parakeet found the clips effectively empty. Run the entire 44-second session through Parakeet and the sum of everything that survived the Bluetooth trip is four faint words:

“Of of eight six”

Timing wasn’t the problem

An obvious suspect: maybe the app just listened at the wrong moments. The debug log rules that out. Here are the seven listen windows against the seven speech bursts the session recording actually contains:

mic open (listen window) speech burst in the recording

Every speech burst landed inside an open window — the silence gate opened on time. The problem is the bursts themselves: 0.2–0.7 s slivers where half-second words should be. The mic was listening; the audio it delivered was fragments.

Exhibit B — the USB mic session

10rounds
6clean & correct
2human slips
0audio failures

Same person, same app, same silence gate — the only change is the microphone. “Five”, “four”, “ten”, “three”, “one”, “seven” all recognized cleanly. When he talked over the drill in full sentences, those transcribed too. And the two “errors”? The referee proved they weren’t the app’s.

OBSBOT Tiny2 · USB 5.1 s captured

Waveform: two complete word envelopes, a short one for uh and a longer one for five, with natural pauses.

He said
“uh… five”
App heard Moonshine
“Five”
Ground truth Parakeet
“Uh five.”
Even with a filler word and a think-pause, the full utterance arrives intact and the answer lands.
OBSBOT Tiny2 · USB 2.1 s captured

Waveform: one complete word envelope with a rising tail.

Card’s answer
11
He said
“thirteen?”
App heard Moonshine
“Thirteen” — scored wrong
Ground truth Parakeet
“Thirteen?”
A “recognition error” that wasn’t: the answer was 11, and he really did say “thirteen” — question mark and all. Same story for the other miss (“uh twenty-one” when the card said 13). With clean audio, the recognizer is right even when the human is wrong.

Why Bluetooth ate the words

When AirPods play audio, they are a high-quality speaker. The moment an app opens their microphone, everything changes: the link drops into the Bluetooth hands-free profile, and the signal runs through the AirPods’ own DSP noise suppression — and then through the browser’s noise suppression and auto gain on top. Two noise reducers in series, both tuned for continuous conversation.

A flashcard drill is that stack’s worst case: short, isolated words surrounded by silence. To a suppressor tuned for speech-in-conversation, a lone “six” popping out of dead air looks like a noise transient. By the time the gate ramps open, the word’s onset is gone — “twelve” becomes “of”, “six” becomes something ruder. And the very first capture after the Bluetooth mic path wakes arrives digitally clipped while the gain stages scramble to converge.

The fix

Use a wired or USB microphone for speech recognition. Keep the AirPods for output only — they are a lovely speaker and a hostile mic.

If you build speech apps

  • Log which mic actually opened. “Default device” is a landmine; the user usually has no idea their AirPods grabbed the input. Show the active mic on screen.
  • Export the real audio. A debug bundle with the actual captures turned “the model is flaky” into “the audio contains the word of” in one listen.
  • Get ground truth from a second model. A stronger independent ASR over the same clips separates “recognizer error” from “destroyed input” — and even caught the human’s own memory slips.