Read this in: English (this page) · Português · Español
nomicswitch is a small macOS daemon that keeps the default audio input on the MacBook's built-in microphone and keeps the input volume at 100%. When macOS, an app or your AirPods move the input somewhere else, it moves it back in under 100 ms. Between events it sleeps, so idle CPU use is zero.
"AirPods sound bad on Mac", "my Mac keeps switching the microphone to AirPods", "MacBook keeps using my iPhone as a mic". If you searched for any of those, this is the fix that sticks.
When AirPods connect, macOS switches the default input to the AirPods microphone. Two things go wrong:
- The AirPods mic is much worse than the microphone array built into a modern MacBook.
- In most conferencing apps, what you hear gets worse too. As soon as the Bluetooth mic is in use, AirPods drop to a low-bandwidth headset mode. Apple describes the two modes in support.apple.com/102217 and suggests closing the app that uses the mic.
Zoom, Teams, browsers and macOS itself keep flipping the input back. Fixing it by hand every time gets old fast.
Didn't Apple fix this? Partly. On macOS 15 or newer with recent AirPods Pro 2 or AirPods 4 firmware, some apps (Safari, FaceTime, games) can keep 48 kHz in headset mode. Reports from 2026 still show Teams and Chrome degrading, and none of that changes the first point: the AirPods mic itself. Pinning the built-in mic takes care of both.
- Keeps the default input device on the built-in microphone, or on any device you choose.
- Keeps the input volume at 100%, or at any level you choose, or leaves it alone.
- Listens for three CoreAudio events: input device switched, input volume changed, device connected or removed.
- Uses 0.0% CPU while idle and about 14 MB of RAM. It only wakes up when macOS announces a change.
- Leaves your AirPods connected for output. Music and calls keep playing through them; only the microphone is protected.
macOS has no API to lock the default input device. Any app, and the system itself, can change it at any time. Every tool in this space works the same way, including paid ones like ToothFairy and SoundSource: listen for the change event and switch back at once. The window is a few milliseconds, which is too short for an app to record through the AirPods mic.
curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/install.sh | bashThis downloads the prebuilt universal binary (Intel and Apple Silicon, built by GitHub Actions from this repository), checks its SHA-256, installs it to ~/.local/bin and loads a LaunchAgent. You do not need Xcode or Homebrew. install.sh is about 100 lines if you want to read it first.
To pin a different mic or a different volume from the start:
NOMICSWITCH_ARGS="--uid <UID> --volume 80" bash -c "$(curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/install.sh)"brew install marks-zyz/tap/nomicswitch
brew services start nomicswitchYou need the Xcode Command Line Tools (xcode-select --install).
git clone https://github.com/marks-zyz/NoMicSwitch.git
cd NoMicSwitch
make install # builds, installs to ~/.local/bin, loads a LaunchAgentAll three start the daemon right away and bring it back after a reboot.
| Action | One-line or source install | Homebrew |
|---|---|---|
| Start (and enable at login) | the install command above | brew services start nomicswitch |
| Pause (to use another mic for a while) | launchctl bootout gui/$(id -u)/com.nomicswitch |
brew services stop nomicswitch |
| Start again | launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nomicswitch.plist |
brew services start nomicswitch |
| Remove | curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/uninstall.sh | bash |
brew services stop nomicswitch && brew uninstall nomicswitch |
| Watch the log | tail -f ~/Library/Logs/nomicswitch.log |
tail -f $(brew --prefix)/var/log/nomicswitch.log |
nomicswitch [options] run the guard (meant for launchd / brew services)
nomicswitch --list list input-capable devices with their UIDs, then exit
-u, --uid <UID> device UID to pin (default: BuiltInMicrophoneDevice)
-v, --volume <0-100> input volume percentage to lock (default: 100)
--no-volume pin the device only, leave the volume alone
--version print version and exit
-h, --help show help
To pin a USB microphone instead of the built-in one, run nomicswitch --list, copy its UID, and add --uid <UID> to the LaunchAgent plist (or to the brew services plist). The daemon finds devices by UID because UIDs are stable and the same in every language, while macOS translates device names.
The daemon registers three CoreAudio property listeners:
| Listener | Fires when | Response |
|---|---|---|
kAudioHardwarePropertyDefaultInputDevice |
anything switches the default input | switch it back |
kAudioDevicePropertyVolumeScalar (input scope) |
anything lowers the input volume | raise it back |
kAudioHardwarePropertyDevices |
a device connects or disconnects | re-check everything, re-attach volume listeners |
Between events the process is asleep. On macOS 26 I measured 0.0% idle CPU, reaction under 100 ms and about 14 MB of RAM. There are no runtime dependencies: no Homebrew packages, no scripting bridges, only CoreAudio.
Design note: the first version was a shell script that polled every two seconds with SwitchAudioSource and osascript. It worked, but every tick spawned two processes and cost about 0.1 s of CPU, forever. The Swift daemon replaced it so the cost between events is exactly zero.
Tested on macOS 26 (Tahoe) 26.6.2 on Apple Silicon. It should work on macOS 12 Monterey or newer, Intel or Apple Silicon, since it builds from source. The build uses kAudioObjectPropertyElementMain from the macOS 12 SDK; on older SDKs, replace it with kAudioObjectPropertyElementMaster and it should compile. Building needs the Swift compiler, which comes with the Xcode Command Line Tools. Running needs nothing.
- AirPods, or any Bluetooth headset, connecting and grabbing the mic.
- The iPhone "Continuity" microphone showing up as an input.
- Apps such as Zoom, Teams or a browser switching the input device, or turning the input volume down through auto-gain.
- Devices reconnecting after sleep, reboots (LaunchAgent with KeepAlive), and daemon crashes (launchd restarts it).
- It reverts the change within milliseconds; it cannot prevent it, because macOS offers no API for that (see above).
- While the daemon runs you cannot pick another microphone by hand. Pause the service first (one command, table above).
- If you pin a removable device such as a USB mic and unplug it, the daemon waits quietly and pins it again the moment it returns.
- There is no
.pkgor.app. Without a paid Apple Developer ID, Gatekeeper blocks unsigned downloads on recent macOS, which would be worse than a one-line installer. The binary is ad-hoc signed, built in public CI, and its checksum is checked before install.
Other projects that solve the same problem (star counts from September 2026):
- milgra/airpodssoundqualityfixer (536★): AirPods Sound Quality Fixer, the classic menu bar app.
- Gaulomatic/AirPodsSanity (467★): menu bar app shipped as a DMG.
- roaldnefs/airpods (44★): fork lineage of the same idea.
- yigitkonur/cli-fix-my-mic (28★): headless CoreAudio daemon with a curl installer, the closest relative; no volume lock.
- hbertsch/macos-microphone-input-volume-locker (17★): shell script polling every 0.5 s that locks input volume only.
- Aayush9029/Crisp, adrbn/podfidelity, LockAudio: newer menu bar apps.
- Paid and closed source: ToothFairy, SoundSource, AirBuddy (Audio Input Lock since August 2026), SoundAnchor and CrystalClear Sound on the App Store.
NoMicSwitch puts device pinning and input volume locking in one event-driven process, works with any device by UID, runs under brew services, installs with one dependency-free line, is public domain, and has this README in English, Portuguese and Spanish.
Unlicense: public domain. Do whatever you want with it, no attribution required. Icon glyphs are from Phosphor Icons (MIT).
nomicswitch é um daemon pequeno para macOS que mantém a entrada de áudio padrão no microfone embutido do MacBook e o volume de entrada em 100%. Quando o macOS, um app ou seus AirPods movem a entrada para outro lugar, ele devolve em menos de 100 ms. Entre um evento e outro ele dorme, então o uso de CPU em repouso é zero.
Quando os AirPods conectam, o macOS troca a entrada padrão para o microfone deles. Duas coisas dão errado: (1) o microfone dos AirPods é muito pior que o conjunto de microfones embutidos de um MacBook moderno; (2) na maioria dos apps de chamada, o que você ouve também piora, porque ao ativar o microfone Bluetooth os AirPods caem para um modo headset de baixa banda (a Apple descreve os dois modos em support.apple.com/102217). Firmwares recentes dos AirPods Pro 2 e AirPods 4 no macOS 15 ou mais novo amenizam o segundo problema em alguns apps, mas não o primeiro.
Ele não bloqueia a troca (o macOS não oferece API para isso, e até os apps pagos como ToothFairy e SoundSource funcionam do mesmo jeito): ele escuta o evento e reverte em milissegundos.
Uma linha, sem dependências (recomendado). Baixa o binário universal pré-compilado (Intel e Apple Silicon, gerado pelo GitHub Actions a partir deste repositório), confere o SHA-256, instala em ~/.local/bin e carrega um LaunchAgent. Não precisa de Xcode nem de Homebrew:
curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/install.sh | bashVia Homebrew:
brew install marks-zyz/tap/nomicswitch
brew services start nomicswitchDo código-fonte (precisa do Xcode Command Line Tools, xcode-select --install):
git clone https://github.com/marks-zyz/NoMicSwitch.git
cd NoMicSwitch
make installNos três casos ele inicia na hora e volta sozinho depois de reiniciar o Mac.
| Ação | Instalação de uma linha ou do fonte | Homebrew |
|---|---|---|
| Iniciar (e ativar no login) | o comando de instalação acima | brew services start nomicswitch |
| Pausar (para usar outro mic por um tempo) | launchctl bootout gui/$(id -u)/com.nomicswitch |
brew services stop nomicswitch |
| Iniciar de novo | launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nomicswitch.plist |
brew services start nomicswitch |
| Remover | curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/uninstall.sh | bash |
brew services stop nomicswitch && brew uninstall nomicswitch |
| Acompanhar o log | tail -f ~/Library/Logs/nomicswitch.log |
tail -f $(brew --prefix)/var/log/nomicswitch.log |
nomicswitch --list lista os dispositivos de entrada com seus UIDs. --uid <UID> trava outro dispositivo (um mic USB, por exemplo), --volume <0-100> escolhe o volume travado (padrão 100) e --no-volume trava só o dispositivo e deixa o volume em paz. O daemon acha os dispositivos pelo UID porque o UID é estável e igual em qualquer idioma, enquanto o macOS traduz os nomes.
Um binário Swift com três listeners do CoreAudio: troca do dispositivo de entrada, mudança do volume de entrada, e conexão ou remoção de dispositivos. Entre eventos o processo dorme. No macOS 26 medi 0,0% de CPU em repouso, reação abaixo de 100 ms e cerca de 14 MB de RAM. Não há dependências em runtime. A primeira versão era um script de shell verificando a cada dois segundos; funcionava, mas cada verificação criava dois processos, e o daemon substituiu isso.
Testado no macOS 26 (Tahoe) 26.6.2 em Apple Silicon. Deve funcionar do macOS 12 em diante, Intel ou Apple Silicon. Enquanto o daemon roda você não consegue escolher outro microfone à mão: pause o serviço antes (um comando, tabela acima). Não existe .pkg nem .app porque, sem um Apple Developer ID pago, o Gatekeeper bloqueia downloads não assinados no macOS recente; o binário é assinado ad-hoc, compilado em CI público, e o checksum é conferido antes de instalar. Alternativas: veja a seção "Alternatives" acima.
Unlicense: domínio público. Faça o que quiser, sem exigência de atribuição. Os glifos do ícone são do Phosphor Icons (MIT).
nomicswitch es un pequeño daemon para macOS que mantiene la entrada de audio predeterminada en el micrófono integrado del MacBook y el volumen de entrada al 100%. Cuando macOS, una app o tus AirPods mueven la entrada a otro sitio, la devuelve en menos de 100 ms. Entre eventos duerme, así que el uso de CPU en reposo es cero.
Cuando los AirPods se conectan, macOS cambia la entrada predeterminada a su micrófono. Dos cosas salen mal: (1) el micrófono de los AirPods es mucho peor que el conjunto de micrófonos integrados de un MacBook moderno; (2) en la mayoría de las apps de videollamada, lo que escuchas también empeora, porque al activarse el micrófono Bluetooth los AirPods pasan a un modo auricular de bajo ancho de banda (Apple describe los dos modos en support.apple.com/102217). Los firmwares recientes de AirPods Pro 2 y AirPods 4 en macOS 15 o posterior mitigan el segundo problema en algunas apps, pero no el primero.
No bloquea el cambio (macOS no ofrece ninguna API para eso, e incluso las apps de pago como ToothFairy y SoundSource funcionan igual): escucha el evento y lo revierte en milisegundos.
Una línea, sin dependencias (recomendado). Descarga el binario universal precompilado (Intel y Apple Silicon, generado por GitHub Actions a partir de este repositorio), verifica el SHA-256, lo instala en ~/.local/bin y carga un LaunchAgent. No necesitas Xcode ni Homebrew:
curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/install.sh | bashCon Homebrew:
brew install marks-zyz/tap/nomicswitch
brew services start nomicswitchDesde el código fuente (necesita Xcode Command Line Tools, xcode-select --install):
git clone https://github.com/marks-zyz/NoMicSwitch.git
cd NoMicSwitch
make installEn los tres casos arranca de inmediato y vuelve solo tras reiniciar el Mac.
| Acción | Instalación de una línea o desde fuente | Homebrew |
|---|---|---|
| Iniciar (y activar al iniciar sesión) | el comando de instalación de arriba | brew services start nomicswitch |
| Pausar (para usar otro micro un rato) | launchctl bootout gui/$(id -u)/com.nomicswitch |
brew services stop nomicswitch |
| Iniciar de nuevo | launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nomicswitch.plist |
brew services start nomicswitch |
| Eliminar | curl -fsSL https://raw.githubusercontent.com/marks-zyz/NoMicSwitch/main/uninstall.sh | bash |
brew services stop nomicswitch && brew uninstall nomicswitch |
| Ver el log | tail -f ~/Library/Logs/nomicswitch.log |
tail -f $(brew --prefix)/var/log/nomicswitch.log |
nomicswitch --list lista los dispositivos de entrada con sus UIDs. --uid <UID> fija otro dispositivo (un micro USB, por ejemplo), --volume <0-100> elige el volumen bloqueado (100 por defecto) y --no-volume fija solo el dispositivo y no toca el volumen. El daemon busca los dispositivos por UID porque el UID es estable e igual en cualquier idioma, mientras que macOS traduce los nombres.
Un binario Swift con tres listeners de CoreAudio: cambio del dispositivo de entrada, cambio del volumen de entrada, y conexión o desconexión de dispositivos. Entre eventos el proceso duerme. En macOS 26 medí 0,0% de CPU en reposo, reacción por debajo de 100 ms y unos 14 MB de RAM. No hay dependencias en runtime. La primera versión era un script de shell que comprobaba cada dos segundos; funcionaba, pero cada comprobación creaba dos procesos, y el daemon lo sustituyó.
Probado en macOS 26 (Tahoe) 26.6.2 en Apple Silicon. Debería funcionar desde macOS 12 en adelante, Intel o Apple Silicon. Mientras el daemon corre no puedes elegir otro micrófono a mano: pausa el servicio antes (un comando, tabla de arriba). No hay .pkg ni .app porque, sin un Apple Developer ID de pago, Gatekeeper bloquea las descargas sin firmar en macOS reciente; el binario está firmado ad-hoc, compilado en CI público, y el checksum se verifica antes de instalar. Alternativas: consulta la sección "Alternatives" más arriba.
Unlicense: dominio público. Haz lo que quieras, sin atribución obligatoria. Los glifos del icono son de Phosphor Icons (MIT).
