pub trait AudioSink: Send {
fn push(&mut self, samples: &[f32]) -> usize;
fn pending(&self) -> usize;
fn clear(&mut self);
fn set_paused(&mut self, paused: bool);
fn is_paused(&self) -> bool;
fn capacity(&self) -> usize;
fn total_written(&self) -> usize;
fn take_error(&mut self) -> Option<String> {
None
}
}
pub struct VecSink {
capacity: usize,
queued: usize,
pub written: Vec<f32>,
pub paused: bool,
}
impl VecSink {
pub fn new(capacity: usize) -> Self {
VecSink { capacity, queued: 0, written: Vec::new(), paused: false }
}
pub fn drain(&mut self, n: usize) {
self.queued = self.queued.saturating_sub(n);
}
}
impl AudioSink for VecSink {
fn push(&mut self, samples: &[f32]) -> usize {
let room = self.capacity.saturating_sub(self.queued);
let n = room.min(samples.len());
self.written.extend_from_slice(&samples[..n]);
self.queued += n;
n
}
fn pending(&self) -> usize {
self.queued
}
fn clear(&mut self) {
self.queued = 0;
}
fn set_paused(&mut self, paused: bool) {
self.paused = paused;
}
fn is_paused(&self) -> bool {
self.paused
}
fn capacity(&self) -> usize {
self.capacity
}
fn total_written(&self) -> usize {
self.written.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vec_sink_accepts_up_to_capacity() {
let mut s = VecSink::new(4);
assert_eq!(s.push(&[1.0, 2.0]), 2);
assert_eq!(s.push(&[3.0, 4.0, 5.0]), 2, "only what fits is accepted");
assert_eq!(s.pending(), 4);
}
#[test]
fn vec_sink_records_everything_written() {
let mut s = VecSink::new(100);
s.push(&[1.0, 2.0]);
s.push(&[3.0]);
assert_eq!(s.written, vec![1.0, 2.0, 3.0]);
}
#[test]
fn vec_sink_clear_empties_pending_but_keeps_the_record() {
let mut s = VecSink::new(100);
s.push(&[1.0, 2.0]);
s.clear();
assert_eq!(s.pending(), 0);
assert_eq!(s.written, vec![1.0, 2.0], "written is the test's transcript");
}
#[test]
fn vec_sink_tracks_pause_state() {
let mut s = VecSink::new(4);
assert!(!s.paused);
s.set_paused(true);
assert!(s.paused);
}
#[test]
fn vec_sink_drain_simulates_playback() {
let mut s = VecSink::new(10);
s.push(&[1.0, 2.0, 3.0]);
s.drain(2);
assert_eq!(s.pending(), 1);
}
#[test]
fn vec_sink_total_written_survives_clear_and_drain() {
let mut s = VecSink::new(10);
s.push(&[1.0, 2.0, 3.0]);
s.drain(2);
s.push(&[4.0]);
s.clear();
assert_eq!(s.total_written(), 4, "total_written never goes down");
}
}