pub struct Stream { /* private fields */ }Expand description
Time-synchronized PCM stream buffer.
The Stream is responsible for buffering decoded PCM chunks and delivering them to the
audio player in a way that remains synchronized with the server’s time. It implements
the same synchronization strategy as the original C++ Snapcast client.
§Synchronization Strategy
There are two main modes of synchronization:
- Hard Sync: Used when the client is far out of sync (> 50ms) or just starting. In this mode, the stream skips forward in the buffer or inserts silence to reach the desired target time exactly.
- Soft Sync: Used for fine-tuning when the drift is small (typically < 10ms). Instead of jumping, the stream subtly adjusts the playback rate (e.g., by 0.05%) by adding or removing single samples at regular intervals. This is inaudible to most listeners.
§Drift Detection
Synchronization is based on “age”, which is the difference between when a sample should have been played (server time) and when it is being played (now).
The stream maintains three DoubleBuffer instances to track drift over different timescales:
- Mini Buffer (20 samples): Fast reaction to sudden network or system jitter.
- Short Buffer (100 samples): Used for calculating soft sync rate corrections.
- Long Buffer (500 samples): Long-term stability tracking and hard sync re-triggering.
The median value of these buffers is used to filter out outliers and ensure stable synchronization even in unstable network conditions.
Implementations§
Source§impl Stream
impl Stream
Sourcepub fn new(format: SampleFormat) -> Self
pub fn new(format: SampleFormat) -> Self
Create a new stream for the given sample format.
Sourcepub fn with_encoding(format: SampleFormat, encoding: SampleEncoding) -> Self
pub fn with_encoding(format: SampleFormat, encoding: SampleEncoding) -> Self
Create a new stream for the given sample format and sample encoding.
Sourcepub fn format(&self) -> SampleFormat
pub fn format(&self) -> SampleFormat
Returns the sample format.
Sourcepub fn encoding(&self) -> SampleEncoding
pub fn encoding(&self) -> SampleEncoding
Returns the sample byte encoding.
Sourcepub fn set_buffer_ms(&mut self, ms: i64)
pub fn set_buffer_ms(&mut self, ms: i64)
Set the target buffer size in milliseconds.
Sourcepub fn chunk_count(&self) -> usize
pub fn chunk_count(&self) -> usize
Number of queued chunks.
Sourcepub fn get_player_chunk(
&mut self,
server_now_usec: i64,
output_buffer_dac_time_usec: i64,
output: &mut [u8],
frames: u32,
) -> bool
pub fn get_player_chunk( &mut self, server_now_usec: i64, output_buffer_dac_time_usec: i64, output: &mut [u8], frames: u32, ) -> bool
Fill output with time-synchronized PCM data. Returns false if no data available.
Sourcepub fn get_silence(&self, output: &mut [u8], frames: u32)
pub fn get_silence(&self, output: &mut [u8], frames: u32)
Fill output with silence.
Sourcepub fn get_player_chunk_or_silence(
&mut self,
server_now_usec: i64,
output_buffer_dac_time_usec: i64,
output: &mut [u8],
frames: u32,
) -> bool
pub fn get_player_chunk_or_silence( &mut self, server_now_usec: i64, output_buffer_dac_time_usec: i64, output: &mut [u8], frames: u32, ) -> bool
Like get_player_chunk, but fills silence on failure.