Why not a regular queue?
Standard FIFO queues grow unbounded on overrun and crash on underrun. Audio needs fixed-size circular buffers with read and write pointers that wrap. The buffer size sets your latency floor (e.g., 5ms at 48kHz = 240 samples).
Advertisement
The ring buffer pattern
pub struct RingBuf {
data: Vec, write: AtomicUsize, read: AtomicUsize,
cap: usize,
}
impl RingBuf {
pub fn write(&self, samples: &[f32]) -> usize {
// lock-free SPSC, returns bytes actually written
}
pub fn read(&self, out: &mut [f32]) -> usize {
// ditto
}
pub fn available_read(&self) -> usize { /* ... */ 0 }
} Advertisement
Clock drift correction
Your microphone clock and your speaker clock are not synchronized down to the last nanosecond. Over 10 minutes, a 50 ppm drift produces a 30 ms offset — enough to cause audible glitches. Use a small resampler running at ratio ~1.000005x to correct slow drift without sample drops.