Files
aes67-ESP32-P4/docs/user-guide.md
T
bsncubed 214d6b2c29 Firmware version: <version.txt>-<git short hash>, starting at 0.0.1
e.g. 0.0.1-1d613b1: the first part is set by hand, the hash says which
commit was built. No dirty flag (the build always patches cspot).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 07:52:23 +10:00

15 KiB
Raw Blame History

P4 AES67 Streamer: user guide

The P4 AES67 Streamer turns Spotify Connect or an internet radio stream (HLS / m3u8) into an AES67 multicast stream, locked to your PTP clock. Any AES67 receiver on the network can play it: a Riedel Artist 4-wire port, a Dante device in AES67 mode, a DAW, and so on.

It runs on a Waveshare ESP32-P4-ETH board, powered over PoE, and is set up entirely from a web page.

Contents: Getting started · The web page · Sources · Spotify · AES67 output · PTP · Network · Logging · Firmware updates · Player API · Troubleshooting · Limitations


Getting started

  1. Connect the board's Ethernet port to a PoE switch port, or to a normal port and power it over USB-C. Use the same network (or VLAN) as your AES67 devices and your PTP grandmaster.
  2. Wait about 20 seconds. The board gets an address by DHCP and locks to PTP.
  3. Open the web page at http://p4-aes67.local/. Alternatively, look up the board's IP in your router's DHCP list (the name is p4-aes67) and open http://<IP>/.
  4. Pick a source under Source and click Save (see Sources).
  5. On the receiver, either find the stream via SAP, or copy the SDP from the page's SDP section (see AES67 output).

Out of the box the board streams 2-channel, 24-bit, 48 kHz audio with 1 ms packets to 239.69.1.10:5004 and announces it by SAP under the name "P4 AES67".

More than one board? Each board needs its own hostname, stream name and multicast address, or they clash. Change them under Network and AES67 output, or let tools/flash_board.py ask for them when you flash a new board.


The web page

The page is split into sections, from top to bottom:

Section What it's for
Status Firmware version, IP / MAC, link speed, active source, Spotify state, buffer, packets sent, underruns, uptime, memory, chip temperature.
PTP status Whether the clock is locked, which grandmaster it follows, offset and path delay. Details shows more.
Player What's playing now, transport buttons, progress bar (drag to seek), volume.
Source, PTP, AES67 output, Network, Logging Settings. They take effect only when you click Save.
SDP The stream description, to copy or download for receivers.
Firmware Update the firmware (see Firmware updates).

Saving: Save, Revert (throw away unsaved edits) and Reboot stay at the bottom of the window while you scroll through the settings. Messages such as "Saved." or error texts appear next to them. Invalid values are rejected with the reason, and nothing is saved.

Light / dark: the page is dark by default. The ◐ button at the top right switches to light, and your browser remembers the choice.


Sources

Choose the source under Source → Source:

Source What it plays
Spotify Connect The board appears as a speaker in the Spotify app (default). Needs your own Spotify app credentials; see Spotify.
HLS / M3U8 URL An internet radio stream, e.g. https://…/playlist.m3u8. Enter it under Stream URL.
Spotify, fail over to HLS Spotify when someone plays to it, otherwise the stream (see below).
Test tone 1 kHz sine at −18 dBFS, locked to PTP. For line-up and receiver tests.
Pink noise Pink noise at −18 dBFS RMS (peaks around −6 dBFS), the same signal on both channels. For level and EQ checks.
Off Silence. The stream keeps running.

Failover (Spotify, fail over to HLS)

  • Spotify playing: the board plays Spotify, switching over within about a second of pressing play.
  • No Spotify connection: after Failover delay seconds (default 5), the board switches to the HLS stream.
  • Paused: with Also fail over when paused ticked, a paused Spotify counts as "not playing" and the stream takes over after the delay. Unticked (default), a pause gives silence and the board stays on Spotify.
  • Fades: switches fade out and in over 30 ms, so there are no clicks.
  • Resuming: Spotify is held while the stream plays. When you press play again, the song continues where you paused.

Volume and gain

  • Volume (Player section): the everyday volume. With Spotify it follows the app's volume slider, and the other way round.
  • Output gain (dB): a fixed trim on top of the volume, −60 to +12 dB. Above 0 dB, loud passages can clip at full scale.
  • Neither affects the test tone or pink noise. Those always come out at their calibrated level.

Spotify

Since 2025, Spotify requires every Spotify Connect device to use a developer app registered to your own account. You need Spotify Premium. Setup takes about five minutes:

  1. Go to https://developer.spotify.com/dashboard and log in.
  2. Create app:
    • Name and description: anything, e.g. "P4 AES67".
    • Redirect URI: http://127.0.0.1:8888/callback. Spotify requires one, but this device never uses it.
    • API: tick Web API, then save.
  3. Open the app's Settings. Copy the Client ID, and click View client secret to copy the Client secret.
  4. On the board's page under Source, paste them into Spotify client ID and Spotify client secret, then Save.

The secret is write-only: after saving, the field shows empty. Leave it empty to keep the stored secret, or type a new one to replace it.

Connecting: make sure your phone or computer is on the same network as the board. In the Spotify app, open the device list and pick P4 AES67 (or the name you set under Spotify device name). Play, pause, skip, seek and volume all work from the app. The web page shows the track and position and can control playback too.

  • Spotify bitrate: 96, 160 or 320 kbit/s (default 320).
  • Spotify device name: the name shown in the app. Changing it disconnects a running session.
  • Status → Spotify shows the state: e.g. waiting for Spotify app, connected, no client credentials, login failed.

AES67 output

Setting Default Notes
Stream name (s=) P4 AES67 The name receivers show.
Enabled on Off stops sending.
Discovery SAP SAP: announced every 30 s on 239.255.255.255:9875, so receivers that support SAP find it by themselves. Manual: no announcements; use the SDP.
RTP multicast IP / port 239.69.1.10 : 5004 Must be unique per stream on your network.
TTL 32
DSCP (media) 34 (AF41) QoS marking for the audio packets.
Channels 2 1 or 2.
Mono sum off Sends (left + right) / 2 as a 1-channel stream. Forces Channels to 1; it can't clip.
Bit depth L24 L24 or L16.
Sample rate 48000 Fixed; all sources are 48 kHz.
Packet time 1 ms 0.125, 0.25, 0.333, 1 or 4 ms. 1 ms is the AES67 default and works with nearly all receivers.
Payload type / SSRC / time stamp offset 96 / 0 / 0 Only change these if a receiver needs it.

Getting the SDP to a receiver:

  • SAP: receivers that listen for SAP (Riedel, many AES67 devices) list the stream by its name.
  • By hand: in the SDP section, Copy or Download .sdp and import it on the receiver. The board also serves it at http://p4-aes67.local/stream.sdp.
  • When the SDP changes: after a setting that changes the stream, the SDP gets a new version number. Re-import it on receivers that were set up by hand.

PTP

The board locks its media clock to the PTP grandmaster on the network (IEEE 1588-2008, UDP/IPv4, E2E). PTP status shows the lock state and the grandmaster.

Setting Default Notes
Mode multicast hybrid sends the delay requests unicast (fewer multicast packets).
Role Auto TimeReceiver only: never becomes grandmaster. Auto: becomes grandmaster only if there is none (fallback). Preferred TimeTransmitter: tries to be grandmaster.
Domain 0 Must match your grandmaster.
Priority 1 / 2 250 / 250 Lower wins the grandmaster election.
Intervals, timeout, DSCP (46) Presets below set them.
HW timestamping on Leave on (much more accurate).

Presets:

  • Riedel SIC defaults: TimeReceiver only, priorities 128/126, Riedel's intervals. Use this when a Riedel system provides the clock.
  • AES67 media profile defaults: the faster intervals of the AES67 profile.

A preset only fills in the fields; click Save to apply them.

Audio starts only when PTP is locked, usually about 20 s after power-up. When the board is itself the grandmaster (no other clock on the network), its clock starts at 1 January 1970. That's fine for AES67, but it isn't real time.


Network

  • Hostname: the name in DHCP, mDNS (<hostname>.local) and LLDP (the switch's neighbour list). Changing it applies at once.
  • DHCP (default): with DHCP on, the greyed-out IP, netmask, gateway and DNS fields show the addresses DHCP handed out.
  • Static IP: untick DHCP. The current addresses stay in the fields as a starting point; edit them and Save. The board reboots to apply them, and the page switches to the new address after 20 s. The page checks that the netmask is valid, that the IP isn't the subnet's network or broadcast address, and that the gateway is in the subnet.
    • A wrong static address makes the board unreachable over the network. Double-check before saving; see Troubleshooting for recovery.
    • With a static IP, your router's DNS name for the board can go stale. http://<hostname>.local/ keeps working.

Logging

The board can send its log to a syslog server (UDP):

  • Tick Send to syslog and enter the server (hostname or IP) and port (default 514).
  • Minimum level: Error, Warning, Info or Debug.
  • Facility and format: RFC 5424 or RFC 3164 (BSD).
  • Send test message checks the path.

The log shows PTP lock/unlock, source switches, stream errors and firmware updates, which makes it useful for troubleshooting.


Firmware updates

Over the network (normal way): in the Firmware section, choose the new aes67_p4.bin and click Upload & install. The board installs it to its second firmware slot and reboots into it.

  • The new firmware must prove itself within 60 s: network up and web page answering. Only then is it kept. If it fails or crashes, the board automatically goes back to the previous firmware.
  • While the new firmware is on trial, the page offers Keep this firmware and Roll back to previous.
  • During the upload the Spotify session ends and the stream pauses. Reconnect from the app afterwards.
  • From a computer: curl -f --data-binary @aes67_p4.bin -H 'Content-Type: application/octet-stream' http://p4-aes67.local/api/ota

Over USB (new board, or recovery): tools/flash_board.py (needs ESP-IDF or pip install esptool, plus a build). It:

  • checks the board (chip revision, 32 MB flash),
  • optionally erases it (this clears all settings),
  • flashes the firmware and finds the board's IP,
  • asks for a hostname, stream name and multicast address.

Making an update file:

  1. Set the version in version.txt (first line, e.g. 0.0.2) and commit your changes.
  2. Build: idf.py build. The firmware version becomes <version>-<commit>, e.g. 0.0.2-1d613b1, as shown under Firmware and Status.
  3. The update file is build/aes67_p4.bin. Upload it in the Firmware section, or with the curl command above.

The .bin is for ESP32-P4 chips of revision v1.x (the current Waveshare boards). A board with a v3 chip needs a build for that revision; the flash script refuses it with a hint.


Player API

Everything the Player section does is also available over HTTP, e.g. for a control panel or Companion. Every command returns the current player state as JSON.

GET  /api/player                            state, source, track, position, volume
POST /api/player/play | pause | toggle | stop | next | prev
POST /api/player/seek     {"ms": 90000}
POST /api/player/volume   {"value": 0-100}   or   {"delta": -5}
POST /api/player/source   {"source": "spotify" | "hls" | "off" | "config"}
POST /api/player/url      {"url": "https://…/playlist.m3u8"}

Example: curl -X POST http://p4-aes67.local/api/player/next

  • With Spotify: the app follows every command. stop equals pause. prev restarts the song if it has played more than 3 s, like the Spotify apps.
  • With HLS (live radio): pause stops downloading, and play rejoins the live stream. next, prev and seek return an error (409).
  • source and url: temporary overrides; they're not saved, and a reboot or "source": "config" returns to the saved setting. url plays a stream right away.
  • Security: there is no password. Keep the device on a trusted network.

The full device API (status, config, SDP, firmware) is described in docs/aes67-core-base.md.


Troubleshooting

Problem What to try
Can't find the page Try http://p4-aes67.local/, or the IP from your router's DHCP list. If the board has a static IP you no longer know, use tools/flash_board.py over USB with erase (resets all settings).
Board doesn't appear in the Spotify app Phone or computer on the same network? Status → Spotify should say waiting for Spotify app. no client credentials: enter ID and secret. login failed: check them, and check that the account is Premium.
"Can't connect" in Spotify on the first try Try again; a second attempt usually works.
Spotify controls do nothing after a long idle session Quit and reopen the Spotify app, then connect again.
No audio at the receiver PTP status locked? Status → AES67 TX counting packets? The receiver on the same grandmaster and domain? After changing stream settings, re-import the SDP.
Stutter or dropouts Status → underruns rising? With HLS, check the internet connection. During a firmware upload short stutters are normal.
HLS stream doesn't start Check the URL in a browser. Status → Source shows buffering while it loads, usually for a few seconds.

Limitations

These are known limitations in the current firmware:

  • Autoplay stream on boot: the checkbox has no effect yet. HLS always starts on boot.
  • VLAN split (separate VLANs for AES67 and internet) isn't available yet.
  • No password on the web page or API.
  • HLS clock drift: the radio station's clock and PTP drift slightly apart. Over many hours of continuous playback, the stream can skip ahead to catch up with the live edge.