#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-opus-quantum -- Opus Audio Frame Handler with VAD
#[derive(Debug)] pub enum OpusError { InvalidToc(String), FrameTooShort(String) }
impl std::fmt::Display for OpusError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidToc(e)|Self::FrameTooShort(e) => write!(f, "{e}") } } }
impl std::error::Error for OpusError {}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OpusBandwidth { Narrowband, Mediumband, Wideband, Superwideband, Fullband }
impl OpusBandwidth { pub fn sample_rate(&self) -> u32 { match self { Self::Narrowband=>8000, Self::Mediumband=>12000, Self::Wideband=>16000, Self::Superwideband=>24000, Self::Fullband=>48000 } } }
#[derive(Debug, Clone)] pub struct OpusFrame { pub bandwidth: OpusBandwidth, pub channels: u8, pub frame_size_ms: f32, pub stereo: bool, pub payload: Vec<u8> }
pub fn decode_toc(toc: u8) -> Result<(OpusBandwidth, bool, u8), OpusError> {
    let config = (toc >> 3) & 0x1F;
    let stereo = (toc >> 2) & 1 == 1;
    let frame_code = toc & 0x03;
    let bw = match config {
        0..=3 => OpusBandwidth::Narrowband, 4..=7 => OpusBandwidth::Mediumband,
        8..=11 => OpusBandwidth::Wideband, 12..=15 => OpusBandwidth::Superwideband,
        16..=31 => OpusBandwidth::Fullband, _ => return Err(OpusError::InvalidToc(format!("config {config}")))
    };
    Ok((bw, stereo, frame_code))
}
pub fn encode_toc(bw: &OpusBandwidth, stereo: bool, frame_code: u8) -> u8 {
    let config: u8 = match bw { OpusBandwidth::Narrowband=>0, OpusBandwidth::Mediumband=>4, OpusBandwidth::Wideband=>8, OpusBandwidth::Superwideband=>12, OpusBandwidth::Fullband=>16 };
    (config << 3) | ((stereo as u8) << 2) | (frame_code & 0x03)
}
pub struct SilenceDetector { pub threshold: f64 }
impl SilenceDetector {
    pub fn new(threshold: f64) -> Self { Self { threshold } }
    pub fn is_silence(&self, samples: &[i16]) -> bool {
        if samples.is_empty() { return true; }
        let energy: f64 = samples.iter().map(|&s| (s as f64) * (s as f64)).sum::<f64>() / samples.len() as f64;
        energy.sqrt() < self.threshold
    }
}
#[cfg(test)] mod tests {
    use super::*;
    #[test] fn test_toc_roundtrip() { let toc = encode_toc(&OpusBandwidth::Fullband, true, 1); let (bw, st, fc) = decode_toc(toc).unwrap(); assert_eq!(bw, OpusBandwidth::Fullband); assert!(st); assert_eq!(fc, 1); }
    #[test] fn test_silence() { let d = SilenceDetector::new(100.0); assert!(d.is_silence(&[0, 1, -1, 0, 2])); assert!(!d.is_silence(&[10000, -10000, 8000])); }
}
