Open-source tooling to turn any mic, any phone, or any DJ gear into one stream → BILLO, reachable wherever Billy is.
Both servers start automatically at login and restart if they crash.
| What | Open this |
|---|---|
| Listen to the live hub (MacBook mic) | http://100.77.111.113:8123/ (Tailscale, from anywhere) or http://<mac-wifi-ip>:8123/ |
| Phone as a mic | https://100.77.111.113:8200/?id=phone1 (Tailscale) or https://<mac-wifi-ip>:8200/?id=phone1 (same Wi-Fi) |
| Health check | ./billo-audio.sh status (prints the exact URLs) ·
./billo-audio.sh doctor (also checks parked hardware) |
Phone steps: join the same Wi-Fi as the Mac (or turn on the Tailscale
app) → open the phone URL → tap through the “not private / certificate”
warning once (it’s this Mac’s own certificate) → Start
Mic → allow the microphone. Give each phone its own
?id= name. Each press of Start makes a new file in
phone-mic/recordings/ (iPhone saves .m4a,
Android .webm). Hotel/venue Wi-Fi often blocks
phone-to-laptop traffic — if the page won’t load, use the Tailscale URL.
After a reboot the hub takes about a minute to start hearing the
mic.
| Path | What it does | Status |
|---|---|---|
hub.py |
Capture + MIX one or more macOS audio devices → record WAV and/or serve a live MP3 stream over HTTP | ✅ verified (incl. multi-input mixing) |
phone-mic/ |
Turn old phones into wireless mics (browser → server over WiFi/HTTPS) | ✅ server verified |
sdr-mic.sh |
Receive analog UHF wireless mics with an RTL-SDR dongle | ⏳ ready (needs dongle) |
billo-audio-hub.plist +
phone-mic.plist |
launchd always-on services (hub :8123 + phone-mic :8200) | ✅ installed + running |
~/roadmics/ |
Headless recorder + RØDE Wireless GO setup (physical mics → interface) | ✅ built |
./billo-audio.sh start # hub + phone-mic (default mic)
./billo-audio.sh start "BlackHole 2ch" "MacBook Pro Microphone" # MIX multiple sources
./billo-audio.sh status # health of both
./billo-audio.sh stop # stop everythingpython3 hub.py listpython3 hub.py record "MacBook Pro Microphone" --secs 30 # 30s WAV
python3 hub.py record "MacBook Pro Microphone" "BlackHole 2ch" --secs 30 # MIX two sourcespython3 hub.py stream "MacBook Pro Microphone" --port 8123
python3 hub.py stream "MacBook Pro Microphone" "BlackHole 2ch" --port 8123 # two mics, one stream
python3 hub.py stream recordings/foo.wav --port 8123 # loop-stream a recorded file (no hardware)
python3 hub.py record recordings/a.wav recordings/b.wav --secs 5 # MIX two recorded files
# Browser/player: http://<this-mac-ip>:8123/
# Over Tailscale: http://100.77.111.113:8123/ (any BILLO machine or Billy's phone)
# Raw stream: http://<ip>:8123/streamZero install: open https://vdo.ninja on the phone (“Add your camera/mic”) and on this Mac, play the phone’s view link out to BlackHole 2ch → the hub picks it up.
Self-hosted copy (static site, ~500 MB clone — use Wi-Fi):
./vdo-ninja-setup.sh install # once (git clone of steveseguin/vdo.ninja)
./vdo-ninja-setup.sh start # serves https://<mac-ip>:8443/Peers still meet through VDO.Ninja’s public handshake server, so internet is required.
Already running as a service on :8200 (see “Use it now”). Manual run:
cd phone-mic && python3 server.py 8200 --https
# On each phone: open https://<mac-ip>:8200/?id=phone1 (trust the cert once)
# Audio lands in phone-mic/recordings/<id>_<time>.webm (Android) or .m4a (iPhone)Bluetooth mic (HFP) is narrowband ~8 kHz mono, one device at a time, and macOS doesn’t expose a clean BT-mic input. Prefer WiFi (above) or WebRTC. Android has a BT fallback via WO Mic (https://wolicheng.com/womic); iOS has no good BT-mic path. Use BT only as a last resort for a single low-fi mic.
# rtl-sdr software is already installed; just plug in the dongle
./sdr-mic.sh 570.125 # tune to the mic's frequency in MHzWithout the dongle the script stops with a plain “PARKED: plug in the RTL-SDR dongle” message.
./install-service.sh # (re)install + start hub AND phone-mic as launchd agents
./install-service.sh uninstall # stop + remove both (back to manual ./billo-audio.sh start)Logs: .run/service-hub.log,
.run/service-phone-mic.log. To stream different inputs
always-on, edit the device names in billo-audio-hub.plist
and re-run ./install-service.sh.
BlackHole (already installed) is the virtual mixer. Route ANY audio into it and the hub captures it as ONE live stream — this is how phones (via a player / VDO.Ninja), SDR output, a DAW, DJ gear, or any app’s audio all converge.
./route-to-blackhole.sh recordings/foo.wav & # loop a file into the bus
python3 hub.py stream "BlackHole 2ch" --port 8123 # capture the bus -> one streamProven: sox -> BlackHole -> hub -> stream (tone
measured at mean -6.5 dB).
100.77.111.113).
The stream at http://100.77.111.113:8123/stream is
reachable by any fleet machine and Billy’s phone over the Tailscale
mesh.