Networked Audio · GPS Time · Real-Time Linux

GPS-Disciplined AVB & Realtime Remote Audio Exchange

A Raspberry Pi 5 implementation streaming pro-audio between California cities over the public internet: Campbell ↔ Saratoga ↔ Los Angeles.

Jeff Koftinoff <jeff.koftinoff@statusbar.com> · Ford Motor Company. Enthusiastically involved with real-time audio, music, networking, time synchronization, and open source for almost all my life! A personal experiment, presented with Ford Motor Company's gracious support.

Connect on LinkedIn: linkedin.com/in/jdkoftinoff

Motivation · The Dream

A personal experiment: GPS as a global word clock

Can a low-cost Raspberry Pi 5 run a full AVB stack — and can GPS time be the media clock for the whole planet?

The Gear

Three residential sites

The Setup

The easy plan

The Preparations

But what is the worst-case latency?

You can't size the buffer until you've measured the network performance.

The Hard Parts

Tricky stuff for owlm-tool

The Hard Part — Real-Time Constraints

Can we do real work without missing the next 125 µs?

The Hard Part — Interference, and Avoiding It

Own two cores completely

Where the jitter comes from

  • Interrupts & high-priority drivers
  • CLOCK_MONOTONIC perturbed by NTP
  • Thermal throttling
  • Kernel MMU page work for low-prio tasks blocks high-prio tasks

How we shut it out

PREEMPT_RT · HZ=1000 · NO_HZ_FULL · RCU_NOCB_CPU · IRQ_FORCED_THREADING

isolcpus=2-3 nohz_full=2-3 rcu_nocbs=2-3 irqaffinity=0-1

Cores 2–3 leave the scheduler entirely; cores 0–1 take every IRQ and all of Linux.

MMU interference is unavoidable if any syscall is needed.

Architecture — Core Partitioning

Two cores, one job each

Core 3 — Network I/O

  • Time-triggered SCHED_FIFO task
  • All packet TX / RX
  • Traffic shaping, separation, prioritization

Core 2 — Audio

  • Owns the media-clock domain
  • Compensation (playout) buffers
  • Schedules every audio packet at the correct gPTP time

Cores 2 and 3 communicate exclusively through lock-free SPSC (single-producer / single-consumer) queues with no locks, no syscalls, and no shared scheduler. Cores 0–1 run Linux + all IRQs.

Architecture — Traffic Shaping

The Pi has just enough Ethernet to do AVB

The BCM2712 MAC hardware-timestamps, but it has no separate priority queues, no packet launch-time control, and no traffic shaping.

Architecture — Jitter Removal

Inter-thread presentation-time compensation buffer

One buffer keyed by presentation (gPTP/TAI) time sits between the cores: written by core 3 (network), read by core 2 at the exact playout time.

Ingress AVB audio

  • Local AVTP stream arrives with LAN jitter
  • Re-clocked to the media clock and played out on time

Ingress inter-city audio

  • WAN tunnel buffered to the worst-case path (WCL)
  • Temporally-redundant copies carry the same presentation time — a late/lost primary is filled by its redundant; the buffer simply keeps whichever lands first
Evidence — Campbell ↔ Saratoga (near)
⬇ Full report (PDF) ~20 km apart · one-way ≈ 2 ms baseline. Tap graph to zoom · drag box edge to resize.
Campbell↔Saratoga owlm latency-vs-wall-time (both directions)
Evidence — Campbell ↔ Los Angeles (far)
⬇ Full report (PDF) ~500 km · one-way ≈ 8 ms baseline — distance adds only a few ms. Tap graph to zoom.

The last mile is where the primary latency is. The worst-case tail that sizes your buffer is residential-uplink bufferbloat — not the 10× distance.

Campbell↔Los Angeles owlm latency-vs-wall-time (both directions)
The Audio Packets

What's in each UDP packet

WAN tunnel datagram · AAF v1 / Annex J
Channels8
Samples / channel44  (352 total)
Formatint32 · 96 kHz
Audio per packet458.3 µs
Datagram rate~2181/s  (×2 redundant)
PCM payload44×8×4 = 1408 B
+ AAF header44 B
UDP payload1452 B · one MTU
Grandmaster ID70:B3:D5:FF:FE:ED:CF:FF

Every packet's ptp_grandmaster_identity is a sentinel I defined in my own OUI-36 range (70-B3-D5-ED-C, 36 bits): this value declares the media clock is TAI disciplined by GPS/GNSS — one shared Earth clock domain. It's the only clock-domain field AAF-over-UDP carries, so two cities with independent GPS receivers know they share one timescale.

The Audio Packets

Local AVB vs. the WAN tunnel

Smp/pktPkt/s
Native AVB (LAN)128000
UDP tunnel (WAN)44~2181

Local format follows the device: MOTU 8A → AM824 (IEC 61883-6), Meyer Galaxy → AAF. The tunnel carries AAF-v1 over UDP either way — 12-sample AVB packets re-framed up to one MTU for the internet, then back at the far end. Both 8 ch / 96 kHz / int32.

The Hard Part — Media-Clock Surprise

GPS clock quality wasn't good enough

AVB audio devices rejected gPTP derived from GPS.

The Hard Part — Solution

Split frequency from phase

Jitter hurts more locally than between sites, so use a different clock domain at each layer.

Local (low jitter)

  • Luminex/MOTU switch = gPTP Grand Master
  • linuxptp locks to that gPTP
  • GPS-via-NTP drives CRF / AM824 media-clock streams the devices lock to

Between sites (absolute time)

  • TM2000B = plain NTP server; chrony locks to it
  • Inter-site UDP timestamped in GPS TAI
  • Kalman filters reject NTP jitter → ±1 ms cross-site, clean media-clock rate

A model is always wrong but sometimes useful: pick the clock domain that's accurate enough for each requirement.

The Result

8 channels of 96 kHz audio, city to city, over the open internet

How I built it · LLM (1 of 2)

What I leveraged Claude (Opus 4.7/4.8) for

All under tight guardrails (see next slide).

LLM (2 of 2) — How to use it well

Build reusable, tested tools

Where it's good

  • Strong, explicit acceptance criteria up front
  • Test-driven: tests first, short functions, testable code
  • Clean code, best practices, clang-tidy as a gate
  • Make reusable, tested tools for analysis/refactor
  • Once the submodules, components & test harnesses exist, agents connect them like building blocks

Where it's bad

  • Plausible-but-wrong without acceptance criteria + tests
  • One-shot "do the thing" rots; tools compound
  • Needs the human to own the physics & the spec

Proof from this project: owlm_analyze, the masked re-analyzer, the colbin renderers, the test harnesses — reusable and tested, written with the model, not by it. Write code that's easy for an LLM to reuse — the components shown here are meant to be used exactly this way.

Open Source

All MIT-licensed

QR: codeberg.org/statusbar

codeberg.org/statusbar
source code

QR: abc.statusbar.com

abc.statusbar.com
AVB bandwidth calculator

QR: avb.statusbar.com

avb.statusbar.com
AVB presentations

QR: linkedin.com/in/jdkoftinoff

linkedin.com/in/jdkoftinoff
connect on LinkedIn

repos & caveats in the appendix →   Jeff Koftinoff <jeff.koftinoff@statusbar.com>

Appendix / Backup

Appendix

Reference material : future work and repositories.

Appendix — Repositories & Caveats

Where the code lives

codeberg.org/statusbar

corenet (raw + POSIX sockets, reactor) · realtime (RT timers, SCHED_FIFO) · itc (lock-free SPSC) · colbin (capture format) · tsn · ieee (Ethernet) · test · sg14 · buffer · config / toml / csv
cryptoAES-128/256 · AES-CBC / GCM / SIV · CMAC · HKDF · SHA-256 / 512 · Ed25519 · ECDSA · X25519 (standard encrypted AVB)
audiodsp (SIMD, oscillators, complex-coefficient filters) · osc (Open Sound Control) · engine · midi · ltc (linear timecode)
avbgptp (802.1AS) · ptpclient (linuxptp) · srp (SRP / MSRP / MVRP) · atdecc + nanoavb (AVDECC / 1722.1) · avtp (AAF / AM824 / CRF) · avb_entity · udptun (inter-site tunnel + redundancy) · owlm · stun (NAT)

Caveats: personal experiment, not a product; a low-cost Pi 5 is not a certified AVB endpoint. MIT-licensed, as-is.

Appendix — Future Work

A network TAP device

Intended next step: ‘make the RT core own the Ethernet port’ — non-real-time tasks reach the network only through a virtual TAP it controls.

1 / 1

Controls

SpacePgDnNext slide
PgUpPrevious slide
+ / / 0Zoom slide in / out / reset
Scroll a zoomed slide
fFullscreen the browser
tToggle dark / light theme
Home / EndFirst / last slide
On the PDF slidesClick ⤢ Fullscreen PDF, then use the PDF viewer's own zoom & scroll
? / EscToggle / close this help

The bar at the bottom of the screen has the same buttons (for an air-mouse remote).