A Python reference implementation of an NMOS Node with Matrox NMOS extensions.
An NMOS Node implementation — covering the AMWA NMOS Interface Specifications (IS-04, IS-05, IS-10, IS-11), a curated set of AMWA Best Current Practices, and selected VSF Technical Recommendations — written in typed Python on top of asyncio + aiohttp. It is intended as both a working device and a teaching reference.
The security surface — TLS (with cipher and curve restriction), OAuth 2.0 Bearer-token validation with JWKS lifecycle, and CRL handling — is implemented and exercised by the bundled test suite.
- NMOS Interface Specifications — Discovery (IS-04), Connection (IS-05), Authorization (IS-10), and Stream Compatibility (IS-11; excludes the
Input/Outputresources). - Capabilities-driven controller — the embedded NMOS Controller consumes BCP-004-01/-02 Sender / Receiver capabilities and drives IS-11 stream-compatibility negotiation (active + supported constraint sets, parameter constraints) through the Matrox Capability Constraint Framework (CCF) in
caps/. Senders and Receivers are reconfigured at runtime against what the connected peers actually advertise — the matching surface is the device's declared capabilities, not prebaked SDP templates. IS-11Input/Outputresources are not implemented (see the Matrox NMOS extensions table below). - Hierarchical mux capabilities — transport / container layering for MPEG2-TS, NDI, SRT, and RTSP, plus the AM824 / AES3 audio mux container. IS-11 carries through the mux hierarchy: the Controller negotiates and configures each sub-flow / sub-stream (video, audio, data) independently against the connected peer's per-layer constraints. Audio sub-flows can be PCM, AAC, or AM824; video sub-flows can be raw, JPEG XS, H.264, or H.265 — all selected by capability matching.
- BCP-008 status reporting over IS-04 (no IS-12 / MS-05-02 dependency) — Sender / Receiver status flows through IS-04 registration. The status appears as monitor resources in the registry; any controller subscribing to the registry's
/x-nmos/query/v1.3/subscriptions/WebSocket sees changes asynchronously as grain messages. Any registry-connected controller can observe status without implementing the NC control-protocol stack. - VSF Technical Recommendations — TR-10-13 (privacy-encrypted transport) and TR-10-14 (USB-over-IP and capability sets).
- Three security configurations, each with launch scripts and test coverage:
- Config A — Mutual TLS, no OAuth 2.0
- Config B — OAuth 2.0 with server TLS
- Config C — Mutual TLS + OAuth 2.0
- TLS — cipher whitelist enforcement, ECDH curve restriction, configurable CRL (GCRL) for revocation handling.
- Typed JSON serializers — generated from the NMOS JSON schemas, so the wire format and the in-memory types stay in sync.
- Typed Python —
mypy --strictclean across thenmos/package (tests excluded). - Asyncio throughout — aiohttp HTTP / WebSocket servers,
DispatchGroup-based task lifecycles, errgroup-style cancellation. - Test suite — 2 000+ tests across unit, integration, and end-to-end paths.
This implementation follows the Matrox "One Model to Rule them All" design, formalised in the NMOS-MatroxOnly corpus. The model presents two stream topologies — that NMOS controllers typically handle through separate code paths — under a single configuration surface:
- Group of independent streams — multiple Senders, one per essence (e.g., one audio Sender + one video Sender + one data Sender).
- Multiplexed stream — one Sender carrying multiple sub-streams (e.g., a single MPEG2-TS mux containing video + audio + data).
From the user's point of view the configuration model is the same: both shapes expose video 0, audio 0, audio 1, … and are configured through IS-11 active constraints in the same way. The Controller abstracts the underlying transport / streaming implementation. The constraint-set metadata on each Sender / Receiver — format, layer, and layer_compatibility_groups (alongside the natural-grouping role / role-index from BCP-002-01) — are what let one code path drive both topologies.
In practice this means the same IS-11 negotiation handles MPEG2-TS, RTSP, NDI, USB-over-IP muxes, AM824 audio mux containers, and independent RTP / SRT senders for the same set of essences. The Controller asks "what's the user's intent for video 0 and audio 0?" once; the per-Sender/Receiver hints decide whether that becomes a mux-sub-stream configuration or a coordinated independent-Sender configuration.
Three pre-configured launch scripts cover the three security configurations.
# Prerequisites: Python 3.12 or newer, plus the dependencies in pyproject.toml
pip install -e .[dev]
# Config A — mTLS without OAuth 2.0
./start-node1-noauth2.sh
# Config B — OAuth 2.0 with server TLS
./start-node1-nomtls.sh
# Config C — mTLS + OAuth 2.0
./start-node1.shEach launch script binds the Node on a hostname that matches the configured server-certificate's SAN. Resolve that hostname to 127.0.0.1 in /etc/hosts for local testing. Positional arguments to the launch script set the AS host/port and registry host/port — see --help in nmos_node.py for the full flag surface.
The Node ships a built-in NMOS Controller on --nodeControlPort (HTTP Basic auth) once you set --controllerAdminPassword.
| Component | Config A (start-node1-noauth2.sh) |
Config B (start-node1-nomtls.sh) |
Config C (start-node1.sh) |
|---|---|---|---|
| NMOS Registry (IS-04) | optional | optional | optional |
| OAuth 2.0 Authorization Server (IS-10) | not used | required | required |
| TLS server certificate | required | required | required |
| TLS client certificate | required (mTLS) | not used | required (mTLS) |
Notes on the dependencies:
-
NMOS Registry: a single Node runs standalone with no registry — pass
--rdsHost ""(the launch-script default already wires this when no$3 $4are supplied). In this mode the embedded NMOS Controller seeds its cache once at startup from the local Node's resources, so the Controller UI shows the initial set of senders / receivers / sources / flows. The cache is not live-updated afterwards — IS-05 activations, IS-11 reconfigurations, BCP-008 status changes that happen at run-time will not appear in the Controller UI until you point the Node at a real registry. To exercise multi-Node negotiation AND see live updates, use any IS-04-compliant registry (e.g. nmos-cpp's registry, or another instance of this implementation) by passing$3 $4positional args on the launch script. -
OAuth 2.0 Authorization Server: required for Configs B and C — the Node fetches JWKS from the AS, validates Bearer tokens against the published public keys, and enforces the IS-10 claim semantics (
aud,scope,x-nmos-*). Any IS-10-compliant AS works; a Keycloak realm is a common choice for production deployments. Pass the AS host / port to the launch script as$1 $2. Config A does not contact an AS. -
TLS material: each launch script references a server cert / key (and, for mTLS, a client cert / key) and a trust root. Vendors substitute their own PKI by editing the scripts or by running
nmos_node.pydirectly with--nodeCertificate/--nodeKey/--nodeTrustedRootCA.
The Node also supports a no-TLS dev mode that sits outside Configs A/B/C — plain HTTP on every surface, no OAuth, no client-cert verification. It is not certifiable under any security spec (under TR-10-SEC §9.1-1 a device shall not claim compliance while so configured), but is useful for quick connectivity experiments without PKI setup.
Run nmos_node.py directly with the disable flags:
python3 nmos_node.py \
--nodeDisableTLS --rdsDisableTLS --oauth2DisableTLS \
--nodeAddr 127.0.0.1 --nodePort 5050 \
--nodeControlPort 8080 --controllerAdminPassword adminThe full flag surface is documented by --help.
python3 -m pytest -q nmos/ sdp/Runs the full test suite (~3 minutes, 2 000+ tests). See the Tests section for per-module invocation and marker breakdown.
The Node ships with a built-in streaming engine that emulates Sender / Receiver behaviour at the packet level. It lets you validate connectivity, transport setup, encryption, and registry orchestration without real media hardware on either end.
When IS-05 activates a Sender or Receiver, the engine starts (or stops) a flow of structured test packets over the configured transport. Each test packet carries a small fixed-format header that lets the receiving side detect:
- Packet loss — via the per-packet sequence counter
- Late delivery — via the embedded timestamp (>100 ms threshold)
- Source mismatch — the receiver verifies the configured source matches the inbound address
- Length / framing errors — packets that aren't the expected size
- Privacy-encryption integrity — counter + key-version fields exercise the TR-10-13 PEP path end-to-end
Supported transports out of the box:
| Transport | Use |
|---|---|
| UDP multicast / unicast | RTP-style flows, multi-receiver fan-out, MPEG2-TS over UDP |
| SRT | Reliable unicast over the public internet |
| TCP | Reliable unicast |
| USB-over-IP | USB device traffic tunneled over IP per TR-10-14 |
Together with the embedded capabilities-driven NMOS Controller, the streaming engine supports a multi-Node test fabric across any number of machines: IS-05 activations drive real connections, the Controller runs IS-11 stream-compatibility negotiation against the connected peers, and Senders / Receivers are reconfigured against what the device declares in BCP-004-01/-02 — codec profile / level, sampling, bit-depth, packet-time, transport, channel layout. The TLS, OAuth 2.0, PEP, registry registration, and capability negotiation paths are exercised end-to-end.
AMWA NMOS Interface Specifications (specs.amwa.tv)
| Spec | Role |
|---|---|
| IS-04 Discovery & Registration | Node API, Registry client |
| IS-05 Connection Management | Senders, Receivers, staged/active model |
| IS-10 Authorization | OAuth 2.0 Bearer tokens, JWKS, claims |
| IS-11 Stream Compatibility | Sender / Receiver capability + constraint support via the Matrox CCF framework (caps/); dynamic reconfiguration driven by active constraint sets; per-sub-flow / per-sub-stream configuration for hierarchical mux transports. IS-11 Input / Output resources are not implemented. |
AMWA NMOS Best Current Practices (specs.amwa.tv)
| BCP | Role |
|---|---|
| BCP-002-01 Natural Grouping of NMOS Resources | Grouping Sender / Receiver / Source resources into logical units |
| BCP-002-02 Asset Distinguishing Information | Instance Identifier used by IS-10 audience claims |
| BCP-003-01 Securing Communications with TLS | TLS cipher whitelist, mTLS, version pinning |
| BCP-003-02 Authorization with OAuth 2.0 | Token validation, public-key cache, scope semantics |
| BCP-004-01 Receiver Capabilities | Sender / Receiver capability advertisement |
| BCP-004-02 Receiver Capabilities — Schemas | Capability/constraint JSON schemas |
| BCP-005-03 NMOS With Privacy Encryption | Privacy-encrypted Sender / Receiver wiring |
| BCP-006-01 NMOS With JPEG XS | JPEG XS sender/receiver SDP profile, profile/level/sublevel mapping |
| BCP-006-02 NMOS With H.264 | H.264 (AVC) sender/receiver SDP profile, profile/level mapping |
| BCP-006-03 NMOS With H.265 | H.265 (HEVC) sender/receiver SDP profile, profile/level/tier mapping |
| BCP-007-02 NMOS With USB | USB sender/receiver SDP profile and verification |
| BCP-008-01 Receiver Monitoring | Receiver status delivered through IS-04 — async WebSocket subscriptions to the NMOS registry's /x-nmos/query/v1.3/subscriptions/ (no IS-12 / MS-05-02 dependency) |
| BCP-008-02 Sender Monitoring | Sender status delivered through IS-04 — same async-WebSocket-grain channel; status changes are observable by every controller subscribed to the registry |
VSF Technical Recommendations (vsf.tv)
| TR | Role |
|---|---|
| TR-10-13 Privacy Encryption Protocol | Per-flow AES-CTR encryption, key derivation, RTP adaptation. UDP, SRT, RTSP protocol adaptation also supported. |
| TR-10-14 USB-over-IP | USB protocol adaptation |
Matrox NMOS extensions (NMOS-MatroxOnly)
The Matrox extensions are formalised in the NMOS-MatroxOnly specifications corpus. This implementation covers the subset of that corpus listed below; each entry is integrated with IS-11 and the Matrox CCF so every sub-flow / sub-stream of a hierarchical mux is configured independently by the embedded Controller.
| Extension | Role |
|---|---|
| NMOS With MPEG2-TS | MPEG2-TS (H.222.0) mux containing video + audio + data sub-streams; per-sub-stream IS-11 constraint negotiation |
| Matrox With NDI | NDI mux sender / receiver — Matrox-extended capability set covering the BCP-007-01 surface |
| NMOS With RTSP | RTSP-based receiver with RTP sub-flows; capability-driven RTSP OPTIONS / DESCRIBE / SETUP |
| NMOS With SRT | SRT unicast transport (caller / listener), with PEP encryption hand-off |
| NMOS With USB | USB device transport (USB-over-IP) — Matrox-extended capability set covering the BCP-007-02 surface, with the TR-10-14 protocol adaptation wired through PEP |
| NMOS With AES3 (AM824) | AES3-style audio mux container; per-channel constraint negotiation |
| NMOS With AAC | AAC audio sender / receiver with codec-profile constraints |
| NMOS With H.264 | H.264 (AVC) Sender / Receiver — Matrox-extended capability set covering the BCP-006-02 surface; full profile / level / bitrate negotiation |
| NMOS With H.265 | H.265 (HEVC) Sender / Receiver — Matrox-extended capability set covering the BCP-006-03 surface; profile / level / tier / bitrate negotiation |
| NMOS With Privacy Encryption | PEP integration on every supported transport (RTP, SRT, RTSP, USB) — Matrox-extended capability set covering the BCP-005-03 surface |
| NMOS With OAuth 2.0 | OAuth 2.0 Bearer-token validation flow — Matrox-extended capability set covering the BCP-003-02 / IS-10 surface (JWKS cache lifecycle, claim semantics, scope / x-nmos-* enforcement, public-key rotation) |
| NMOS With Status Reporting | Sender / Receiver monitor resources delivered over IS-04 async WebSocket subscriptions — Matrox-extended capability set covering the BCP-008-01 / BCP-008-02 surface; no IS-12 / MS-05-02 dependency |
| NMOS With IS-11 | Sender / Receiver capability + constraint flow — Matrox-extended capability set covering the IS-11 surface, with hierarchical-mux sub-flow / sub-stream constraints keyed by layer, format, and layer_compatibility_groups. Excludes IS-11 Input / Output resource support. |
| NMOS With Reservation API | Exclusive-acquire / renew / release control surface for protected resources |
| Capability layer extensions | Constraint sets keyed by layer, format, and layer_compatibility_groups — the basis for hierarchical mux negotiation |
If you're new to NMOS or to the Matrox extensions, two sets of tutorials are recommended starting points:
- AMWA NMOS — concept walk-throughs, architectural overviews, and worked examples are published at specs.amwa.tv/nmos/info/. Start here for the foundational vocabulary (Senders / Receivers / Sources / Flows / Devices / Nodes), the registration + discovery model, and how IS-04 / IS-05 / IS-11 fit together.
- Matrox NMOS Advanced Streaming Architecture (NASA) — Matrox-extension tutorials covering the hierarchical mux model, the IS-11 sub-flow negotiation pipeline, PEP wiring, capability-layer / compat-groups usage, and the Reservation API. Available at github.com/alabou/NMOS-MatroxOnly/tree/main/tutorials.
nmos/ — Core NMOS implementation
api/ — HTTP/WS endpoints, TLS context factories, IS-04/05/...
controller/ — Built-in NMOS Controller + outbound OAuth2/registry clients
node/ — Node resources (senders/receivers/sources/flows/devices), config
json/ — Typed JSON serialization engine
types/generated/ — Auto-generated typed wrappers for all NMOS resource types
oauth2/ — Bearer token validation, JWKS cache lifecycle
tasks/ — DispatchGroup wrapping asyncio.TaskGroup
codec/ — Audio/video codec descriptors (H.264, H.265, AAC, JXSV, AES3, …)
enums/, ip/, errors/, uuid/ — Domain primitives
sdp/ — SDP encoding/decoding (Matrox profile)
caps/ — Capability/constraint framework (Matrox CCF)
pep/ — Privacy Encryption Protocol (PEP) helpers
nmos_node.py — Main entry point; parses CLI and starts the server
run_server.py — Lightweight wrapper for embedding nmos_node from scripts
demo_controller.py — Standalone demo controller for manual exploration
start-node*.sh — Launch scripts for the three security configurations
# Full test suite (~3 minutes; 2 000+ tests)
python3 -m pytest -q nmos/ sdp/
# Per-module
python3 -m pytest -q nmos/oauth2/tests/
python3 -m pytest -q nmos/api/tests/test_tr10_tls.pyThe test markers are documented in pyproject.toml:
- default gate excludes
e2eandslow integrationtests run in-process across multiple modules and remain in the default gatee2e/slowmarkers cover full-protocol scenarios you can opt in to
This repository implements an NMOS Node and a curated set of VSF IPMX / TR-10-x extensions. Its coverage of the broader Matrox specification corpus is bounded by the spec coverage tables above.
NMOS-MatroxOnly/ is the broader Matrox documentation corpus. This Python implementation supports only the subset of that corpus that has been validated end-to-end here. See the NMOS-MatroxOnly repository for the full specification set; the spec coverage tables above list what this implementation exercises.
IS-05 Bulk interface is intentionally not supported. The Node implements the per-Sender / per-Receiver IS-05 single-resource endpoints (/single/...) but does not expose the /bulk/... interface. Bulk operations are out of scope: the Controller drives multi-resource activations as coordinated single-resource calls, which keeps the connection-management state machine uniform across Senders and Receivers and avoids the partial-success semantics of bulk activations. Vendors who need IS-05 Bulk on their own products must add it themselves.
Apache License 2.0 — © 2025-2026 Alain Bouchard.
This implementation tracks specifications from three bodies:
- The AMWA NMOS Interface Specifications and Best Current Practices maintained by the Advanced Media Workflow Association — the work of the AMWA Networked Media Incubator and contributors.
- The VSF Technical Recommendations (TR-10 family) maintained by the Video Services Forum — the work of the VSF IPMX Task Force.
- The Matrox NMOS Advanced Streaming Architecture (NASA) documented in the NMOS-MatroxOnly specifications corpus.
See each specification for full credits.