Source, state, artist/title/album, position and duration (from cspot's
playback state, so it matches the app), volume and `can`. cspot patch 0004
adds read getters for the playback state and context.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No Spotify session (or paused, with failover_on_pause) for failover_delay_s
switches to HLS; Spotify playing switches back within ~1 s. Switches fade
out/in over 30 ms and flush the ring. HLS is suspended while Spotify plays.
cspot is held back instead of drained while it isn't Spotify's turn: it keeps
decoding on pause, so dropping its frames let it race through the queue.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mac dropped the device soon after the first track change: we never
called SpircHandler::notifyAudioReachedPlayback(), so cspot's queue did
not advance and the state sent to Spotify stalled.
- The data callback records a boundary (output write position, track
id) when the track id changes; the session loop (<= 200 ms) calls
notifyAudioReachedPlayback(id) once playback (ring read position)
passes it, and notifyAudioEnded() after DEPLETED once the buffer is
empty. PLAYBACK_START clears boundaries (next data is a new one),
seek/flush drop pending ones.
- audio_ring exposes its write/read frame counters (wrap-safe compare).
- Verified: 10 min on the Mac without a disconnect, every track change
notified ("track audible, Spotify notified"), app shows the playing
track (switches up to ~3-5 s early), 0 underruns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Spotify AP reset the connection (recv -1, errno 104 ECONNRESET) on
the third Ping, every 6 minutes, like clockwork. cspot answered each
Ping at once; librespot (core/src/session.rs) waits 60 s:
Ping -> 60 s -> Pong -> PongAck -> 60 s -> Ping.
- 0003-delayed-pong: record the Ping, send the Pong 60 s later from
triggerTimeout() (called on every 3 s receive timeout), through the
PR #3 connection snapshot; dropped on reconnect.
- 0002-diag-log-recv-errors: log recv's return value/errno before
"Error in read" (error path only); this is what showed the RST.
Verified: over 8+ minutes Ping/delayed Pong/PongAck every 2 min, no
reset at the 6-minute mark.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MercurySession::reconnect() nulls conn/shanConn (for 5 s per failed
retry) while other tasks keep sending through them: a NULL dereference,
not a catchable exception. Our Spotify sessions are dropped by the
server and reconnect every ~6 minutes, so this race is hit regularly;
likely behind the sporadic resets during long sessions/OTA.
Patch applies cleanly to the pinned 3010349; builds, boots, confirmed.
Drop it once the fix is in the pinned cspot commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- OTA: the player now ends the Spotify session (spotify_suspend: stop
flag, waits until the session's tasks are gone, refuses new ones)
instead of pausing it, and suspends HLS. Pausing was not enough (an
upload still failed once with a paused session). Verified twice with a
session running for minutes: "Disconnecting mercury session / session
ended / suspended", installed in ~26 s, clean reboot.
- Volume: createFromBlob() starts cspot at volume 0, which the app
showed while we played at 100 %. The session now starts with the
player's volume (spotify_set_volume); volumes coming from the app are
stored exactly, without echo. Verified: slider starts at 100 %.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- spotify_init() sets up the logger, zeroconf routes and session task
once; spotify_apply() (at boot and on every source save) enables or
disables: enabled = mode spotify/auto + credentials. Disable removes
the mDNS entry, zeroconf answers 404 and a running session ends
(loop exits within 200 ms, SpircHandler::disconnect stops the queue
and player tasks). A new device name ends the session and
re-advertises. The login blob is swapped under a mutex.
- Verified: hls/spotify/rename switch the mDNS entry and /spotify_info
(404/200) live; switching to hls during Spotify playback ended the
session in < 2 s, HLS played after ~5 s, internal heap 221 -> 365 KB
(cspot frees everything).
- CLAUDE.md: OTA-with-session findings (intermittent, flash-write stalls
seen as TX resyncs during uploads), serial-port reset caveat.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An upload during an active Spotify session crawled (~10 kB/s, 197 s)
and ended in a reset (seen twice). Workaround:
- aes67_ota_on_update(cb): cb(true) right before an accepted upload
writes flash, cb(false) if it then fails.
- The player pauses Spotify (spotify_pause -> SpircHandler::setPause, the
app follows) and suspends HLS fetching (hls_suspend); resumed if the
upload fails. AES67 TX keeps running (silence).
- Verified: upload during Spotify playback paused the session and
installed in 25.8 s (normal for 2 MB), clean reboot and self-test.
Root cause still open (noted in CLAUDE.md with the other cspot items).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- spotify_init(pcm_cb, event_cb): cspot's data callback hands 44.1 kHz
stereo s16 PCM to the player and returns what was taken; the player's
blocking ring write paces decoding to playback speed.
- Events: FLUSH/SEEK/PLAYBACK_START empty the ring (skip/seek sound at
once); PLAY_PAUSE pauses output (silence, buffer kept, no underrun);
VOLUME logged (applied in b4).
- player: Spotify via its own audio_out converter (44.1 -> 48 kHz);
source_state playing / paused / buffering.
- Verified from a Mac: music on the AES67 stream (10 s: 0 gaps, no
silent packets, RMS -9.6 dBFS, peak 0.0 dBFS), buffer 4.0 s full,
0 underruns, pause/play/skip/seek events.
Seen: first 3 connects "Can't connect to spotify servers", 4th worked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Zeroconf on our httpd (GET/POST /spotify_info, form body URL-decoded)
and _spotify-connect._tcp via our mDNS (VERSION, CPath, Stack TXT).
- Session task: waits for the app's login blob, connects with the
user's client ID/secret and the configured bitrate (96/160/320 ->
OGG_VORBIS_*), SpircHandler, events logged; cspot exceptions caught.
Starts when source.mode is spotify/auto and credentials are set.
- bell::bellGlobalLogger was NULL: every CSPOT_LOG crashed the board
right after addUser (Load access fault in Session.cpp:67 /
LoginBlob.cpp:58). cspot/bell logs now go to esp_log (UART + syslog);
signed CDN URL tokens are cut from the log.
- esp_audio_codec's own Vorbis decoder clashed with bell's Tremor
symbols: CONFIG_AUDIO_DECODER_VORBIS_SUPPORT / SIMPLE_DEC_OGG off.
- status.spotify_state from the session (waiting / connecting /
connected / login failed / error / disabled / no client credentials).
- Verified from a Mac: device appears, "connected as <user>", access
token fetched with the user's client credentials, track info, audio
key, CDN URL (the step broken upstream), PCM decoded. Without
backpressure a track decodes in ~26 s (b3 feeds the ring).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>