- Core config: cfg_mark_secret(group, key). GET /api/config returns ""
for secret keys; a POST with "" keeps the stored value, null clears it;
cfg_get() returns the real value. Documented in aes67-core-base.md.
- source.spotify_client_id / spotify_client_secret (secret write-only):
each user's own Spotify developer app, needed by the maintained cspot
fork (philippe44/cspot) since Spotify's 2025 API restrictions.
- UI: client ID field, password field for the secret ("leave empty to
keep"), link to developer.spotify.com; enabled for spotify/auto modes.
- status.spotify_state: "no client credentials" while either is missing.
- Verified: secret never appears in GET; UI-style re-save keeps it;
survives reboot; null clears it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- main/audio_ring: SPSC ring of interleaved int32 frames in PSRAM
(4 s at 48 kHz stereo), lock-free with acquire/release counters; the
TX pull callback never blocks.
- main/player: source selection from source.mode and the pull callback
for aes67_tx. tone -> the core's PTP-phased 1 kHz tone; off -> silence;
hls/spotify -> ring with 1 s prefill (silence while buffering is not an
underrun; running dry is, and prefills again). Status fields
active_source, source_state, spotify_state, buffer_ms. source config
applies live.
- New source.mode "tone" (validation, UI dropdown, doc) for commissioning.
- Temporary 440 Hz producer in hls mode (until the HLS player exists).
- Verified: tone 999.7 Hz -18 dBFS; off silent; hls 440.0 Hz with max
sample step 60816 (ideal sine 60825, i.e. no discontinuities), buffer
3983 ms, 0 underruns; spotify silent/not implemented.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- aes67_web/cfg.c: cfg_register(group, defaults, validate, apply),
cfg_override_defaults() for project defaults, cfg_get(). Stored values
are loaded on register and merged over defaults (known keys, matching
types). NVS keeps only keys that differ from defaults, one JSON string
per group, so new firmware defaults still reach untouched settings.
- POST /api/config: type check against defaults, per-group validation,
nothing stored unless every group passes; 400 "group.key: reason".
Unknown keys/groups are ignored. Returns the new config.
- Core groups registered by their components with the UI's ranges:
ptp (aes67_ptp), aes67 (aes67_tx, incl. multicast range and mono_sum
=> 1 channel), net/inet (aes67_net), log (aes67_syslog).
- Project: PROJECT.def overrides (hostname p4-aes67, name P4 AES67) and
the "source" group in main/project_cfg.c.
- Config is stored only; nothing is applied live yet.
- Verified on board: defaults, valid save, 8 rejected values (nothing
stored), persistence across reboot, restore to defaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>