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 cancels: usize,
68}
69
70impl MockSink {
71 pub fn new(format: AudioFormat) -> Self {
73 Self {
74 format,
75 received: Vec::new(),
76 cancels: 0,
77 }
78 }
79
80 pub fn chunks(&self) -> &[AudioChunk] {
83 &self.received
84 }
85
86 pub fn samples(&self) -> Vec<f32> {
88 self.received
89 .iter()
90 .flat_map(|c| c.samples.iter().copied())
91 .collect()
92 }
93
94 pub fn cancels(&self) -> usize {
96 self.cancels
97 }
98}
99
100maybe_async_trait! {
101 impl AudioSink for MockSink {
102 fn format(&self) -> AudioFormat {
103 self.format
104 }
105
106 async fn play(&mut self, chunk: AudioChunk) -> Result<(), AudioError> {
107 self.received.push(chunk);
108 Ok(())
109 }
110
111 fn cancel(&mut self) {
112 self.cancels += 1;
113 }
114 }
115}