# 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](https://github.com/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](https://github.com/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) components/dante/ Clean-room Dante support (discovery now; ARC/CMC/flows/PTPv1 later) 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. ```bash 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 - [x] 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 - [x] Write clean-room Dante protocol notes (`docs/dante-protocol-notes.md`) - [x] Prototype Dante mDNS **discovery** (`components/dante`, read-only browse) - [ ] Prototype Dante mDNS **advertisement** (needs ARC/CMC servers behind it) - [ ] 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.