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

FlagDefaultDescription
--device-map, -mAuto-detectPath to device map JSON file
--device, -dAuto-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

FlagDefaultDescription
--host0.0.0.0Bind address for all servers
--port, -p4710TCP port for Mixer Engine (text protocol)
--helper-port4720TCP port for Mixer Helper (UBJSON protocol)
--ws-port4721WebSocket port for UA Connect
--no-helper(disabled)Disable the Mixer Helper TCP:4720 server
--no-ws(disabled)Disable the WebSocket server

Service discovery

FlagDefaultDescription
--no-bonjour(disabled)Disable Bonjour/mDNS service advertisement
--name, -nHostnameBonjour service name (displayed in ConsoleLink device list)

Metering

FlagDefaultDescription
--alsa-deviceAuto-detectALSA capture device for software metering (e.g., hw:2,0)

Logging

FlagDefaultDescription
--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

FlagLevelOutput
(none)INFOConnections, hardware events, errors
-vDEBUGAll of the above plus control changes, state tree operations
-v -tDEBUG + traceAll 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:

  1. The pyalsaaudio Python package
  2. The kernel driver loaded with audio transport running
  3. 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/:

ModelDevice typeDevice map
Apollo x40x1Fdevice_map_apollo_x4.json
Apollo x8p0x20device_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

Previous
Protocol Reference