use crate::{ProcessTimings, VadCapabilities, VadError, VoiceActivityDetector};
pub struct FrameAdapter {
inner: Box<dyn VoiceActivityDetector>,
capabilities: VadCapabilities,
buffer: Vec<i16>,
}
impl FrameAdapter {
pub fn new(inner: Box<dyn VoiceActivityDetector>) -> Self {
let capabilities = inner.capabilities();
Self {
inner,
capabilities,
buffer: Vec::new(),
}
}
pub fn capabilities(&self) -> &VadCapabilities {
&self.capabilities
}
pub fn sample_rate(&self) -> u32 {
self.capabilities.sample_rate
}
pub fn frame_size(&self) -> usize {
self.capabilities.frame_size
}
pub fn process(&mut self, samples: &[i16], sample_rate: u32) -> Result<Option<f32>, VadError> {
if sample_rate != self.capabilities.sample_rate {
return Err(VadError::InvalidSampleRate(sample_rate));
}
self.buffer.extend_from_slice(samples);
if self.buffer.len() >= self.capabilities.frame_size {
let frame: Vec<i16> = self.buffer.drain(..self.capabilities.frame_size).collect();
let probability = self.inner.process(&frame, sample_rate)?;
Ok(Some(probability))
} else {
Ok(None)
}
}
pub fn process_all(&mut self, samples: &[i16], sample_rate: u32) -> Result<Vec<f32>, VadError> {
if sample_rate != self.capabilities.sample_rate {
return Err(VadError::InvalidSampleRate(sample_rate));
}
self.buffer.extend_from_slice(samples);
let mut results = Vec::new();
while self.buffer.len() >= self.capabilities.frame_size {
let frame: Vec<i16> = self.buffer.drain(..self.capabilities.frame_size).collect();
let probability = self.inner.process(&frame, sample_rate)?;
results.push(probability);
}
Ok(results)
}
pub fn process_latest(&mut self, samples: &[i16], sample_rate: u32) -> Result<f32, VadError> {
let results = self.process_all(samples, sample_rate)?;
Ok(results.into_iter().last().unwrap_or(0.0))
}
pub fn reset(&mut self) {
self.buffer.clear();
self.inner.reset();
}
pub fn buffered_samples(&self) -> usize {
self.buffer.len()
}
pub fn timings(&self) -> ProcessTimings {
self.inner.timings()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockVad {
sample_rate: u32,
frame_size: usize,
call_count: usize,
}
impl MockVad {
fn new(sample_rate: u32, frame_size: usize) -> Self {
Self {
sample_rate,
frame_size,
call_count: 0,
}
}
}
impl VoiceActivityDetector for MockVad {
fn capabilities(&self) -> VadCapabilities {
VadCapabilities {
sample_rate: self.sample_rate,
frame_size: self.frame_size,
frame_duration_ms: (self.frame_size as u32 * 1000) / self.sample_rate,
}
}
fn process(&mut self, samples: &[i16], _sample_rate: u32) -> Result<f32, VadError> {
assert_eq!(samples.len(), self.frame_size);
self.call_count += 1;
Ok(0.5)
}
fn reset(&mut self) {
self.call_count = 0;
}
}
#[test]
fn test_adapter_buffers_samples() {
let mock = MockVad::new(16000, 512);
let mut adapter = FrameAdapter::new(Box::new(mock));
let result = adapter.process(&[0i16; 256], 16000).unwrap();
assert!(result.is_none());
assert_eq!(adapter.buffered_samples(), 256);
let result = adapter.process(&[0i16; 256], 16000).unwrap();
assert!(result.is_some());
assert_eq!(adapter.buffered_samples(), 0);
}
#[test]
fn test_adapter_handles_multiple_frames() {
let mock = MockVad::new(16000, 512);
let mut adapter = FrameAdapter::new(Box::new(mock));
let results = adapter.process_all(&[0i16; 1024], 16000).unwrap();
assert_eq!(results.len(), 2);
}
#[test]
fn test_adapter_wrong_sample_rate() {
let mock = MockVad::new(16000, 512);
let mut adapter = FrameAdapter::new(Box::new(mock));
let result = adapter.process(&[0i16; 512], 48000);
assert!(matches!(result, Err(VadError::InvalidSampleRate(48000))));
}
#[test]
fn test_adapter_reset() {
let mock = MockVad::new(16000, 512);
let mut adapter = FrameAdapter::new(Box::new(mock));
let _ = adapter.process(&[0i16; 256], 16000);
assert_eq!(adapter.buffered_samples(), 256);
adapter.reset();
assert_eq!(adapter.buffered_samples(), 0);
}
#[test]
fn test_process_latest() {
let mock = MockVad::new(16000, 512);
let mut adapter = FrameAdapter::new(Box::new(mock));
let result = adapter.process_latest(&[0i16; 1600], 16000).unwrap();
assert_eq!(result, 0.5); assert_eq!(adapter.buffered_samples(), 64); }
}