gemini_genai_rs/buffer/
jitter.rs1use std::collections::VecDeque;
9use std::time::Instant;
10
11#[derive(Debug, Clone)]
13pub struct JitterConfig {
14 pub sample_rate: u32,
16 pub min_depth_samples: usize,
18 pub max_depth_samples: usize,
20 pub jitter_alpha: f64,
23 pub target_jitter_multiple: f64,
25}
26
27impl Default for JitterConfig {
28 fn default() -> Self {
29 Self {
30 sample_rate: 24000,
31 min_depth_samples: 24000 / 5, max_depth_samples: 24000 * 2, jitter_alpha: 0.125, target_jitter_multiple: 2.0,
35 }
36 }
37}
38
39impl JitterConfig {
40 pub fn for_sample_rate(sample_rate: u32) -> Self {
42 Self {
43 sample_rate,
44 min_depth_samples: sample_rate as usize / 5,
45 max_depth_samples: sample_rate as usize * 2,
46 ..Default::default()
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum BufferState {
54 Filling,
56 Playing,
58 Underrun,
60}
61
62pub struct AudioJitterBuffer {
64 config: JitterConfig,
65 queue: VecDeque<i16>,
66 state: BufferState,
67 jitter_estimate_us: f64,
69 last_arrival: Option<Instant>,
71 underrun_count: u64,
73}
74
75impl AudioJitterBuffer {
76 pub fn new(config: JitterConfig) -> Self {
78 let initial_capacity = config.max_depth_samples;
79 Self {
80 config,
81 queue: VecDeque::with_capacity(initial_capacity),
82 state: BufferState::Filling,
83 jitter_estimate_us: 0.0,
84 last_arrival: None,
85 underrun_count: 0,
86 }
87 }
88
89 pub fn state(&self) -> BufferState {
91 self.state
92 }
93
94 pub fn depth(&self) -> usize {
96 self.queue.len()
97 }
98
99 pub fn depth_ms(&self) -> f64 {
101 self.queue.len() as f64 / self.config.sample_rate as f64 * 1000.0
102 }
103
104 pub fn underrun_count(&self) -> u64 {
106 self.underrun_count
107 }
108
109 pub fn jitter_estimate_us(&self) -> f64 {
111 self.jitter_estimate_us
112 }
113
114 fn adaptive_min_depth(&self) -> usize {
116 let jitter_samples = (self.jitter_estimate_us / 1_000_000.0
117 * self.config.sample_rate as f64
118 * self.config.target_jitter_multiple) as usize;
119 jitter_samples.max(self.config.min_depth_samples)
120 }
121
122 pub fn push(&mut self, samples: &[i16]) {
124 let now = Instant::now();
126 if let Some(last) = self.last_arrival {
127 let interval_us = now.duration_since(last).as_micros() as f64;
128 let deviation = (interval_us - self.jitter_estimate_us).abs();
130 self.jitter_estimate_us = self.jitter_estimate_us * (1.0 - self.config.jitter_alpha)
131 + deviation * self.config.jitter_alpha;
132 }
133 self.last_arrival = Some(now);
134
135 let total_after = self.queue.len() + samples.len();
137 if total_after > self.config.max_depth_samples {
138 let to_drop = total_after - self.config.max_depth_samples;
139 self.queue.drain(..to_drop.min(self.queue.len()));
140 }
141
142 self.queue.extend(samples.iter());
144 while self.queue.len() > self.config.max_depth_samples {
145 self.queue.pop_front();
146 }
147
148 if (self.state == BufferState::Filling || self.state == BufferState::Underrun)
150 && self.queue.len() >= self.adaptive_min_depth()
151 {
152 self.state = BufferState::Playing;
153 }
154 }
155
156 pub fn pull(&mut self, out: &mut [i16]) -> usize {
163 match self.state {
164 BufferState::Filling => {
165 out.fill(0);
167 0
168 }
169 BufferState::Playing | BufferState::Underrun => {
170 let available = self.queue.len().min(out.len());
171 for (i, sample) in self.queue.drain(..available).enumerate() {
172 out[i] = sample;
173 }
174
175 if available < out.len() {
177 out[available..].fill(0);
178 if self.state == BufferState::Playing {
179 self.state = BufferState::Underrun;
180 self.underrun_count += 1;
181 }
182 } else if self.state == BufferState::Underrun
183 && self.queue.len() >= self.adaptive_min_depth()
184 {
185 self.state = BufferState::Playing;
186 }
187
188 available
189 }
190 }
191 }
192
193 pub fn flush(&mut self) {
198 self.queue.clear();
199 self.state = BufferState::Filling;
200 self.last_arrival = None;
201 }
202
203 pub fn reset(&mut self) {
205 self.flush();
206 self.jitter_estimate_us = 0.0;
207 self.underrun_count = 0;
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 fn make_buffer() -> AudioJitterBuffer {
216 AudioJitterBuffer::new(JitterConfig {
217 sample_rate: 16000,
218 min_depth_samples: 1600, max_depth_samples: 16000,
220 jitter_alpha: 0.125,
221 target_jitter_multiple: 2.0,
222 })
223 }
224
225 #[test]
226 fn starts_in_filling_state() {
227 let buf = make_buffer();
228 assert_eq!(buf.state(), BufferState::Filling);
229 assert_eq!(buf.depth(), 0);
230 }
231
232 #[test]
233 fn filling_produces_silence() {
234 let mut buf = make_buffer();
235 buf.push(&vec![42i16; 800]); let mut out = [0i16; 160];
238 let real = buf.pull(&mut out);
239 assert_eq!(real, 0);
240 assert!(out.iter().all(|&s| s == 0));
241 }
242
243 #[test]
244 fn transitions_to_playing() {
245 let mut buf = make_buffer();
246 buf.push(&vec![100i16; 1600]); assert_eq!(buf.state(), BufferState::Playing);
249
250 let mut out = [0i16; 160];
251 let real = buf.pull(&mut out);
252 assert_eq!(real, 160);
253 assert!(out.iter().all(|&s| s == 100));
254 }
255
256 #[test]
257 fn underrun_fills_silence() {
258 let mut buf = make_buffer();
259 buf.push(&vec![99i16; 1600]);
260 assert_eq!(buf.state(), BufferState::Playing);
261
262 let mut out = [0i16; 1600];
264 buf.pull(&mut out);
265
266 let mut out2 = [0i16; 160];
268 let real = buf.pull(&mut out2);
269 assert_eq!(real, 0);
270 assert_eq!(buf.state(), BufferState::Underrun);
271 assert_eq!(buf.underrun_count(), 1);
272 }
273
274 #[test]
275 fn flush_clears_and_resets() {
276 let mut buf = make_buffer();
277 buf.push(&vec![42i16; 3200]);
278 assert_eq!(buf.state(), BufferState::Playing);
279
280 buf.flush();
281 assert_eq!(buf.state(), BufferState::Filling);
282 assert_eq!(buf.depth(), 0);
283 }
284
285 #[test]
286 fn overflow_drops_oldest() {
287 let mut buf = AudioJitterBuffer::new(JitterConfig {
288 sample_rate: 16000,
289 min_depth_samples: 100,
290 max_depth_samples: 500,
291 ..Default::default()
292 });
293
294 buf.push(&vec![1i16; 400]);
295 buf.push(&vec![2i16; 200]); assert!(buf.depth() <= 500);
298
299 let mut out = [0i16; 500];
301 buf.pull(&mut out);
302 assert!(out[300..].iter().all(|&s| s == 2));
304 }
305
306 #[test]
307 fn depth_ms_calculation() {
308 let mut buf = make_buffer();
309 buf.push(&vec![0i16; 1600]); assert!((buf.depth_ms() - 100.0).abs() < 0.01);
311 }
312
313 #[test]
314 fn large_sample_exceeds_max_depth() {
315 let mut buf = AudioJitterBuffer::new(JitterConfig {
316 sample_rate: 16000,
317 min_depth_samples: 100,
318 max_depth_samples: 500,
319 ..Default::default()
320 });
321
322 buf.push(&vec![1i16; 200]);
324 assert_eq!(buf.depth(), 200);
325
326 buf.push(&vec![2i16; 600]);
329
330 assert!(
332 buf.depth() <= 500,
333 "Buffer depth {} exceeded max {} after large push",
334 buf.depth(),
335 500
336 );
337 }
338}