1use std::collections::VecDeque;
9use std::sync::Arc;
10
11use pipecrab_runtime::maybe_async_trait;
12
13use crate::{AudioChunk, AudioError, AudioFormat, AudioSink, AudioSource};
14
15pub struct MockSource {
17 format: AudioFormat,
18 queue: VecDeque<AudioChunk>,
19}
20
21impl MockSource {
22 pub fn new(format: AudioFormat, chunks: impl IntoIterator<Item = Arc<[f32]>>) -> Self {
25 let queue = chunks
26 .into_iter()
27 .map(|samples| AudioChunk::new(samples, format))
28 .collect();
29 Self { format, queue }
30 }
31
32 pub fn ramp(format: AudioFormat, chunk_frames: usize, chunks: usize) -> Self {
38 let mut queue = VecDeque::with_capacity(chunks);
39 for c in 0..chunks {
40 let start = (c * chunk_frames) as u32;
41 let samples: Arc<[f32]> = (0..chunk_frames)
42 .map(|i| (start + i as u32) as f32)
43 .collect();
44 queue.push_back(AudioChunk::new(samples, format));
45 }
46 Self { format, queue }
47 }
48}
49
50maybe_async_trait! {
51 impl AudioSource for MockSource {
52 fn format(&self) -> AudioFormat {
53 self.format
54 }
55
56 async fn next_chunk(&mut self) -> Result<Option<AudioChunk>, AudioError> {
57 Ok(self.queue.pop_front())
59 }
60 }
61}
62
63pub struct MockSink {
65 format: AudioFormat,
66 received: Vec<AudioChunk>,
67}
68
69impl MockSink {
70 pub fn new(format: AudioFormat) -> Self {
72 Self {
73 format,
74 received: Vec::new(),
75 }
76 }
77
78 pub fn chunks(&self) -> &[AudioChunk] {
80 &self.received
81 }
82
83 pub fn samples(&self) -> Vec<f32> {
85 self.received
86 .iter()
87 .flat_map(|c| c.samples.iter().copied())
88 .collect()
89 }
90}
91
92maybe_async_trait! {
93 impl AudioSink for MockSink {
94 fn format(&self) -> AudioFormat {
95 self.format
96 }
97
98 async fn play(&mut self, chunk: AudioChunk) -> Result<(), AudioError> {
99 self.received.push(chunk);
100 Ok(())
101 }
102 }
103}