Skip to content

CLI Reference

Score2 edited this page Aug 15, 2026 · 1 revision

CLI reference

AudioHub ships a command-line binary alongside the app. Most of it duplicates what the interface does — but a few things have no interface at all in 1.0.0, and those are the reason this page exists.

Everything under audiohub ctl talks to the running audio service over the same local channel the interface uses, so a change made here shows up in the window immediately and survives a restart. Everything outside ctl is a self- contained probe that runs in its own process and does not consult the service. Mixing the two is the most common mistake; see Commands that bypass the service.


Where the binary is

Neither installer puts it on your PATH. Call it by full path, or add the directory yourself.

macOS /Applications/AudioHub.app/Contents/MacOS/audiohub
Windows C:\Program Files\AudioHub\audiohub.exe

The examples below say audiohub for readability.

Every command accepts a global --json, which prints exactly one JSON object on stdout. Human-readable progress always goes to stderr, so --json output is safe to pipe.

Some of the human-readable output is in Chinese. Several ctl explanations — the transport summaries, the warning when advertising fails, the refusal when --dir is missing — are hardcoded and do not follow the interface language. The --json payload is unaffected.

Exit codes

Code Meaning
0 success
2 the service was reached and refused the request
3 could not reach or authenticate to the service — usually "it is not running"
4 anything else, including bad arguments

2 and 3 are worth telling apart in a script: 3 means try again after starting AudioHub, 2 means the request itself was wrong.


What has no interface in 1.0.0

These are the only reasons to reach for the CLI in normal use.

Capability Command
Dial policy — stop one side of a one-way tunnel from dialling ctl peer-transport --tier … --dial-policy …
Change the control port away from 47810 audiohub daemon --port N
Drop a peer's connection and stop reconnecting to it ctl disconnect
Choose your own pairing PIN instead of a generated one ctl pair-enable --pin
Read or set the volume of a named output device audiohub volume --device

--dial-policy is the important one. It is the answer to the situation Transport Tiers describes — a tunnel that only carries connections one way, where the side that cannot originate keeps dialling forever and looks exactly like a machine that is switched off.


audiohub ctl

Status and inspection

audiohub ctl status
audiohub ctl peers
audiohub ctl sessions
audiohub ctl settings

status prints the service's name, fingerprint, control port, uptime and protocol version, then the output devices, detected audio bridges and system-audio capture backends it can see. With --json it carries considerably more, including the latency servo's per-stream state:

audiohub ctl status --json | jq '.latency_guard.servo.by_stream'

peers lists every paired peer with its fingerprint, last known address, online state, and — when it is retrying — how long until the next attempt.

sessions lists live media sessions with the counters the Stats tab shows. One field is only here: for each session, transport is the connection method the bytes really travel on, as opposed to the one that was requested. A ? means the service did not report it and must not be read as Direct (UDP).

settings with no flags is a plain read — it cannot write anything by accident.

Peers and pairing

audiohub ctl pair-enable [--pin 123456] [--ttl 120]
audiohub ctl pair-disable
audiohub ctl pair --addr <host[:port]> --pin <pin>
audiohub ctl unpair --peer <fingerprint>
audiohub ctl alias --peer <fingerprint> [--alias "<name>"]
audiohub ctl discover [--secs 5]
audiohub ctl connect --peer <fingerprint> [--addr <ip[:port]>]
audiohub ctl disconnect --peer <fingerprint>

Notes that are not obvious from the flags:

  • --peer takes any unique prefix of a fingerprint, not the whole thing. An ambiguous prefix is refused rather than guessed.
  • pair-enable prints the PIN in a box on stderr. Without --pin it generates one; the interface always generates one, so choosing your own is CLI-only. The default lifetime is 120 seconds, matching the interface.
  • pair --addr defaults to port 47810 when you omit it. Pairing does not bring a control connection up — see Discovery and Pairing for what that means for Mode B devices.
  • alias with no --alias clears the alias and falls back to the peer's own computer name.
  • disconnect is not the same as unpair: it drops the control channel and stops the reconnect loop, until something asks for that peer again. The interface has no equivalent.
  • unpair removes the trust record, its sessions and its virtual devices here. What reaches the other machine is conditional — Unpairing has the detail.

peer-transport

The per-peer transport settings. This one command covers two different writes, and they cannot be combined.

Read — no flags beyond --peer:

audiohub ctl peer-transport --peer <fingerprint>

Prints the latency and quality target for each direction, the connection method for the peer as a whole, and — only when this machine is the one being used — the two values the peer has pushed onto it.

Write a per-direction target — needs --dir:

audiohub ctl peer-transport --peer <fp> --dir recv --latency 200
audiohub ctl peer-transport --peer <fp> --dir send --quality pcm48k24
Flag Values
--dir recv (this machine receives from the peer) or send (this machine sends to it)
--latency auto, or one of 0 10 20 30 50 75 100 150 200 300 500 750 1000 — milliseconds, end to end, network included
--quality auto, or pcm48k32f pcm48k24 pcm48k16 pcm32k16 pcm24k16 pcm16k16

--dir has no default and the command refuses to guess one. The two directions are enforced on different machines, so picking a default would silently change the half you did not mean. --latency 0 is what the interface calls Lowest; see the latency setting is a target, not a limit before setting a large number. The opus64 / opus128 / opus256 stops are listed by the service but refused — this build cannot deliver them. So are the older depth-less ids such as pcm48k: they are rejected, not translated.

Write the connection method--tier, optionally with the two flags that must accompany it:

audiohub ctl peer-transport --peer <fp> --tier tier2 --dial-policy inbound_only
audiohub ctl peer-transport --peer <fp> --tier tier2 --endpoint ws://tunnel.example:8080/audiohub
audiohub ctl peer-transport --peer <fp> --tier auto --endpoint ""
Flag Values Interface equivalent
--tier auto, tier0 (Direct (UDP)), tier1 (TCP relay), tier2 (Single-link mux) Connection method on the peer's detail page
--dial-policy both (default), outbound_only, inbound_only none
--endpoint ws://host[:port][/path], or "" to clear Tunnel address on the peer's detail page

--dial-policy and --endpoint both require --tier on the same command line. That is deliberate: they are one decision about how the peer is reached, and every such write drops the control connection. Applying them separately would put the peer through two reconnections and, in between, leave it in a combination nobody asked for.

For the same reason, --tier may not be given together with --latency or --quality. Those are two writes with two failure modes; the command refuses rather than reporting one result for both.

After a tier write the command tells you which of three things happened:

Reported Meaning
reconnecting the connection was dropped and renegotiates on the new setting in about a second
awaiting peer dropped, but this machine is not the dialling side — it takes effect when the peer reconnects
written stored; it applies at the next connection

A peer left on inbound_only sits in a third state — not offline, but expected to arrive. The 1.0.0 interface does not distinguish that from offline, so that peer's card reads as disconnected between sessions even though the setup is correct.

Settings

ctl settings reaches every machine-wide setting the service accepts — the same twelve the interface writes. Settings Reference explains what each one does; this is only the flag spelling.

Flag Values
--mode share, a, b
--name this machine's display name; --name= clears the override and follows the computer name again
--remove-virtual-on-disconnect true / false
--mark-offline-devices true / false
--mode-a-volume-sync true / false
--mode-a-mute-local true / false
--discovery-announce true / falseAdvertise on LAN
--airplay-enabled true / false
--airplay-name advertised receiver name; empty follows the machine name
--airplay-password empty removes it
--autostart true / falseStart at login
--native-locale zh-CN / en-US — the language the operating system sees in device names; the local app normally keeps this in step

Two behaviours worth knowing:

  • Passing --discovery-announce true when it is already true retries a failed advertisement. If the service wants to advertise but could not, the command says so instead of reporting success.
  • --airplay-password puts a password in your shell history and, while the command runs, in a process list other local users may be able to read. Prefer the interface on a shared machine.

Settings that are not here, because they are not machine-wide: latency, quality and connection method are per peer and live in peer-transport. Interface language and appearance are per-client and are not service settings at all.

Sessions and volume

These exist mainly for diagnostics — in normal use the interface (Mode A) or your operating system's device picker (Mode B) opens sessions for you.

audiohub ctl open --peer <fp> --kind mic|spk [--source tone|mic|sysaudio|halspk] [...]
audiohub ctl close --id <n>
audiohub ctl set-volume --id <n> --scalar 0.5 [--mute|--unmute]

--kind mic consumes the peer's microphone; --kind spk sends audio to the peer's output. Useful modifiers: --monitor also plays a received mic stream locally, --bridge "<device name>" renders it into a named audio bridge, --backend <id> picks a system-audio capture backend (only with --source sysaudio), and --volume-sync lets set-volume drive the peer's real output.

open is refused outright in two of the three modes unless you pass --override: in Share mode, because that machine serves peers rather than using them, and in Mode B, because sessions there are supposed to follow the system's device selection — which is the whole point of Mode B. Only Mode A accepts it without the flag. --override cannot defeat the other machine's half of the same rule.

Service control

audiohub ctl shutdown
audiohub ctl simulate-device-change --kind input|output

shutdown is what the tray item Stop Audio & Quit does. simulate-device-change forces the default-device rebuild path without touching real devices; it has no interface and exists for testing that path.


audiohub daemon

Runs the audio service in the foreground. The app normally starts it for you — run it by hand when you need a non-default port or want its log on your terminal.

audiohub daemon [--port 47810] [--ipc-port 0] [--announce | --no-announce] [--secs 0]
Flag Effect
--port N control (TCP) and media (UDP) port. The only way to move it off 47810 — the interface shows it read-only
--ipc-port N the loopback interface channel; 0 picks a free one and records it in ipc.json
--announce / --no-announce force mDNS advertising on or off for this run without changing the stored setting
--secs N stop after N seconds; 0 runs until killed

With neither --announce nor --no-announce, the service follows the stored setting — which is what every shipping path does, including the login item.

If the port is busy the service fails to start; it does not fall back. See If 47810 is already taken.


audiohub volume

Reads, and optionally sets, an output device's volume on this machine. No service involved.

audiohub volume
audiohub volume --device "AudioHub – Studio Mac" --set 0.4
audiohub volume --mute

Without --device it acts on the system default output. With it, it reaches a named device's own control — which is the only way to read or drive a virtual device's volume without first making it the system default. The output includes adjustable, which is false on devices whose volume cannot be driven at all; Volume explains what AudioHub does in that case.


Commands that bypass the service

Everything below runs in its own process. It loads the identity and the trust file from disk itself, opens its own sockets, and the running service never learns about it.

Command What it really does
audiohub id prints/creates this machine's identity
audiohub peers reads the trust file directly
audiohub unpair --fingerprint <fp> | --all edits the trust file behind the service's back
audiohub discover its own mDNS browse
audiohub announce its own mDNS advertisement
audiohub pair --to <ip[:port]> --pin <pin> its own pairing handshake
audiohub pair-listen, verify, verify-listen the other halves of those exchanges
audiohub probe … audio and network measurement: devices, tone, capture, loopback, sysaudio, tx, rx, echo, echo-server, selftest, winvad

Use the ctl versions. audiohub unpair will not remove virtual devices, will not tell the other machine, and leaves the running service holding a pairing that no longer exists on disk. audiohub pair has no listener of its own, so it advertises a guessed port back to the peer unless you pass --listen-port <the service's real port>. The names are similar; the behaviour is not.

The probe family is a measurement toolkit, not a user feature. Two of its commands are worth knowing anyway:

audiohub probe sysaudio --list      # capture backends and detected audio bridges
audiohub probe devices              # every audio device with its UID

Environment

Variable Effect
AUDIOHUB_CONFIG_DIR overrides the configuration directory for identity, trust file, settings and ipc.json. Both the CLI and the service honour it — set it for one and not the other and they will not find each other
AUDIOHUB_NAME overrides this machine's display name. While it is set, ctl settings --name is refused

Related

Clone this wiki locally