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.

Refreshing discovery

With the daemon running, netaudio discovery refresh requests service discovery again without clearing the current inventory. To query one address directly, use netaudio discovery refresh --address 192.168.1.50. HTTP clients can send POST /discovery/refresh with {} or {"address":"192.168.1.50"}. Replies arrive through the normal discovery and event stream. A successful request does not mean a device answered. Direct mDNS queries do not guarantee discovery across routers. The daemon honors its configured local interface.

Interface selection also binds direct-device control sockets to that interface's IPv4 address. A missing interface or unavailable address is an error; NetAudio does not silently send through another source address. Low-level Python callers can select a source explicitly with CoreClient(..., local_ip="192.0.2.10"). Leaving local_ip unset permits the operating system to select the source. Native callers must use the matching ABI 6 header and library.

Selecting devices and channels

Device commands select 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.

The app's Presets page downloads presets as XML and opens XML files for review before applying them. Select devices from the current inventory view; missing entries must be explicitly skipped. Routing and transmitter names are included by default when saving; audio and single-interface network settings are optional. Loading supports receiver subscriptions, transmitter names, sample rate, encoding, latency, preferred leader and network configuration—not a full device backup. Receiver names, AES67 settings and multicast flows are not restored. Applying may interrupt audio or connectivity; the app stops after an unsuccessful or unverified change, reports partial results, and never automatically rolls back or reboots devices.

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 .

Network configuration

netaudio device config interface reads active and configured settings for both primary and secondary interfaces. Primary settings can be changed with dhcp or static --ip ADDRESS --netmask MASK [--gateway ADDRESS] [--dns ADDRESS]. Secondary settings are currently read-only; secondary writes are rejected.

netaudio device config redundancy reads Dante Redundancy. Add switched, redundant, or split_redundant to request a supported mode. Support is scoped to the observed A32 Switched/Redundant and AD4D Switched/Split/Redundant variants; unrecognized modes and network protocols are unavailable.

The device's Network Config panel provides the same controls and distinguishes active values from configured values awaiting reboot. Changes use fresh preflight and configured-value readback. An uncertain result is reported without automatically retrying or rebooting. Network changes can interrupt connectivity; reboot the device separately when ready.

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.

Use Search to find a device or view. On phones, Routing presents receiving channels as touch-sized controls with source selection in a sheet. Larger screens offer the crosspoint grid or channel list; grid headers show subscription indicators even when a connection is off-screen. The navigation sidebar can be collapsed to make room for the grid. Diagnostic details and advanced actions remain secondary to routing controls.

The client uses Preact, Tailwind CSS, daisyUI components, and Lucide icons. Assets are bundled: end users need neither Node nor an external CDN. For UI development, run npm ci and npm run build:webapp after editing components or styles. Edit CSS sources in scripts/webapp/, not the generated app.css. Run npm run test:webapp for model/render tests and npx playwright test for fixture-backed phone and desktop interactions (install test browsers with npx playwright install chromium webkit).

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.1

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.1
File Size Uploaded
netaudio-0.3.1.tar.gz 683.4 kB Details

Built distributions (wheels)

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

Total release size: 7.0 MB

Release files / netaudio-0.3.1.tar.gz

Download URL netaudio-0.3.1.tar.gz
Size 683.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6e9f1fcafdd44c1552a9b608ba0fc31169a0f8f7d4b19203173d73badffb6e88
BLAKE2b-256 checksum
How to use checksums
8b0d71e485b7f9c7dee39663e48b5f40a790592ea0571fd6f05a9741916c4616
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 7, 2026.

Transparency log

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

Download URL netaudio-0.3.1-py3-none-win_amd64.whl
Size 1.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
cb61e951e57afa487f165baca05a9382df3e55626572653d16d622925cf2742b
BLAKE2b-256 checksum
How to use checksums
0372d528c00961b216dbe94aaae433a99e23f0a428ac6cf223a903cc5c05c0ec
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 7, 2026.

Transparency log

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

Download URL netaudio-0.3.1-py3-none-manylinux_2_28_x86_64.whl
Size 1.3 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
ac51d81ba57868c00e8e1ae64f24ac2bbab2abbd1ce469c8b5c228de492630fc
BLAKE2b-256 checksum
How to use checksums
004a0c99234eca43738151a4d69d8462d577d054a6a5ddf0be1dd72be4c0ae16
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 7, 2026.

Transparency log

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

Download URL netaudio-0.3.1-py3-none-manylinux_2_28_aarch64.whl
Size 1.3 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
f2e1e9f18613ff8d5edaf779957a72d6c2e155f679e3b0674da191b906cc1149
BLAKE2b-256 checksum
How to use checksums
221d04f8daa57799eb5980557d8c78ee7d1fe26c8560ea222ec6c2a23a0a64b0
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 7, 2026.

Transparency log

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

Download URL netaudio-0.3.1-py3-none-macosx_11_0_x86_64.whl
Size 1.3 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
7332815ed604b592cf3ceaba7618b596b371a992d2da6d290834d166005bbec1
BLAKE2b-256 checksum
How to use checksums
3c6cda59d99182ccf03bb1421b0c80822fb40e1ea81683e68a6d384bbfe76cf1
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 7, 2026.

Transparency log

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

Download URL netaudio-0.3.1-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
126ebf25ab0d1e840eb6a30c654d98dd0135781fb7835ddb3b308a008c0b30aa
BLAKE2b-256 checksum
How to use checksums
67df060f5e2a4dcb8b88c3e6eb0278a1801876b8833707bf30258e04a5eeec8c
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 7, 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

This release

0.3.1 This release

6 release files

0.3.0

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