Package Exports
- airmic
- airmic/server.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (airmic) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
AirMic
Turn your phone into a wireless microphone that types speech directly into your desktop. Your phone handles speech recognition, and the text is typed into whatever window is focused — no drivers, no Bluetooth, no pairing headaches.
Phone (browser) → WebSocket → Desktop (types into focused window)How it works
- Start AirMic on your desktop — a TUI appears with a QR code
- Scan the QR code with your phone's camera
- Tap the mic button and start talking
- Text appears in your focused desktop window in real-time
Works over your local WiFi network, or over the internet via a relay server.
Platform support
| Component | Linux | macOS | Windows |
|---|---|---|---|
| Phone UI (browser) | ✅ | ✅ | ✅ |
| Relay server | ✅ | ✅ | ✅ |
| Desktop agent (local typing) | ✅ X11 | ⚠️ Partial | ⚠️ Partial |
The phone UI runs in any modern browser (Chrome, Safari, Edge). The relay server is pure Node.js and runs anywhere.
The desktop agent currently uses xdotool for keystroke injection, which is Linux/X11 native. On macOS and Windows, you can run AirMic in clipboard mode (clipboardMode: true in config.json) — speech text is copied to your clipboard and pasted into the focused window. Full native keystroke support for macOS (AppleScript) and Windows (PowerShell/SendKeys) is planned.
Requirements
Linux
- X11 desktop (Wayland not yet supported)
- Node.js 18+
xdotoolandxclip
sudo apt install xdotool xclipmacOS
- Node.js 18+
pbcopy(pre-installed on macOS)- Works in clipboard mode out of the box
brew install nodeWindows
- Node.js 18+
- Works in clipboard mode out of the box
- PowerShell (pre-installed) handles clipboard operations
# Install Node.js from https://nodejs.org or via winget:
winget install OpenJS.NodeJS.LTSQuick start
# Clone the repo
git clone https://github.com/code-pumpkin/airmic.git
cd airmic
# Install dependencies
npm install
# Generate a self-signed TLS cert (required — browsers need HTTPS for mic access)
bash gen-cert.sh
# Start AirMic
node server.jsA TUI launches with a QR code. Scan it with your phone, accept the self-signed cert warning once, and you're live.
Headless mode (daemon)
Run as a background daemon (useful for SSH sessions):
airmic headless on # Start daemon
airmic headless off # Stop daemon
airmic status # Check status
airmic approve <PIN> # Approve new deviceOr run inline without the TUI:
npx airmicPhone UI
The phone gets a clean, mobile-optimized web app with:
- Large mic button — tap to start/stop, or use push-to-talk (Hold) mode
- Live transcript display with interim results
- Pause, Clipboard, AI, and Hold toggle buttons
- Language selector (13 languages)
- History of sent phrases with resend
No app install needed — it's just a web page served over HTTPS.
Connection modes
Local network (same WiFi)
The default. Your phone connects directly to your desktop over your local network. Lowest latency, no internet required.
Relay server (internet)
For when your phone isn't on the same network as your desktop (mobile data, different WiFi, etc.). A relay server on a VPS brokers the WebSocket connection.
AirMic Cloud is included as a default relay. To use it, press Ctrl+K → Relay Servers → select AirMic Cloud.
The phone will automatically try a direct local connection first and fall back to the relay if your desktop isn't reachable locally.
TUI keyboard shortcuts
| Key | Action |
|---|---|
Ctrl+K |
Command palette (access all actions) |
Ctrl+P |
Pause / resume |
Ctrl+E |
Relay server manager |
Ctrl+A |
AI settings |
Ctrl+R |
Add word replacement |
Ctrl+D |
Delete word replacement |
Ctrl+L |
Clear log |
Ctrl+Q |
Quit |
AI summarize
Spoken text is typed immediately, then silently replaced with an AI-cleaned version in the background. Useful for turning rambling speech into clean prose.
Supports OpenAI, Anthropic, and Google AI.
Setup
- Add your API key to
.env:
cp .env.example .env
# Edit .env and add your key:
# AIRMIC_AI_KEY=sk-your-key-hereOr configure interactively: Ctrl+A in the TUI.
- Toggle AI on/off from the TUI (
Ctrl+A→Ctrl+T) or from the phone's AI button.
| Provider | Default model |
|---|---|
| OpenAI | gpt-4o-mini |
| Anthropic | claude-3-5-haiku-latest |
| gemini-1.5-flash |
You can override the model and system prompt in AI settings.
Word replacements
Auto-replace words or phrases as they're typed. Useful for fixing consistent misrecognitions or expanding abbreviations.
Ctrl+Rto add a replacement (e.g., "gonna" → "going to")Ctrl+Dto remove one
Replacements are saved to config.json and apply to all future transcriptions.
Self-hosting a relay server
1. Provision a VPS
Any VPS with Node.js 18+ works. AWS Lightsail $3.50/month (512MB) is plenty. Open port 4001 in the firewall.
2. Deploy
# On your VPS (as root)
git clone <this-repo> /tmp/wmic
cd /tmp/wmic/relay
bash deploy.shdeploy.sh installs Node, copies files to /opt/wireless-mic-relay, generates a self-signed cert, and starts a systemd service.
3. Set a relay secret (recommended)
Edit /etc/systemd/system/wireless-mic-relay.service:
Environment=RELAY_SECRET=your-strong-secret-heresystemctl daemon-reload && systemctl restart wireless-mic-relay4. Use a real TLS cert (recommended)
apt install certbot
certbot certonly --standalone -d yourdomain.comIn the service file:
Environment=CERT_DIR=/etc/letsencrypt/live/yourdomain.com5. Connect your desktop
Press Ctrl+K → Relay Servers → Add custom server. Enter your relay URL (wss://yourdomain.com:4001) and secret.
Config reference
Config is stored in config.json (auto-generated on first run).
| Key | Default | Description |
|---|---|---|
port |
4000 |
Local HTTPS port |
language |
en-US |
Speech recognition language (BCP 47) |
clipboardMode |
false |
Paste via clipboard instead of xdotool typing |
wordReplacements |
{} |
Auto-replace map (e.g., {"gonna": "going to"}) |
relayUrl |
"" |
Active relay server URL |
relaySecret |
"" |
Must match RELAY_SECRET on the relay |
relayServers |
[...] |
Saved relay server list |
aiEnabled |
false |
Enable AI text cleanup |
aiProvider |
openai |
openai, anthropic, or google |
aiModel |
"" |
Blank = provider default |
aiPrompt |
(built-in) | System prompt for AI rewriting |
API keys are stored in .env (not config.json). See .env.example.
Environment variables
| Variable | Description |
|---|---|
AIRMIC_AI_KEY |
AI provider API key |
Set these in .env or export them in your shell.
Security
- All connections are TLS-encrypted (HTTPS + WSS)
- Phone access requires a random URL token (shared via QR code)
- New devices must be approved via 6-digit PIN confirmation on the desktop
- Returning devices are remembered via cryptographic device tokens
- Per-socket message rate limiting (30 msg/sec)
- HTTP rate limiting (60 req/min per IP)
- Security headers: HSTS, CSP, X-Frame-Options, nosniff, Referrer-Policy
- Control characters stripped before typing
- API keys stored in
.env, not in config - Sessions auto-expire after 90 days
Project structure
├── server.js # Desktop app — TUI, WebSocket server, xdotool integration
├── public/
│ └── index.html # Phone web UI (single self-contained file)
├── relay/
│ ├── relay.js # Relay server for internet access
│ ├── deploy.sh # VPS deployment script
│ ├── wireless-mic-relay.service # systemd service file
│ └── public/
│ └── index.html # Phone UI copy served by relay
├── gen-cert.sh # Self-signed cert generator
├── config.example.json # Example configuration
├── .env.example # Example environment variables
└── package.jsonTroubleshooting
Phone can't connect / cert error Accept the self-signed certificate warning in your phone's browser. On some phones you need to visit the HTTPS URL directly first, accept the warning, then reload.
"Speech recognition not supported" Use Chrome or Safari. Firefox doesn't support the Web Speech API.
Text not appearing on desktop (Linux)
Make sure xdotool is installed and you're running X11 (not Wayland). Check that the target window is focused.
Text not appearing on desktop (macOS/Windows)
Make sure clipboardMode is set to true in config.json. AirMic will copy text to your clipboard and paste it into the focused window.
Android "pyramid" effect (repeated text) This is handled automatically — AirMic uses single-shot recognition mode on Android with auto-restart.
Relay connection fails
Check that port 4001 is open on the VPS, the relay secret matches, and the service is running (systemctl status wireless-mic-relay).
License
MIT