Dante-interoperable AES67 audio-over-IP firmware for the ESP32-P4

Benjamin Harris b0c90fda7c docs: fill in clean-room Dante protocol notes il y a 3 mois
components 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois
docs b0c90fda7c docs: fill in clean-room Dante protocol notes il y a 3 mois
main 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois
.gitignore 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois
CLAUDE.md 341c70786e first commit il y a 3 mois
CMakeLists.txt 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois
LICENSE 341c70786e first commit il y a 3 mois
README.md 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois
sdkconfig.defaults 55b0d95b52 Scaffold ESP-IDF project and vendor AES67 base il y a 3 mois

README.md

Dante / AES67 Audio-over-IP for ESP32-P4

Status: AES67 base vendored in, untested on hardware. The aes67-esp32p4 engine and a board-configurable app entry point are in place; not yet build-verified or run against real gear. Native Dante support is still at the notes stage.

Goal

A low-cost, network audio endpoint on the ESP32-P4 that can interoperate with Dante-based AV systems. In practice "Dante-interoperable" is being pursued in two phases:

  1. AES67 interop (primary target) — most Dante hardware from the last several years can send/receive AES67, so a solid AES67 endpoint already gets us into the same audio network as Dante gear.
  2. Native Dante protocol support (stretch goal) — Dante's proprietary discovery (mDNS records), control protocol (routing/subscription), and PTPv1 clocking, for talking to older or AES67-disabled Dante devices.

Why ESP32-P4

The original ESP32 (WiFi, Xtensa) can't hold AES67's ~1ms RTP packet timing tightly enough over WiFi to be spec-compliant. The P4 drops WiFi in favour of a real Ethernet MAC with hardware PTP timestamping, which is what makes sub-millisecond, spec-accurate AoIP achievable on this class of chip at all.

Two source projects this builds on

1. DatanoiseTV/aes67-esp32p4 — foundation (Apache-2.0)

This is what we fork from. It already solves the hard, P4-specific problems: hardware PTP timestamping via the EMAC, an I2S driver with APLL clock recovery, an RTP engine with an L2 hook that bypasses lwIP for latency, SAP/SDP, and mDNS/DNS-SD advertisement. Apache-2.0 means we can build on it freely, including for commercial client work.

2. teodly/inferno — protocol reference only (GPL-3.0-or-later / AGPL-3.0-or-later)

A full software Dante device implementation for Linux. We do not vendor or copy code from this repo. It's copyleft-licensed, and incorporating its code would obligate this whole firmware image to the same license — which rules out using it in closed commercial deliverables. Instead it's used as documentation: reading inferno_aoip to understand Dante's wire behaviour (mDNS service records, control-protocol framing, flow subscriptions) well enough to write an independent, clean-room implementation against the P4 component.

This licensing boundary is the most important constraint on this project. See CLAUDE.md for the hard rule any dev session (human or agent) needs to follow.

Hardware target

Starting point is DatanoiseTV's reference pinout for the ESP32-P4-NANO board — confirm/update against whatever board this actually gets deployed on:

Function GPIO Notes
Ethernet MDC 31
Ethernet MDIO 52
Ethernet REF_CLK 50 External 50MHz crystal
Ethernet PHY_RST 51
I2S MCLK 13 18.432MHz via APLL
I2S BCLK 36 (onboard: 12)
I2S LRCLK 33 (onboard: 10)
I2S DOUT 32 (onboard: 9)
I2S DIN 11 Codec ADC input
PA Enable 53 Active high
I2C SCL / SDA 8 / 7 ES8311 control

Ethernet PHY: IP101 GRI via RMII. Onboard codec: ES8311 + NS4150B amp.

Unresolved — confirm against the actual board. The I2S rows above are not internally consistent. BCLK/LRCLK/DOUT (36/33/32) are the external DAC pins from the upstream example, while DIN (11) is the onboard ES8311 ADC pin — the upstream example's active config actually uses DIN=21 for an external ADC. Decide whether this build targets the onboard ES8311 (MCLK 13, BCLK 12, LRCLK 10, DOUT 9, DIN 11) or an external DAC/ADC (MCLK 13, BCLK 36, LRCLK 33, DOUT 32, DIN 21), then make the table, main/board_config.h, and the ES8311 vs. external assumption in main/main.c all agree. Current board_config.h mirrors the table above verbatim (external data pins + onboard DIN) and is therefore a placeholder.

Repo layout

components/aes67/   Forked from aes67-esp32p4 — AES67 engine (PTP, RTP, I2S, SAP/SDP, mDNS)
main/                Application entry point, board config
docs/                Design notes, incl. clean-room Dante protocol notes
reference/           Local clones of both source repos, for reading only (gitignored, not part of this repo)

Build

Requires ESP-IDF v5.5+ with the ESP32-P4 target.

idf.py set-target esp32p4
idf.py build
idf.py flash monitor

components/aes67 is vendored in (from aes67-esp32p4, Apache-2.0) and main/ wires it up via main/board_config.h. Not yet build-verified in this environment — needs an ESP-IDF v5.5+ toolchain and, before flashing, the pinout confirmation noted above.

Roadmap

  • Fork aes67-esp32p4's components/aes67 in as the starting point
  • Confirm pinout against actual target hardware (see note above — I2S rows are inconsistent and board_config.h is a placeholder)
  • Build-verify with ESP-IDF v5.5+ (idf.py set-target esp32p4 build)
  • Get AES67 send/receive verified against real Dante gear in AES67 mode
  • Write clean-room Dante protocol notes (docs/dante-protocol-notes.md)
  • Prototype Dante mDNS advertisement/discovery
  • Prototype Dante control protocol (routing/subscriptions)
  • Investigate PTPv1 support alongside the existing PTPv2 stack

License

Apache-2.0 (see LICENSE), matching the aes67-esp32p4 base this project forks from.