use opus_rs::{Application, OpusDecoder, OpusEncoder};
fn make_sine(sample_rate: i32, freq_hz: f32, n_samples: usize) -> Vec<f32> {
(0..n_samples)
.map(|i| {
let t = i as f32 / sample_rate as f32;
(2.0 * std::f32::consts::PI * freq_hz * t).sin() * 0.5
})
.collect()
}
fn encode_decode(
encoder: &mut OpusEncoder,
decoder: &mut OpusDecoder,
signal: &[f32],
frame_size: usize,
) -> Vec<f32> {
let n_frames = signal.len() / frame_size;
let mut packet_buf = vec![0u8; 2048];
let mut output = Vec::with_capacity(signal.len());
for f in 0..n_frames {
let frame = &signal[f * frame_size..(f + 1) * frame_size];
let len = encoder
.encode(frame, frame_size, &mut packet_buf)
.expect("encode failed");
let mut decoded = vec![0.0f32; frame_size];
decoder
.decode(&packet_buf[..len], frame_size, &mut decoded)
.expect("decode failed");
output.extend_from_slice(&decoded);
}
output
}
fn compute_snr(
input: &[f32],
output: &[f32],
active_start: usize,
active_end: usize,
max_delay: i32,
) -> f64 {
let mut best_corr = f64::NEG_INFINITY;
let mut best_delay = 0i32;
for delay in 0..=max_delay {
let mut corr = 0.0f64;
let mut cnt = 0usize;
for i in active_start..active_end {
let j = i as i32 + delay;
if j >= 0 && (j as usize) < output.len() {
corr += input[i] as f64 * output[j as usize] as f64;
cnt += 1;
}
}
if cnt > 0 {
corr /= cnt as f64;
}
if corr > best_corr {
best_corr = corr;
best_delay = delay;
}
}
let mut signal_e = 0.0f64;
let mut noise_e = 0.0f64;
for i in active_start..active_end {
let j = i as i32 + best_delay;
if j >= 0 && (j as usize) < output.len() {
let s = input[i] as f64;
let d = output[j as usize] as f64;
signal_e += s * s;
noise_e += (d - s) * (d - s);
}
}
if noise_e > 0.0 {
10.0 * (signal_e / noise_e).log10()
} else {
999.0
}
}
fn toc_config(toc: u8) -> u8 {
toc >> 3
}
fn toc_mode_name(toc: u8) -> &'static str {
match toc_config(toc) {
0..=11 => "SilkOnly",
12..=13 => "HybridSWB",
14..=15 => "HybridFB",
_ => "CeltOnly",
}
}
#[test]
fn test_mode_voip_16k_is_silk_only() {
let mut enc = OpusEncoder::new(16000, 1, Application::Voip).unwrap();
enc.bitrate_bps = 20000;
enc.use_cbr = true;
let input = make_sine(16000, 440.0, 320);
let mut buf = vec![0u8; 512];
enc.encode(&input, 320, &mut buf).unwrap();
assert_eq!(
toc_mode_name(buf[0]),
"SilkOnly",
"Voip 16 kHz must use SilkOnly, got config {}",
toc_config(buf[0])
);
}
#[test]
fn test_mode_voip_48k_is_hybrid_fb() {
let mut enc = OpusEncoder::new(48000, 1, Application::Voip).unwrap();
enc.bitrate_bps = 32000;
enc.use_cbr = true;
let input = make_sine(48000, 440.0, 960);
let mut buf = vec![0u8; 512];
enc.encode(&input, 960, &mut buf).unwrap();
assert_eq!(
toc_mode_name(buf[0]),
"HybridFB",
"Voip 48 kHz must use HybridFB, got config {}",
toc_config(buf[0])
);
}
#[test]
fn test_mode_audio_16k_is_silk_only() {
let mut enc = OpusEncoder::new(16000, 1, Application::Audio).unwrap();
enc.bitrate_bps = 24000;
enc.use_cbr = true;
let input = make_sine(16000, 440.0, 320);
let mut buf = vec![0u8; 512];
enc.encode(&input, 320, &mut buf).unwrap();
assert_eq!(
toc_mode_name(buf[0]),
"SilkOnly",
"Audio 16 kHz must use SilkOnly, got config {}",
toc_config(buf[0])
);
}
#[test]
fn test_mode_audio_48k_is_hybrid_fb_not_celt_only() {
let mut enc = OpusEncoder::new(48000, 1, Application::Audio).unwrap();
enc.bitrate_bps = 16000; enc.use_cbr = true;
let input = make_sine(48000, 440.0, 960);
let mut buf = vec![0u8; 512];
enc.encode(&input, 960, &mut buf).unwrap();
assert_eq!(
toc_mode_name(buf[0]),
"HybridFB",
"Audio 48 kHz at 16kbps must use HybridFB (not CeltOnly), got config {}",
toc_config(buf[0])
);
}
#[test]
fn test_snr_voip_16k() {
let sample_rate = 16000i32;
let frame_size = 320; let n_frames = 30;
let signal = make_sine(sample_rate, 440.0, n_frames * frame_size);
let mut enc = OpusEncoder::new(sample_rate, 1, Application::Voip).unwrap();
enc.bitrate_bps = 20000;
enc.use_cbr = true;
let mut dec = OpusDecoder::new(sample_rate, 1).unwrap();
let decoded = encode_decode(&mut enc, &mut dec, &signal, frame_size);
let snr = compute_snr(
&signal,
&decoded,
5 * frame_size,
n_frames * frame_size,
500,
);
println!("voip 16 kHz SNR: {snr:.2} dB (floor 11 dB)");
assert!(
snr >= 11.0,
"SNR regression: voip_16k = {snr:.2} dB < 11 dB floor"
);
}
#[test]
fn test_snr_voip_48k() {
let sample_rate = 48000i32;
let frame_size = 960; let n_frames = 30;
let signal = make_sine(sample_rate, 440.0, n_frames * frame_size);
let mut enc = OpusEncoder::new(sample_rate, 1, Application::Voip).unwrap();
enc.bitrate_bps = 32000;
enc.use_cbr = true;
let mut dec = OpusDecoder::new(sample_rate, 1).unwrap();
let decoded = encode_decode(&mut enc, &mut dec, &signal, frame_size);
let snr = compute_snr(
&signal,
&decoded,
5 * frame_size,
n_frames * frame_size,
1000,
);
println!("voip 48 kHz SNR: {snr:.2} dB (floor 11 dB)");
assert!(
snr >= 11.0,
"SNR regression: voip_48k = {snr:.2} dB < 11 dB floor"
);
}
#[test]
fn test_snr_audio_16k() {
let sample_rate = 16000i32;
let frame_size = 320; let n_frames = 30;
let signal = make_sine(sample_rate, 440.0, n_frames * frame_size);
let mut enc = OpusEncoder::new(sample_rate, 1, Application::Audio).unwrap();
enc.bitrate_bps = 24000;
enc.use_cbr = true;
let mut dec = OpusDecoder::new(sample_rate, 1).unwrap();
let decoded = encode_decode(&mut enc, &mut dec, &signal, frame_size);
let snr = compute_snr(
&signal,
&decoded,
5 * frame_size,
n_frames * frame_size,
500,
);
println!("audio 16 kHz SNR: {snr:.2} dB (floor 19 dB)");
assert!(
snr >= 19.0,
"SNR regression: audio_16k = {snr:.2} dB < 19 dB floor"
);
}
#[test]
fn test_snr_audio_48k() {
let sample_rate = 48000i32;
let frame_size = 960; let n_frames = 30;
let signal = make_sine(sample_rate, 440.0, n_frames * frame_size);
let mut enc = OpusEncoder::new(sample_rate, 1, Application::Audio).unwrap();
enc.bitrate_bps = 32000;
enc.use_cbr = true;
let mut dec = OpusDecoder::new(sample_rate, 1).unwrap();
let decoded = encode_decode(&mut enc, &mut dec, &signal, frame_size);
let snr = compute_snr(
&signal,
&decoded,
5 * frame_size,
n_frames * frame_size,
1000,
);
println!("audio 48 kHz SNR: {snr:.2} dB (floor 2 dB)");
assert!(
snr >= 2.0,
"SNR regression: audio_48k = {snr:.2} dB < 2 dB floor"
);
}