SMPTE ST 2110
bilbycast-edge ships first-class support for the broadcast-audio, broadcast-data, and uncompressed-video subset of SMPTE ST 2110:
| Standard | Essence | Status |
|---|---|---|
| ST 2110-30 | Linear PCM audio (L16, L24) | Phase 1 (shipped) |
| ST 2110-31 | AES3 transparent (Dolby E, etc.) | Phase 1 (shipped) |
| ST 2110-40 | Ancillary data (RFC 8331) | Phase 1 (shipped) |
| ST 2110-20 | Uncompressed video (RFC 4175, YCbCr 4:2:2 8/10-bit) | Phase 2 (shipped) |
| ST 2110-23 | Partitioned uncompressed video (2SI + sample-row modes) | Phase 2 (shipped) |
| ST 2110-22 | JPEG XS video | Deferred (pending libjxs wrapper crate) |
The uncompressed video essences reuse the same encoder / decoder
infrastructure as the compressed transports: ST 2110-20 / -23 inputs
RFC 4175-depacketise raw frames and feed them through
video-engine::VideoEncoder in a spawn_blocking worker, then
TsMuxer into the flow; outputs demux the flow’s TS, decode via
video-engine::VideoDecoder, scale into planar 4:2:2 8/10-bit via
VideoScaler::new_with_dst_format, and Rfc4175Packetizer onto the
wire (Red + optional Blue). Inputs require a video_encode block and
a compiled-in video-encoder-* Cargo feature (libx264 / libx265 /
NVENC). Outputs only need the default media-codecs feature.
The accompanying NMOS surface area covers IS-04 (Node API), IS-05 (Connection Management), IS-08 (Audio Channel Mapping), and BCP-004 (Receiver Capabilities). See NMOS for the protocol-level details.
Architecture
Section titled “Architecture”ST 2110 essence flows reuse the existing flow data plane: an input task receives RTP packets, validates them with the essence-specific depacketizer, publishes whole RTP packets to the flow’s broadcast channel, and the output tasks resend them with optional DSCP marking and Red/Blue duplication for SMPTE 2022-7 hitless redundancy. There is no per-sample re-packetization on the loopback path; a paired ST 2110 input + output achieves byte-identical loopback by passthrough.
ST 2110-30 input ──┐ │ broadcast::Sender<RtpPacket>ST 2110-31 input ──┼──►──────────────────────────────► ST 2110-30 output │ ST 2110-31 outputST 2110-40 input ──┘ ST 2110-40 output SRT output (WAN bridge) UDP outputPTP integration
Section titled “PTP integration”bilbycast-edge does not run a PTP daemon itself in the default build.
The recommended deployment runs ptp4l from linuxptp on the host with
a hardware-timestamping-capable NIC; the edge polls the daemon’s
management Unix socket once per second and reports the result through
the existing stats channel as FlowStats.ptp_state. Polling is
best-effort: when the daemon is unreachable the lock state stays at
unavailable and flows continue to operate.
ptp4l ──► /var/run/ptp4l ──► PtpStateReporter ──► PtpStateHandle ──► FlowStats.ptp_state │ └─► manager UIThe optional --features ptp-internal flag is reserved for an
in-process statime slave clock for environments that prefer a
single-process deployment. The flag exists today as a build-matrix
marker; the actual statime integration lands in a follow-up.
NIC requirements
Section titled “NIC requirements”For broadcast-grade lock (sub-µs offset, traceable holdover) you need a NIC with hardware timestamping. Verified families:
- Intel i210, i350, X710, E810
- Mellanox ConnectX-5, ConnectX-6, ConnectX-7
Verify with ethtool -T <iface> — you want hardware-transmit and
hardware-receive in the timestamping capabilities.
Sample ptp4l configuration
Section titled “Sample ptp4l configuration”[global]domainNumber 0priority1 128priority2 128delay_mechanism E2Enetwork_transport UDPv4clockClass 248free_running 0freq_est_interval 1[eth0]SMPTE 2022-7 Red/Blue dual networks
Section titled “SMPTE 2022-7 Red/Blue dual networks”Every ST 2110 input variant accepts an optional redundancy block that
points at a second bind address. When set, the input opens both Red and
Blue UDP sockets, runs the existing hitless merger over the merged
packet stream, and exposes per-leg counters via
FlowStats.network_legs (populated only when redundancy is configured).
Outputs do the same in reverse: every ST 2110 output accepts a
redundancy block that duplicates each packet to a second destination.
┌── Red socket ──┐RTP source ───► │ │ ──► HitlessMerger ──► broadcast channel └── Blue socket ─┘Source-IP allow-listing is supported on the single-leg path. Combining
allowed_sources with redundancy is rejected by validation — the
merger path doesn’t expose per-packet src and the dual-leg path won’t
silently bypass the source filter.
Configuration
Section titled “Configuration”See Configuration for the full schema. Minimal example:
{ "flows": [ { "id": "audio_stereo", "name": "Studio A — stereo", "enabled": true, "clock_domain": 0, "input": { "type": "st2110_30", "bind_addr": "239.0.0.10:5000", "interface_addr": "10.0.0.5", "sample_rate": 48000, "bit_depth": 24, "channels": 2, "packet_time_us": 1000, "payload_type": 97, "redundancy": { "addr": "239.1.0.10:5000", "interface_addr": "10.1.0.5" } }, "outputs": [ { "type": "st2110_30", "id": "loop1", "name": "loopback to monitor", "dest_addr": "239.2.0.10:5000", "dscp": 46, "sample_rate": 48000, "bit_depth": 24, "channels": 2, "packet_time_us": 1000, "payload_type": 97 } ] } ]}Validation limits
Section titled “Validation limits”| Field | Allowed values |
|---|---|
sample_rate | 48000, 96000 |
bit_depth | 16, 24 |
channels | 1, 2, 4, 8, 16 |
packet_time_us | 125 (AM), 1000 (PM) |
payload_type | 96–127 |
clock_domain | 0–127 |
dscp | 0–63 (default 46 / EF) |
ST 2110-21 narrow profile pacing (uncompressed video)
Section titled “ST 2110-21 narrow profile pacing (uncompressed video)”The default ST 2110-20 / -23 egress path is unpaced — the kernel schedules transmission as fast as the NIC will accept it. That works for development, wide-profile receivers, and most informal deployments. For interop with narrow-profile receivers (Imagine, Lawo, EVS Xeebra, Grass Valley LDX, Bridge Tech VB330 in test mode) the sender must obey the ST 2110-21 §6.3 VRX / Cmax bounds, which at production rates means per-packet timing within a few microseconds of the frame raster.
Userspace pacing can’t hit that budget at 1080p50 (≈ 250 k pps,
4 µs inter-packet) or 4K60 (≈ 1 M pps, 1 µs inter-packet). The
solution is Linux SO_TXTIME + the ETF qdisc (Earliest TxTime First),
with HW offload on PTP-disciplined NICs.
How it works
Section titled “How it works”ST 2110-20 / -23 outputs run the paced sender unconditionally — no
per-output opt-in needed. engine::st2110::pacer::St2110_21Pacer
computes the per-packet target tx time against the active video
raster, anchored on CLOCK_TAI (re-anchored from PTP samples; falls
back to monotonic without PTP). The target is handed to
engine::wire_emit, which — when BILBYCAST_ENABLE_TXTIME=1 is set
on the edge process and a working ETF qdisc is installed on the
egress NIC — attaches an SCM_TXTIME CMSG via libc::sendmsg and
lets the kernel ETF qdisc honour it. Without the env var the edge
stays on the default clock_nanosleep release tier, which still
runs the raster math but can’t hit the µs precision narrow profile
demands. One std::thread per output socket runs at SCHED_FIFO
(granted by the systemd unit’s LimitRTPRIO=99) so the tokio runtime
is never blocked.
NIC families with HW offload
Section titled “NIC families with HW offload”| NIC family | Driver | HW offload |
|---|---|---|
| Mellanox CX-6 / CX-7 | mlx5_core | Yes (sub-µs jitter) |
| Intel E810 | ice | Yes |
| Intel i210 | igb | Yes |
| Other | (any) | Software ETF (~ 1–10 µs jitter) |
Software ETF still gives an order-of-magnitude improvement over
unpaced. HW offload requires the NIC’s PHC to be PTP-disciplined
(phc2sys or equivalent).
Operator setup
Section titled “Operator setup”The full step-by-step is in Install edge as a Linux service → “ETF qdisc setup” and Wire-Time Precision. Summary:
- Install the ETF qdisc on the egress NIC:
sudo bash /opt/bilbycast/edge/current/packaging/setup-etf-qdisc.sh enp1s0. - Install the boot-time
bilbycast-etf-qdisc@enp1s0.serviceunit so the qdisc survives reboots:Terminal window sudo install -m 0644 \/opt/bilbycast/edge/current/packaging/bilbycast-etf-qdisc@.service \/etc/systemd/system/sudo systemctl daemon-reloadsudo systemctl enable --now bilbycast-etf-qdisc@enp1s0 - Confirm
ptp4l+phc2sysare running (the system clock must be PTP-disciplined). For HW offload, the NIC’s PHC also needs to be PTP-disciplined viaphc2sys. - Opt the edge in to the SO_TXTIME tier by adding
BILBYCAST_ENABLE_TXTIME=1to/etc/bilbycast/edge.envand restartingbilbycast-edge.service. Without this env var the edge stays on the defaultclock_nanosleeptier, which won’t meet narrow profile. - Confirm the active tier on each output:
Terminal window curl -k https://<edge>:8080/api/v1/stats | \jq '.data.flows[].outputs[] | {id: .output_id, tier: .wire_pacing_tier, late: .wire_pacing_late}'
wire_pacing_tier = "so_txtime" plus ETF qdisc installed = tier 1
(or 2 with software ETF). The deprecated wire_pacing config field
on ST 2110-20 / -23 outputs is ignored at runtime — pacing is
automatic.
What if I skip the setup?
Section titled “What if I skip the setup?”ST 2110-20 / -23 outputs always run the paced sender, but on the default clock_nanosleep tier (without BILBYCAST_ENABLE_TXTIME=1)
the userspace round-trip can’t hit the µs inter-packet budget that
1080p50 / 4K60 demand. Bytes are valid, frames are decodable. What
fails is narrow-profile compliance at the receiver, which manifests
as VRX overflow / underflow events on the receiver’s analyzer.
There is no in-band degradation visible to a wide-profile receiver.
Without PTP, the pacer falls back to monotonic time — outputs run
loose relative to absolute time but are still internally even-paced.
Pending external validation
Section titled “Pending external validation”The following items are deferred until matching hardware and tooling become available in the test lab:
- AMWA NMOS Testing Tool runs against IS-04, IS-05, IS-08, BCP-004. Expected pass matrix is documented in NMOS.
- Live PTP hardware tests on each NIC family above.
- Real-world interop with Lawo, Riedel, Calrec, Evertz, and Imagine
ST 2110 equipment. The manual procedure lives in
testbed/ST2110_INTEROP_TEST.md. - ST 2110-21 narrow-profile compliance against a hardware analyzer
(Bridge Tech VB330, EBU LIST, Telestream PRISM). Today’s pacer
ships
narrow_linearmath; classic gapped narrow lands when a real receiver requires it.