use bytes::Bytes;
#[derive(Clone, Debug, PartialEq)]
pub struct AudioFrame {
pub data: Bytes,
pub sample_rate: u32,
pub channels: u8,
pub duration_ms: u32,
}
impl AudioFrame {
pub fn new(data: impl Into<Bytes>, sample_rate: u32, channels: u8) -> Self {
let data = data.into();
let samples_per_channel =
if channels > 0 && sample_rate > 0 { data.len() / 2 / channels as usize } else { 0 };
let duration_ms = if sample_rate > 0 {
(samples_per_channel as u64 * 1000 / sample_rate as u64) as u32
} else {
0
};
Self { data, sample_rate, channels, duration_ms }
}
pub fn samples(&self) -> &[i16] {
if self.data.len() < 2 {
return &[];
}
let even_len = self.data.len() & !1;
bytemuck::cast_slice(&self.data[..even_len])
}
pub fn silence(sample_rate: u32, channels: u8, duration_ms: u32) -> Self {
let n_samples = (sample_rate as usize * channels as usize * duration_ms as usize) / 1000;
Self { data: Bytes::from(vec![0u8; n_samples * 2]), sample_rate, channels, duration_ms }
}
}
pub fn merge_frames(frames: &[AudioFrame]) -> AudioFrame {
if frames.is_empty() {
return AudioFrame::new(Bytes::new(), 16000, 1);
}
let sample_rate = frames[0].sample_rate;
let channels = frames[0].channels;
let total_len: usize = frames.iter().map(|f| f.data.len()).sum();
let mut buf = Vec::with_capacity(total_len);
for f in frames {
buf.extend_from_slice(&f.data);
}
AudioFrame::new(Bytes::from(buf), sample_rate, channels)
}