mod common;
use common::*;
use opus_pure::Application;
fn fnv1a(data: &[u8]) -> u64 {
let mut h: u64 = 0xcbf2_9ce4_8422_2325;
for &b in data {
h ^= b as u64;
h = h.wrapping_mul(0x100_0000_01b3);
}
h
}
fn encode_stream(
rate: i32,
channels: usize,
app: Application,
bitrate: i32,
kind: &str,
frame_ms: i32,
) -> (Vec<u8>, bool) {
let frame = (rate * frame_ms / 1000) as usize;
let mono = if kind == "speech" {
speech_like(rate, rate as usize * 2)
} else {
music_like(rate, rate as usize * 2)
};
let pcm: Vec<f32> = if channels == 2 {
mono.iter().flat_map(|&s| [s, s * 0.8]).collect()
} else {
mono
};
let packets = Codec::new(rate, channels, app)
.frame_samples(frame)
.bitrate(bitrate)
.encode_all(&pcm);
let all_silk = packets.iter().all(|p| packet_mode(p) == "silk");
(packets.concat(), all_silk)
}
struct Frozen {
rate: i32,
channels: usize,
application: Application,
bitrate: i32,
content: &'static str,
frame_ms: i32,
hash: u64,
len: usize,
}
const FROZEN: &[Frozen] = &[
Frozen {
rate: 16_000,
channels: 1,
application: Application::Voip,
bitrate: 16_000,
content: "speech",
frame_ms: 20,
hash: 0x114b_965f_03ad_a54f,
len: 3140,
},
Frozen {
rate: 16_000,
channels: 1,
application: Application::Voip,
bitrate: 24_000,
content: "speech",
frame_ms: 20,
hash: 0xd1ac_f9fa_bc06_76d8,
len: 4752,
},
Frozen {
rate: 8_000,
channels: 1,
application: Application::Voip,
bitrate: 12_000,
content: "speech",
frame_ms: 20,
hash: 0xe832_89d1_489b_8307,
len: 2648,
},
Frozen {
rate: 48_000,
channels: 1,
application: Application::Audio,
bitrate: 64_000,
content: "music",
frame_ms: 20,
hash: 0xf460_5710_a4e4_f401,
len: 16100,
},
Frozen {
rate: 48_000,
channels: 2,
application: Application::Audio,
bitrate: 96_000,
content: "music",
frame_ms: 20,
hash: 0x5409_9062_2d28_dbe6,
len: 24100,
},
Frozen {
rate: 48_000,
channels: 2,
application: Application::Audio,
bitrate: 128_000,
content: "music",
frame_ms: 20,
hash: 0x1330_5dd3_02c1_f1a2,
len: 32100,
},
Frozen {
rate: 48_000,
channels: 1,
application: Application::Audio,
bitrate: 128_000,
content: "music",
frame_ms: 20,
hash: 0x7d26_9362_79ef_7dff,
len: 32100,
},
Frozen {
rate: 24_000,
channels: 1,
application: Application::Audio,
bitrate: 48_000,
content: "music",
frame_ms: 20,
hash: 0xe6a8_660c_5132_c125,
len: 12100,
},
Frozen {
rate: 16_000,
channels: 1,
application: Application::Voip,
bitrate: 24_000,
content: "speech",
frame_ms: 60,
hash: 0x80d7_c5bf_469c_d264,
len: 4520,
},
Frozen {
rate: 48_000,
channels: 1,
application: Application::Audio,
bitrate: 64_000,
content: "music",
frame_ms: 60,
hash: 0xf85a_841f_bd86_8035,
len: 15807,
},
Frozen {
rate: 48_000,
channels: 1,
application: Application::Audio,
bitrate: 64_000,
content: "music",
frame_ms: 100,
hash: 0xd0e6_552d_bf1c_ad2c,
len: 15940,
},
Frozen {
rate: 48_000,
channels: 2,
application: Application::Audio,
bitrate: 96_000,
content: "music",
frame_ms: 120,
hash: 0xf6bd_d5d7_d860_e829,
len: 22976,
},
Frozen {
rate: 48_000,
channels: 1,
application: Application::Voip,
bitrate: 20_000,
content: "speech",
frame_ms: 20,
hash: 0xb041_b110_172b_54d8,
len: 4055,
},
Frozen {
rate: 48_000,
channels: 2,
application: Application::Voip,
bitrate: 20_000,
content: "speech",
frame_ms: 20,
hash: 0x7418_e2b8_503c_1946,
len: 3991,
},
];
const FROZEN_ARCH: &str = "aarch64";
#[test]
fn bitstream_matches_the_frozen_reference() {
let same_arch = std::env::consts::ARCH == FROZEN_ARCH;
let mut drift = Vec::new();
for f in FROZEN {
let (bytes, all_silk) = encode_stream(
f.rate,
f.channels,
f.application,
f.bitrate,
f.content,
f.frame_ms,
);
let got = fnv1a(&bytes);
let label = format!(
"{}/{}ch/{:?}/{}/{}/{}ms",
f.rate, f.channels, f.application, f.bitrate, f.content, f.frame_ms
);
println!("{label:<44} -> {got:016x} ({} bytes)", bytes.len());
let hash_matters = same_arch || all_silk;
if (hash_matters && got != f.hash) || bytes.len() != f.len {
drift.push(format!(
"{label}: got {got:016x}/{} bytes, expected {:016x}/{} bytes",
bytes.len(),
f.hash,
f.len
));
}
}
assert!(
drift.is_empty(),
"encoder output moved on {}:\n {}\n\nIf the change is intentional, re-freeze the hashes \
above and record why in this file's header.",
std::env::consts::ARCH,
drift.join("\n ")
);
}
#[test]
fn encoding_is_deterministic() {
for f in FROZEN {
let once = encode_stream(
f.rate,
f.channels,
f.application,
f.bitrate,
f.content,
f.frame_ms,
);
let twice = encode_stream(
f.rate,
f.channels,
f.application,
f.bitrate,
f.content,
f.frame_ms,
);
assert_eq!(
once.0, twice.0,
"{} Hz {}ch {} bps {} ms is not reproducible",
f.rate, f.channels, f.bitrate, f.frame_ms
);
}
}