Skip to content

Buffer-depth-correct now-playing metadata (iOS + Android)#1

Open
jamneck wants to merge 4 commits into
mainfrom
vanguard-buffer-depth-fix
Open

Buffer-depth-correct now-playing metadata (iOS + Android)#1
jamneck wants to merge 4 commits into
mainfrom
vanguard-buffer-depth-fix

Conversation

@jamneck

@jamneck jamneck commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Correlates the wall-clock time of audio currently reaching the listener's ears against a public play_history feed, instead of trusting the live-edge /now-playing value directly — fixes now-playing being wrong for any listener whose HLS buffer lags the live edge.
  • iOS: AVPlayerItem.currentDate() (reads HLS PROGRAM-DATE-TIME, which MediaMTX already emits — no server pipeline change needed).
  • Android: Player.getCurrentLiveOffset() (Media3), via a thread-safe handoff to the main looper.
  • Both fall back to today's exact behavior whenever the correction can't be computed (no date/offset yet, no history match, or the station is in live DJ mode).
  • Adversarially reviewed (Codex, independent of the Grok 4.5 builders): found and fixed a real unsynchronized-cache race on both platforms (the history cache was written from one completion queue/thread and read from another with no lock) — now serialized on both.

Test plan

  • Android: ./gradlew compileDebugJavaWithJavac → BUILD SUCCESSFUL
  • iOS: swiftc -parse clean (full swift build/xcodebuild needs an installed iOS SDK not available in this sandbox — needs a real device/simulator build before shipping)
  • Manual: verify on a real device with an artificially throttled connection (deep buffer) that displayed title/artist matches the audio, not the live-edge song
  • Manual: verify live DJ broadcast mode is unaffected (should show liveTitle/liveDj as before)

🤖 Generated with Claude Code

jamneck and others added 4 commits July 9, 2026 17:08
Correlates AVPlayerItem.currentDate() (from HLS PROGRAM-DATE-TIME) against
the public play_history feed instead of trusting /now-playing's live-edge
value directly, so listeners whose buffer lags the live edge see the song
actually reaching their ears. Falls back to existing behavior whenever the
date/history isn't available or the station is in live DJ mode.

Reviewed against a Codex adversarial pass: fixed an unsynchronized-access
race on historyCache/historyFetchedAt (URLSession completion queues for
the now-playing poll and the play_history refresh both touch it), and
reordered so the history fetch only fires when a correction is actually
possible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Correlates Player.getCurrentLiveOffset() (Media3, thread-safe handoff to
the main looper) against the public play_history feed instead of trusting
/now-playing's live-edge value directly, so listeners whose buffer lags
the live edge see the song actually reaching their ears. Falls back to
existing behavior whenever the offset/history isn't available or the
station is in live DJ mode.

Reviewed against a Codex adversarial pass: fixed an unsynchronized-access
race on historyCache/historyFetchedAtMs (the metadata updater's executor
is a thread pool, not single-threaded, so overlapping polls could race),
and scoped the onMetadataUpdate JSON payload rewrite to only fire when a
correction actually happens (was previously unconditional).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant