A tiny macOS menubar app that keeps your chosen microphone as the default input.
macOS always switches to whatever was plugged in or paired last. Plug in USB earphones, connect AirPods, pair a Bluetooth headset — every time, your good mic is quietly dropped. Halfway through dictating a sentence, or halfway through a call. There is no setting to stop it. MicPin puts it straight back.
Speakers and headphones are left alone, so you can listen on Bluetooth while a USB or XLR mic keeps the input.
brew install --cask IamSwap/tap/micpinOr download the latest zip from
Releases, unzip it, and drag
MicPin.app into /Applications. It opens straight away, with no security
warning.
Then click the mic in the menubar, pick your microphone, and turn on Open at login. That's it.
Needs macOS 13 or later. Runs on both Apple silicon and Intel.
No permissions needed. MicPin never records anything — it only reads and changes which device is selected — so macOS never asks for microphone access.
| Menu item | |
|---|---|
| Holding … + switch | what it's doing, and the on/off switch for the whole app |
| device list | pick the mic to keep — the blue badge marks it |
| Open at login | start MicPin with your Mac |
| Sound Settings… | opens the Sound pane |
| Quit MicPin | ⌘Q |
Turn the top switch off when you genuinely want a different mic. Your choice is remembered, so switching back on resumes holding the same one.
Each device shows how it's connected — USB, Bluetooth, built-in, iPhone, virtual — which is often clearer than the name.
The menubar icon shows the state: a plain mic while holding one, crossed out when switched off, and marked when your chosen mic isn't plugged in. If it's unplugged MicPin steps aside and lets macOS choose, then takes over again when it's back.
One thing to know: Zoom, Teams and Google Meet remember their own microphone separately from the system one. MicPin can't reach those, so if one is set to the wrong mic, change it once inside that app.
MicPin listens for CoreAudio notifications
(kAudioHardwarePropertyDefaultInputDevice and kAudioHardwarePropertyDevices)
rather than polling, so it costs nothing while idle and reacts in the same run
loop turn as the change — fast enough that an app opening the mic never sees the
wrong device.
macOS sometimes sets the default input a beat after announcing a device change, overwriting what was just set, so each event is re-checked at 0.4s, 1.0s and 2.5s. Waking from sleep re-checks too.
Your choice is stored by CoreAudio UID, falling back to the device name. A USB device's UID includes the port it's plugged into, so moving the receiver to another port changes it — the name is what covers that.
MicPin=/Applications/MicPin.app/Contents/MacOS/MicPin
$MicPin --status
$MicPin --register-login-item
$MicPin --unregister-login-item--status reports everything without launching the app (* is the current
default):
pinned: Wireless Mic Rx
connected: yes
paused: no
default input: Wireless Mic Rx
holding: yes
running: yes
inputs:
iPhone 12 mini Microphone
* Wireless Mic Rx
BlackHole 2ch
Settings live in ~/Library/Preferences/com.chitranu.micpin.plist:
defaults read com.chitranu.micpinbrew uninstall --cask micpin # add --zap to remove settings tooOr by hand:
/Applications/MicPin.app/Contents/MacOS/MicPin --unregister-login-item
pkill -x MicPin
rm -rf /Applications/MicPin.app
defaults delete com.chitranu.micpinTurn off the login item before deleting the app, or an empty entry is left behind in System Settings → Login Items.
./build.sh # → /Applications/MicPin.app
./build.sh ~/Applications/MicPin.app
UNIVERSAL=1 ./build.sh # arm64 + x86_64If you installed with Homebrew, build.sh refuses to overwrite that copy —
building over it would leave Homebrew's records pointing at a version that is no
longer there. Build to another path, brew uninstall --cask micpin, or set
FORCE=1.
One swiftc call over one file. No Xcode project, no
package manager, no dependencies — just the command line tools.
Built and tested on macOS 27 on Apple silicon, and on macOS 15 in CI. The Intel half is built but has never been run on an actual Intel Mac — reports welcome.
A local build only opens cleanly on the machine that built it. Shipping it elsewhere needs Apple signing; see docs/RELEASING.md.
Issues and pull requests welcome — it's one ~470 line file, so it's quick to find
your way around. ./doctor.sh checks your setup and says what's missing.
The icon is drawn in Resources/icon.svg; run
Resources/make-icon.sh after changing it.
The idea comes from this post, which does the opposite — a shell loop that bans one bad device once a second. Banning doesn't scale: block the headset and AirPods still take over, block those and the iPhone mic does. MicPin holds the one you want instead.
