use rusty_opus::OpusDecoder;
use std::fs::File;
use std::io::{Read, Write};
fn main() {
let a: Vec<String> = std::env::args().collect();
let (rate, ch, drop_every): (i32, usize, usize) = (
a[1].parse().unwrap(),
a[2].parse().unwrap(),
a[4].parse().unwrap(),
);
let mut pcm_out = a
.get(5)
.map(|p| std::io::BufWriter::new(File::create(p).unwrap()));
let nodrop = std::env::var("NODROP").is_ok();
let mut data = Vec::new();
File::open(&a[3]).unwrap().read_to_end(&mut data).unwrap();
let mut dec = OpusDecoder::new(rate, ch).unwrap();
let fsz = rate as usize / 50; let mut out = vec![0f32; fsz * ch];
let (mut pos, mut n, mut lost, mut concealed_energy, mut concealed_frames) =
(0usize, 0usize, 0usize, 0f64, 0usize);
let mut plc_silent = 0usize;
while pos + 8 <= data.len() {
let ln =
u32::from_be_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]) as usize;
pos += 8;
let pkt = &data[pos..pos + ln];
pos += ln;
let drop = !nodrop && n % drop_every == (drop_every - 1);
let r = if drop {
lost += 1;
dec.decode(&[], fsz, &mut out)
} else {
dec.decode(pkt, fsz, &mut out)
};
if r.is_err() {
eprintln!("decode err at {n}: {r:?}");
std::process::exit(1);
}
if drop {
let e: f64 = out[..fsz * ch]
.iter()
.map(|&v| (v as f64) * (v as f64))
.sum();
concealed_energy += e;
concealed_frames += 1;
if e < 1e-6 {
plc_silent += 1;
}
}
if let Some(w) = pcm_out.as_mut() {
for &v in &out[..fsz * ch] {
let s = (v * 32768.0).clamp(-32768.0, 32767.0) as i16;
w.write_all(&s.to_le_bytes()).unwrap();
}
}
n += 1;
}
println!(
"packets={n} lost/concealed={lost} mean_concealed_energy={:.2} silent_conceals={plc_silent}/{concealed_frames}",
concealed_energy / concealed_frames.max(1) as f64
);
}
#[global_allocator]
static RUSTY_ALLOC: rusty_alloc_api::RustyAlloc = rusty_alloc_api::RustyAlloc;