pub struct Timeline { /* private fields */ }Expand description
Shared playback timeline used across stream layers.
Stores canonical committed playback position. The byte cursor lives
on the Source — sources own per-variant or
per-file atomic cursors and expose them through
Source::position /
Source::advance /
Source::set_position.
Implementations§
Source§impl Timeline
impl Timeline
pub fn new() -> Self
Sourcepub fn advance_committed_chunk(&self, pos: &ChunkPosition)
pub fn advance_committed_chunk(&self, pos: &ChunkPosition)
Advance the consumer’s playhead to the end of the consumed
region described by pos. pos.frame_offset + pos.frames
must equal the absolute frame the consumer has now finished
playing through; the decoder owns these numbers, callers do
not invent them.
committed_position_ns (UI) is derived from the new playhead
frame divided by pos.sample_rate. byte_position is set
from pos.source_byte_offset + pos.source_bytes when the
decoder reports absolute offsets (Apple, Android API 28+);
otherwise it is left untouched so the producer-side cursor
(Stream::try_read / Stream::seek) continues to drive it.
Validates against total_duration in dev/test builds: a chunk
pushing the playhead past the declared duration is a real
arithmetic bug — the decoder’s frame counter disagrees with
total_duration, somebody is wrong.
Sourcepub fn clear_seek_pending(&self, epoch: u64)
pub fn clear_seek_pending(&self, epoch: u64)
Clear seek-pending flag after the decoder successfully applied the seek.
Only clears if epoch matches the current seek epoch, preventing a
stale completion from clearing a newer seek.
Sourcepub fn commit_seek_landed(&self, pos: &ChunkPosition)
pub fn commit_seek_landed(&self, pos: &ChunkPosition)
Pin the playhead to the decoder’s actual landing frame after a
seek. Called by the worker once decoder.seek returns
[DecoderSeekOutcome::Landed] — the only authoritative source
for “where did we actually end up”. pos.frame_offset carries
the landed frame; pos.frames should be 0 (we have not yet
consumed any chunk, just repositioned). pos.source_byte_offset
(if known) is the byte offset the decoder is now reading from.
pub fn committed_position(&self) -> Duration
Sourcepub fn complete_seek(&self, epoch: u64)
pub fn complete_seek(&self, epoch: u64)
Complete a seek (FLUSH_STOP).
Clears flushing flag only if epoch is still current.
A superseding initiate_seek will have incremented the epoch,
preventing an older completion from clearing the new seek.
Uses a double-check to guard against the race where a new
initiate_seek fires between our epoch load and flushing store.
pub fn did_clear_pending_seek_epoch(&self, seek_epoch: u64) -> bool
Sourcepub fn did_take_decoder_node_seek(&self) -> bool
pub fn did_take_decoder_node_seek(&self) -> bool
Consume the decoder-node seek latch with an Acquire swap.
Independent from take_seek_preempt: the inner audio source
consumes that one inside step_track, while DecoderNode (the
wrapping scheduler node) needs its own signal so it can reset
preload state and drop parked chunks on a new epoch. true
here means seek_epoch was just bumped and the node must run
the cleanup branch; otherwise the tick falls through.
Sourcepub fn did_take_seek_preempt(&self) -> bool
pub fn did_take_seek_preempt(&self) -> bool
Consume the seek-preempt latch with an Acquire swap.
Returns true exactly once per initiate_seek call: the worker
uses this to short-circuit step_track’s preempt guard without
dereferencing two Arc<AtomicU64>s. The Acquire ordering
synchronises with the Release in initiate_seek so observing
true here means the new seek_epoch and seek_target_ns
stores are also visible.
Sourcepub fn initiate_seek(&self, target: Duration) -> u64
pub fn initiate_seek(&self, target: Duration) -> u64
Initiate a seek (FLUSH_START).
Sets flushing flag, records target position, increments epoch.
All blocking reads (wait_range) will observe is_flushing() and abort.
Returns the new seek epoch.
§Panics
Panics if target overflows u64::MAX nanoseconds (≈584 years —
not reachable for any realistic seek target).
Sourcepub fn is_flushing(&self) -> bool
pub fn is_flushing(&self) -> bool
Check if the pipeline is being flushed (seek pending).
Sourcepub fn is_playing(&self) -> bool
pub fn is_playing(&self) -> bool
Whether the audio FSM has claimed this Timeline as the currently active decode target.
Written by the audio pipeline (StreamAudioSource) on entry into
a decode-producing state and cleared on EOF / failure / unload.
Read by the Downloader peer implementations to decide whether a
track’s fetches should be routed to the high-priority slot.
Sourcepub fn is_seek_pending(&self) -> bool
pub fn is_seek_pending(&self) -> bool
Check if a seek has been initiated but not yet applied by the decoder.
Unlike is_flushing() (which gates I/O via wait_range), this flag
stays set until the decoder successfully repositions. Used by the worker
loop to trigger seek retry.
pub fn mark_pending_seek_epoch(&self, seek_epoch: u64)
pub fn pending_seek_epoch(&self) -> Option<u64>
Sourcepub fn seek_epoch(&self) -> u64
pub fn seek_epoch(&self) -> u64
Read the current seek epoch.
Sourcepub fn seek_epoch_handle(&self) -> Arc<AtomicU64> ⓘ
pub fn seek_epoch_handle(&self) -> Arc<AtomicU64> ⓘ
Cheap clone of the shared atomic seek epoch — same use case.
Sourcepub fn seek_target(&self) -> Option<Duration>
pub fn seek_target(&self) -> Option<Duration>
Read the pending seek target position.
Sourcepub fn set_committed_position(&self, position: Duration)
pub fn set_committed_position(&self, position: Duration)
§Panics
Panics if position overflows u64::MAX nanoseconds (≈584 years);
no realistic media stream can hit this.
Sourcepub fn set_download_position(&self, position: u64)
pub fn set_download_position(&self, position: u64)
Report the current download byte position. The value is not
stored on the timeline — it exists only as a USDT probe point
(#[kithara::probe]) for download-progress observability.
Sourcepub fn set_playing(&self, playing: bool)
pub fn set_playing(&self, playing: bool)
Toggle the PLAYING flag.
Orthogonal to FLUSHING / SEEK_PENDING: toggling PLAYING
does not affect the seek state.