mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
feat(playback): stream buffering UI, M4A moov-at-end streaming, hot-cache spill (#737)
* feat(playback): stream buffering UI, ranged M4A tail prefetch, demuxer fix Defer seekbar/progress until HTTP stream is armed for both legacy and RangedHttpSource; show buffering overlay on cover art. Add MP4 tail prefetch and Symphonia isomp4 bounded-mdat/moov-at-EOF probing so moov-at-end M4A can start without reading the full mdat. * feat(hot-cache): spill large ranged streams to disk for promote When a ranged HTTP download completes above the 64 MiB RAM promote cap, write the existing buffer once to app-data stream-spill/ and register it for hot-cache promote (rename) and replay via fetch_data. Analysis seeds from the spill file up to the local-file cap (512 MiB). * fix(ui): stream buffering — grayscale cover and static clock icon Desaturate player and queue cover art while isPlaybackBuffering; keep a non-animated clock overlay for visibility without the spinning animation. * fix(playback): review follow-up — tests, i18n, spill cleanup, changelog Clippy and test layout fixes; stream spill orphan cleanup on startup; buffering flag guard in progress handler; bufferingStream in all player locales; CHANGELOG and contributor credits for stream/M4A work. * docs: attribute stream buffering and M4A streaming to PR #737 * test(audio): avoid create_engine in stream spill unit test CI runners have no audio output device; test spill take/consume via the Mutex slot only, matching install_stream_completed_spill tests.
This commit is contained in:
@@ -42,7 +42,7 @@ export function useWaveformInterpolation({
|
||||
// On resume the first `tick` would add the entire pause duration to `elapsedSec` and
|
||||
// overshoot the playhead until the next transport heartbeat corrects it.
|
||||
const snap = getPlaybackProgressSnapshot();
|
||||
const raw = snap.progress;
|
||||
const raw = snap.buffering || snap.currentTime < 0.005 ? 0 : snap.progress;
|
||||
progressRef.current = raw;
|
||||
progressAnchorRef.current = {
|
||||
progress: raw,
|
||||
@@ -74,6 +74,15 @@ export function useWaveformInterpolation({
|
||||
rafId = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
const snap = getPlaybackProgressSnapshot();
|
||||
if (snap.buffering || snap.currentTime < 0.005) {
|
||||
progressRef.current = 0;
|
||||
visualTargetProgressRef.current = 0;
|
||||
visualProgressRef.current = 0;
|
||||
progressAnchorRef.current = { progress: 0, atMs: now };
|
||||
rafId = requestAnimationFrame(tick);
|
||||
return;
|
||||
}
|
||||
const anchor = progressAnchorRef.current;
|
||||
const elapsedSec = Math.max(0, (now - anchor.atMs) / 1000);
|
||||
const predicted = Math.max(0, Math.min(1, anchor.progress + elapsedSec / duration));
|
||||
|
||||
Reference in New Issue
Block a user