use crate::audio::types::AudioConfig;
pub struct AudioRingBuffer {
data: Vec<u8>,
capacity: usize,
write_pos: usize,
len: usize,
config: AudioConfig,
}
impl AudioRingBuffer {
pub fn new(config: AudioConfig, duration_secs: f64) -> Self {
let capacity =
(config.sample_rate as f64 * duration_secs) as usize * config.bytes_per_frame();
Self {
data: vec![0u8; capacity],
capacity,
write_pos: 0,
len: 0,
config,
}
}
pub fn push(&mut self, bytes: &[u8]) {
for &byte in bytes {
self.data[self.write_pos] = byte;
self.write_pos = (self.write_pos + 1) % self.capacity;
if self.len < self.capacity {
self.len += 1;
}
}
}
pub fn read_all(&self) -> Vec<u8> {
if self.len < self.capacity {
self.data[..self.len].to_vec()
} else {
let mut result = Vec::with_capacity(self.capacity);
result.extend_from_slice(&self.data[self.write_pos..]);
result.extend_from_slice(&self.data[..self.write_pos]);
result
}
}
pub fn duration_secs(&self) -> f64 {
let frame_size = self.config.bytes_per_frame();
if frame_size == 0 {
return 0.0;
}
let num_frames = self.len / frame_size;
num_frames as f64 / self.config.sample_rate as f64
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn is_full(&self) -> bool {
self.len >= self.capacity
}
pub fn clear(&mut self) {
self.write_pos = 0;
self.len = 0;
}
pub fn config(&self) -> &AudioConfig {
&self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ring_buffer_basic() {
let config = AudioConfig::speech(); let mut buf = AudioRingBuffer::new(config, 0.001);
assert!(buf.is_empty());
assert_eq!(buf.duration_secs(), 0.0);
buf.push(&[1, 2, 3, 4]);
assert_eq!(buf.len(), 4);
assert_eq!(buf.read_all(), vec![1, 2, 3, 4]);
}
#[test]
fn test_ring_buffer_wrap() {
let config = AudioConfig {
sample_rate: 4,
channels: 1,
sample_format: crate::audio::types::SampleFormat::I16,
};
let mut buf = AudioRingBuffer::new(config, 1.0);
assert_eq!(buf.capacity(), 8);
buf.push(&[1, 2, 3, 4, 5, 6, 7, 8]);
assert!(buf.is_full());
buf.push(&[9, 10]);
let data = buf.read_all();
assert_eq!(data, vec![3, 4, 5, 6, 7, 8, 9, 10]);
}
#[test]
fn test_ring_buffer_clear() {
let config = AudioConfig::speech();
let mut buf = AudioRingBuffer::new(config, 0.01);
buf.push(&[1, 2, 3, 4]);
buf.clear();
assert!(buf.is_empty());
assert_eq!(buf.len(), 0);
}
}