Skip to main content

Description

This is a python program for controlling Dante network audio devices (and possibly others in the future). It's early, so expect things to break or switches to change. Use this at your own risk; it's not ready for anything other than a test environment and could make the devices behave unexpectedly. The first goal is to do everything that Dante Controller can do that would be useful for control of the devices from a command-line interface or within scripts.

For more information, check out the gearspace discussion.

Features

Current

  • AVIO input/output gain control
  • Add/remove subscriptions
  • Browser interface served by the daemon
  • CLI
  • Cross-platform foreground daemon plus installable boot service
  • Device lock/unlock through the native Rust protocol core
  • Display active subscriptions, Rx and Tx channels, devices names and addresses, subscription status
  • JSON output
  • Set device latency, sample rate, encoding
  • Set/reset channel names, device names
  • mDNS device discovery

Installation

To install from PyPI:

uv tool install netaudio

Or with pip/pipx:

pip install netaudio

To install from a clone (requires Python 3.9+ and a Rust toolchain, since the native core is compiled from source):

uv sync
uv run netaudio

Arch Linux

To install from AUR, build the package with aur/netaudio.

Usage

Run netaudio if installed globally, or uv run netaudio from a clone.

Subscription status

Subscription JSON keeps the raw 16-bit subscription status.code, separate rx_channel_status.code, and any additional status_message warnings. A connected subscription can carry warnings; it does not prove audio delivery. Managed responses retain ddm_status, ddm_status_message and ddm_summary separately. Their semantic state comes from the shared Rust definitions, while severity follows the managed summary. A null managed status remains unknown, with its available message, summary and channel metadata preserved. GraphQL errors remain full objects in daemon status and leave inventory degraded; unrelated API failures are not treated as successful queries.

Numeric definitions and identifier classification live in netaudio-core. The Python client requires native ABI 5 for these functions. Source checkouts must rebuild the native core after this update. Subscription definitions no longer come from the optional local label file.

The status observation fixture records the evidence scope: a synthetic 0x0000–0x00ff sweep at receiver health 0x0101, observed through one DDM deployment on 2026-09-05. observed_summary is populated for recognized values in the observed receiver contexts. interpretation identifies observed pairs, unverified receiver contexts, unknown numeric values, or code 1 requiring receiver context. Code 1 resolves to DYNAMIC at health 0x0101 and UNRESOLVED at health 0x0000; other contexts remain unresolved. Higher values keep all bits and remain unknown. The sweep does not establish a complete receiver-health precedence rule or naturally occurring hardware faults.

Selecting devices and channels

Every command selects devices with the same global filters: -n/--name (glob), -s/--server-name (glob), -m/--mac, and --host (IP address). Commands that act on one device report device not found or multiple devices matched when the filters do not narrow to exactly one. -h is an alias for --help everywhere.

netaudio -n avio-usb-1 device show
netaudio -n avio-usb-1 flow list
netaudio --host 192.168.1.50 lock set 1234

Channels are written as tx:1, rx:1, tx:NAME, rx:NAME, or a bare channel name. A bare name searches both directions and is rejected when it matches both a transmitter and a receiver channel.

netaudio -n avio-usb-1 channel name rx:1
netaudio -n avio-usb-1 channel name rx:1 vocal-in
netaudio -n avio-usb-1 channel gain tx:1 3
netaudio subscription add --tx tx:1@stagebox --rx rx:1@avio-usb-1
netaudio subscription add --tx 1@stagebox --rx 1@avio-usb-1
netaudio subscription remove --rx rx:1@avio-usb-1

With --tx and --rx the direction is implied, so 1@DEVICE is accepted as shorthand for tx:1@DEVICE and rx:1@DEVICE respectively.

Presets are stored in the preset directory (presets/ next to config.toml, or preset_directory in config.toml); preset save NAME, preset show NAME, and preset load NAME use it unless given an explicit .xml path, and preset list shows what is saved there.

netaudio -n 'avio-*' preset save stage
netaudio preset list
netaudio config show

Latency configuration and monitoring

Read the complete device-wide latency state for one device:

netaudio -n avio-aes3-1 device config latency

The output distinguishes active, configured, and default values, the device-reported minimum/maximum range, and the latency options produced by filtering the standard option set through that range. JSON, YAML, and XML output include both milliseconds and the original nanosecond values. An active or configured value remains visible when it is inside the reported range but absent from the ordinary option list, or even outside the reported range.

Set latency in milliseconds and require matching active readback:

netaudio -n avio-aes3-1 device config latency 2

netaudio -n DEVICE device show keeps three different layers separate: device-wide configuration, each receiver flow's latency setting and frames per packet, and receiver-flow current/average/peak measurements. Flow settings and live measurements are not treated as aliases of the device-wide value.

Channel and flow status JSON

Channel-status reads follow every continuation page and return one merged record list with page_capacity, page_count, and total_record_count. Channel records carry channel_number, media_type, and media_local_channel_id; flow records carry global_flow_id, media_type, media_local_flow_id, and transmitter_channel_ids_by_slot.

Modern ARC channel-status media type codes are 3 for audio, 4 for video, and 5 for ancillary data. The ancillary label is a causal black-box finding: Dante Controller classified devices publishing code 5 with its ancillary capability filter. The finding establishes Controller's interpretation of the field; the tested devices were synthetic, so it does not establish which physical device families publish ancillary channels.

For the packet-observed frontends, an exact mDNS arcp_vers of 2.8.15 selects protocol 0x280f; the existing 2.8.9 frontend uses 0x2809. Unrecognized or missing versions fail closed instead of selecting a presumed protocol. Enrolled DDM devices use the separately observed 0x2809 managed transport contract.

Dante Domain Manager devices

When the daemon's merged inventory marks a device as enrolled, ordinary device commands automatically use DDM. Unenrolled devices continue to use their local ARC/settings services. A device that has both a local address and enrolled DDM metadata still uses DDM, so commands do not accidentally bypass domain policy.

The guided login discovers DDM servers over mDNS when --url is omitted, authenticates, reads the visible domains, prompts when there is more than one choice, and saves the first context as the default:

netaudio ddm login --username operator
netaudio ddm context list
netaudio ddm context use studio-main

An existing Managed API credential can be used without a password prompt:

netaudio ddm login --url https://ddm.example/graphql --server-profile studio \
  --credential-file ~/.config/netaudio/studio.credential

Each context binds one server profile, one credential file, and one domain ID. The resulting config.toml uses this shape:

[ddm]
default_context = "studio-main"

[ddm.servers.studio]
url = "https://ddm.example/graphql"
credential_file = "credentials/studio.credential"

[ddm.contexts.studio-main]
server = "studio"
domain_id = "0123456789abcdef0123456789abcdef"
domain_name = "Main Studio"

Use netaudio --context CONTEXT ... or NETAUDIO_CONTEXT for a one-command override. The daemon polls every configured server, while each managed device record retains its originating server profile, context, domain ID, and device ID. This keeps devices distinct when separate sites reuse names or IP address ranges and ensures credentials are sent only to the configured server.

The URL is used as configured; there are no separate certificate, hostname, or internal-port settings. Low-level Managed API access is grouped by intent and resource so it does not overwhelm the ordinary DDM commands:

netaudio ddm api read domains
netaudio ddm api write device set-name --device-id DEVICE_ID --name NAME
netaudio ddm api schema

Use the normal device commands for ordinary control. ddm api write exposes schema-derived administrative mutations and should be used deliberately.

The documented GraphQL API supplies inventory and device-name, preferred-leader, and subscription changes. Capture-derived, version-scoped Controller-service support supplies Identify and native ARC/settings requests. The normal CLI paths currently cover device/channel/flow status, device and channel names, latency, sample rate, encoding, gain, AES67, clock state/subdomain, network interface status/configuration, subscriptions, receiver port ranges, and the observed modern flow inventory/delete form. Reads were exercised against enrolled AVIO input and output adapters; mutation paths retain their normal readback and capability checks.

Operations without an established managed request and completion model fail closed instead of trying the unmanaged device address. These currently include lock/unlock, reboot and factory reset, capability/log exports, modern multicast flow creation, channel-name reset, and the 0x2729 transmitter-channel-capability query. Sample-rate pull-up is implemented through the managed settings envelope, but the tested AVIO family did not publish a response and is reported as unavailable.

Run tests:

uv lock --check
uv run --python 3.9 --no-project python -m compileall -q packages/netaudio/src/netaudio
cargo test --manifest-path packages/netaudio-core/Cargo.toml
uv run pytest -q

Lint and format:

uv run ruff check .
uv run ruff format .

Browser interface

The daemon serves a browser interface from its own HTTP port, so no extra process or build step is involved. Start the daemon and open the address it reports:

netaudio daemon start
netaudio daemon web --open

The page is a single-page application backed entirely by the daemon HTTP API and its /events stream, so device, subscription, metering, and Shure state update live without polling. It uses real browser history routing, so every view, device, and device tab is a linkable address. It follows Dante Controller's layout and vocabulary so it is immediately familiar:

  • Routing: the full network subscription matrix, Dante receivers down and Dante transmitters across, with devices collapsed by default. Click a device cell to subscribe one-to-one, expand a device to work channel by channel, and filter either axis by device or channel name. The matrix is canvas-rendered and stays responsive across tens of thousands of cells; pending changes, subscribed, warning, and error states are drawn as in Dante Controller.
  • Device info, Clock status, Network status: the network-view tables with the columns Dante Controller operators expect. Every table lets columns be hidden, shown, and dragged into a new order, remembered per table in the browser.
  • Device view: Receive, Transmit, Status, Latency, Device config, Network config, AES67 config, Transmit flows, Device lock, and Domain tabs. Receivers subscribe through a searchable picker; channels can be renamed and gains set where the device supports it.
  • Metering: live meters for every declared channel, drawn on canvas with peak hold. Both metering protocols are surfaced: detailed per-channel levels streamed after an explicit start, and the passive signal-presence records a device already broadcasts.
  • Flows: transmit flow inventory per device, with multicast flow creation and deletion.
  • Domains: Dante Domain Manager status, domains, and the managed inventory.
  • Shure: discovered receivers, channel state, transmitter and battery detail, and live meter values.
  • Events: the daemon event stream, held in memory only and excluding meter samples.

Press Ctrl+K (Command+K on macOS) to jump to any device or view. Defaults show what an operator needs; every field the daemon knows remains available behind column menus and expandable detail sections, never as raw JSON.

The client is Preact with signals, vendored into the package alongside the rest of the assets, so the interface loads with no build step, no bundler, and no network access beyond the daemon itself. make test-webapp renders every view and device tab against captured device records under Node, so template and formatting regressions are caught before deployment.

Device mutations use the same verified-write paths as the CLI, so a control that reports success has been read back from the device. The daemon binds every interface; restrict access at the network layer if that is not wanted.

Documentation

Metadata

Release files for netaudio 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for netaudio 0.3.0
File Size Uploaded
netaudio-0.3.0.tar.gz 616.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for netaudio 0.3.0
File
netaudio-0.3.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
netaudio-0.3.0-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
netaudio-0.3.0-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
netaudio-0.3.0-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
netaudio-0.3.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 6.5 MB

Release files / netaudio-0.3.0.tar.gz

Download URL netaudio-0.3.0.tar.gz
Size 616.4 kB
Tags Source
SHA-256 checksum
How to use checksums
dd0497328cb1b7c3b0ce12589951fe732febeb50654bb9010631fddc3778e300
BLAKE2b-256 checksum
How to use checksums
6a8ffc4c635d2baf01744731a8b8cdac2183c2b00a17f1405f188efd3f3017dd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netaudio-0.3.0-py3-none-win_amd64.whl

Download URL netaudio-0.3.0-py3-none-win_amd64.whl
Size 1.1 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
38997f497577dc57c8e8c190b0811933a639c593774eebbb244a492dec234c2c
BLAKE2b-256 checksum
How to use checksums
373bb1274c2831c13383316c7021c27ce01e71b25e57c57cf963697dae7d63d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netaudio-0.3.0-py3-none-manylinux_2_28_x86_64.whl

Download URL netaudio-0.3.0-py3-none-manylinux_2_28_x86_64.whl
Size 1.2 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
2db4546efb5cca318333bcfc39b1aadfe8a5c39df0ed565d3416d182d3bd22c3
BLAKE2b-256 checksum
How to use checksums
e478656ff70a7bc44ffaa002f4bc94f0aa77e28695421b5e66e4dddb9b2ce48f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netaudio-0.3.0-py3-none-manylinux_2_28_aarch64.whl

Download URL netaudio-0.3.0-py3-none-manylinux_2_28_aarch64.whl
Size 1.2 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
32f82e8518f1bbf76100f1ec0e8e51e797b341ab40799fe5c7c39fc6c7ba7cd8
BLAKE2b-256 checksum
How to use checksums
e4c86a8931c423cfbfe013c70a4e72f23d5a69d4e4fa767128265cbea160da12
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netaudio-0.3.0-py3-none-macosx_11_0_x86_64.whl

Download URL netaudio-0.3.0-py3-none-macosx_11_0_x86_64.whl
Size 1.2 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
f81abd05e3ecdcb2bc79d248bf740bc36a3e93beb549806362a21aec96f1c528
BLAKE2b-256 checksum
How to use checksums
7b880d49b276fabf64e11e329f1008d33ecfc5e66b502365effc7f45d19f2e05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netaudio-0.3.0-py3-none-macosx_11_0_arm64.whl

Download URL netaudio-0.3.0-py3-none-macosx_11_0_arm64.whl
Size 1.2 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
dc0c1f1710cb1bc8566635e05814bf1c87eb51aef2e430972f5d4893fe9973c3
BLAKE2b-256 checksum
How to use checksums
95ffae4f50fac9ccb8694c28aadbe314e38c00e16149ecd2fa5d8443d6669741
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.14

6 release files

0.3.13

6 release files

0.3.12

6 release files

0.3.9

6 release files

0.3.7

6 release files

0.3.6

6 release files

0.3.5

6 release files

0.3.4

6 release files

0.3.3

6 release files

0.3.1

6 release files

This release

0.3.0 This release

6 release files

0.2.5

5 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page