Mixer Daemon
Daemon Configuration
The mixer daemon is configured entirely through command-line flags. There is no configuration file.
Command-line reference
python3 ua_mixer_daemon.py [OPTIONS]
Device and hardware
| Flag | Default | Description |
|---|---|---|
--device-map, -m | Auto-detect | Path to device map JSON file |
--device, -d | Auto-detect /dev/ua_apollo* | Device node path for hardware I/O |
--no-hardware | (disabled) | Software-only mode — no hardware writes, no device node required |
--safe-mode | (disabled) | Block unmapped DSP writes for safety |
Network binding
| Flag | Default | Description |
|---|---|---|
--host | 0.0.0.0 | Bind address for all servers |
--port, -p | 4710 | TCP port for Mixer Engine (text protocol) |
--helper-port | 4720 | TCP port for Mixer Helper (UBJSON protocol) |
--ws-port | 4721 | WebSocket port for UA Connect |
--no-helper | (disabled) | Disable the Mixer Helper TCP:4720 server |
--no-ws | (disabled) | Disable the WebSocket server |
Service discovery
| Flag | Default | Description |
|---|---|---|
--no-bonjour | (disabled) | Disable Bonjour/mDNS service advertisement |
--name, -n | Hostname | Bonjour service name (displayed in ConsoleLink device list) |
Metering
| Flag | Default | Description |
|---|---|---|
--alsa-device | Auto-detect | ALSA capture device for software metering (e.g., hw:2,0) |
Logging
| Flag | Default | Description |
|---|---|---|
--verbose, -v | (disabled) | Enable debug-level logging |
--trace, -t | (disabled) | Log every protocol message sent and received |
Network binding
By default the daemon binds to 0.0.0.0 (all interfaces). To restrict to localhost:
python3 ua_mixer_daemon.py --host 127.0.0.1
To use non-standard ports:
python3 ua_mixer_daemon.py --port 4711 --helper-port 4721 --ws-port 4723
Hardware backend
Auto-detection
When --device is not specified, the daemon scans for /dev/ua_apollo* device nodes. The first match is used.
Software-only mode
python3 ua_mixer_daemon.py --no-hardware
In this mode:
- No device node is opened
- The full state tree is loaded from the device map
- Clients can connect and interact with controls
- SET commands update the state tree but do not reach hardware
- Metering returns silence (-77 dBFS)
This is useful for:
- Protocol development and testing
- UI development without hardware
- Running the daemon on a development machine (e.g., laptop without Thunderbolt)
Safe mode
python3 ua_mixer_daemon.py --safe-mode
Safe mode blocks DSP writes that don't have a verified mapping. This prevents accidental writes to unknown registers during development.
Bonjour / mDNS discovery
The daemon advertises _uamixer._tcp. via Bonjour/mDNS when the zeroconf Python package is installed. This allows ConsoleLink (iOS/iPad) to auto-discover the daemon on the local network.
# Install the optional dependency
pip install zeroconf
The service name defaults to the machine hostname. Override it:
python3 ua_mixer_daemon.py --name "Studio Apollo"
To disable advertisement entirely:
python3 ua_mixer_daemon.py --no-bonjour
Logging
Levels
| Flag | Level | Output |
|---|---|---|
| (none) | INFO | Connections, hardware events, errors |
-v | DEBUG | All of the above plus control changes, state tree operations |
-v -t | DEBUG + trace | All of the above plus every protocol message (raw bytes) |
Format
Log lines include timestamp, logger name, level, and message:
14:32:05 ua-mixer-daemon INFO TCP:4710 (Mixer Engine, text) listening on [('0.0.0.0', 4710)]
14:32:05 ua-mixer-daemon INFO Device: Apollo x4 (11244 controls)
14:32:10 ua-mixer-daemon INFO Connected: <MixerClient client-1 :4710 text ('192.168.1.50', 49832)>
ALSA metering
The daemon computes audio meters in software by reading PCM samples from the ALSA capture device. This requires:
- The
pyalsaaudioPython package - The kernel driver loaded with audio transport running
- A valid ALSA capture device
Auto-detection scans /proc/asound/cards for the ua_apollo driver. Override with:
python3 ua_mixer_daemon.py --alsa-device hw:2,0
If ALSA metering is unavailable, meters report silence (-77 dBFS) for all channels.
Device maps
The daemon loads a device map JSON file that defines the complete state tree structure. This file describes all controls, their types, ranges, and default values.
The device map is a capture of the state tree from a working UA Mixer Engine. Different Apollo models expose different controls (channel counts, preamps, routing), so each model needs its own map. Available maps live in mixer-engine/device_maps/:
| Model | Device type | Device map |
|---|---|---|
| Apollo x4 | 0x1F | device_map_apollo_x4.json |
| Apollo x8p | 0x20 | device_map_apollo_x8p.json |
Automatic selection
When --device-map is not given, the daemon reads the attached device's device_type from the driver (UA_IOCTL_GET_DEVICE_INFO), looks it up against the descriptors in devices/apollo-*.json, and loads the matching device_map_apollo_<model>.json. If the device type is unknown, no map exists for it yet, or the daemon runs with --no-hardware, it falls back to the Apollo x4 map.
To force a specific map (e.g. when developing without matching hardware):
python3 ua_mixer_daemon.py --device-map device_maps/device_map_apollo_x8p.json
Adding a map for a new model
Capture the model's control tree from a working UA Mixer Engine (see Device Capture (macOS)), then flatten it into the daemon's format:
python3 tools/tree_to_device_map.py capture.json -o device_maps/device_map_apollo_<model>.json
Add a matching devices/apollo-<model>.json descriptor with the correct device_type and model, and the daemon will select the new map automatically.
Persistent state
The daemon automatically saves modified control values to mixer-engine/state/<device_map_name>.state.json. On restart, saved values are restored.
This preserves:
- Preamp gain, 48V, pad, low-cut, phase settings
- Monitor volume, mute, dim, source selection
- Fader positions and pan values
- Headphone routing and volume
Further reading
- Daemon Setup — getting started with the daemon
- Protocol Reference — protocol wire formats