1use anyhow::Result;
7
8#[derive(Debug, Clone)]
10pub struct AudioBuffer {
11 pub samples: Vec<f32>,
12 pub channels: u16,
13 pub sample_rate: u32,
14}
15
16pub type AudioCallback = Box<dyn FnMut(&mut [f32]) + Send>;
18
19pub trait AudioBackend: Send {
22 fn start(&mut self, callback: AudioCallback) -> Result<()>;
24 fn stop(&mut self) -> Result<()>;
26 fn sample_rate(&self) -> u32;
28 fn buffer_size(&self) -> u32;
30 fn channels(&self) -> u16;
32}
33
34pub struct TestBackend {
36 sample_rate: u32,
37 buffer_size: u32,
38 channels: u16,
39 captured: Vec<f32>,
40}
41
42impl TestBackend {
43 pub fn new(sample_rate: u32, buffer_size: u32, channels: u16) -> Self {
44 Self {
45 sample_rate,
46 buffer_size,
47 channels,
48 captured: Vec::new(),
49 }
50 }
51
52 pub fn process_blocks(
54 &mut self,
55 num_buffers: usize,
56 mut callback: impl FnMut(&mut [f32]),
57 ) -> AudioBuffer {
58 let block_size = self.buffer_size as usize * self.channels as usize;
59 self.captured.clear();
60 self.captured.reserve(block_size * num_buffers);
61
62 for _ in 0..num_buffers {
63 let start = self.captured.len();
64 self.captured.resize(start + block_size, 0.0);
65 callback(&mut self.captured[start..]);
66 }
67
68 AudioBuffer {
69 samples: self.captured.clone(),
70 channels: self.channels,
71 sample_rate: self.sample_rate,
72 }
73 }
74}
75
76impl AudioBackend for TestBackend {
77 fn start(&mut self, _callback: Box<dyn FnMut(&mut [f32]) + Send>) -> Result<()> {
78 Ok(())
80 }
81
82 fn stop(&mut self) -> Result<()> {
83 Ok(())
84 }
85
86 fn sample_rate(&self) -> u32 {
87 self.sample_rate
88 }
89
90 fn buffer_size(&self) -> u32 {
91 self.buffer_size
92 }
93
94 fn channels(&self) -> u16 {
95 self.channels
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_backend_captures_silence() {
105 let mut backend = TestBackend::new(44100, 64, 2);
106 let result = backend.process_blocks(10, |_buf| {
107 });
109 assert_eq!(result.samples.len(), 64 * 2 * 10);
110 assert!(result.samples.iter().all(|&s| s == 0.0));
111 }
112
113 #[test]
114 fn test_backend_captures_signal() {
115 let mut backend = TestBackend::new(44100, 64, 1);
116 let mut phase = 0.0f32;
117 let result = backend.process_blocks(10, |buf| {
118 for sample in buf.iter_mut() {
119 *sample = phase.sin();
120 phase += 440.0 * std::f32::consts::TAU / 44100.0;
121 }
122 });
123 assert_eq!(result.samples.len(), 64 * 10);
124 assert!(result.samples.iter().any(|&s| s.abs() > 0.1));
126 assert!(result.samples.iter().all(|s| s.is_finite()));
128 }
129
130 #[test]
131 fn test_backend_correct_metadata() {
132 let backend = TestBackend::new(48000, 128, 2);
133 assert_eq!(backend.sample_rate(), 48000);
134 assert_eq!(backend.buffer_size(), 128);
135 assert_eq!(backend.channels(), 2);
136 }
137}