Files
Psychotoxical-psysonic/src-tauri/crates/psysonic-audio/src/state.rs
T
cucadmuh 6ea0acede5 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.
2026-05-16 22:56:47 +03:00

33 lines
1.3 KiB
Rust

//! Small shared structs for preload / gapless chain metadata.
use std::sync::atomic::{AtomicBool, AtomicU64};
use std::sync::Arc;
pub(crate) struct PreloadedTrack {
pub(crate) url: String,
pub(crate) data: Vec<u8>,
}
/// Completed ranged stream too large for `stream_completed_cache`; bytes live on disk.
pub(crate) struct StreamCompletedSpill {
pub(crate) url: String,
pub(crate) path: std::path::PathBuf,
}
/// Info about the track that has been appended (chained) to the current Sink
/// but whose source has not yet started playing (gapless mode only).
pub(crate) struct ChainedInfo {
/// The URL that was chained — used by audio_play to detect a pre-chain hit.
pub(crate) url: String,
/// Raw file bytes (shared with the chained decoder). Lets manual skip reuse
/// them instead of re-downloading after dropping the Sink queue.
pub(crate) raw_bytes: Arc<Vec<u8>>,
pub(crate) duration_secs: f64,
pub(crate) replay_gain_linear: f32,
pub(crate) base_volume: f32,
/// Set by NotifyingSource when this chained track's source is exhausted.
pub(crate) source_done: Arc<AtomicBool>,
/// Atomic sample counter for this chained source (swapped into
/// samples_played on transition).
pub(crate) sample_counter: Arc<AtomicU64>,
}