use crate::range_decoder::RangeDecoder;
use crate::Error;
pub const SILK_MAX_FRAMES_PER_CHANNEL: usize = 3;
pub fn silk_frame_count(frame_size_tenths_ms: u16) -> Option<u8> {
match frame_size_tenths_ms {
100 | 200 => Some(1),
400 => Some(2),
600 => Some(3),
_ => None,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SilkChannelHeader {
pub vad_flags: u8,
pub lbrr_flag: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct PerFrameLbrr {
pub mid: u8,
pub side: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SilkHeaderBits {
pub num_silk_frames: u8,
pub mid: SilkChannelHeader,
pub side: Option<SilkChannelHeader>,
pub per_frame_lbrr: PerFrameLbrr,
}
impl SilkHeaderBits {
pub fn decode(
rd: &mut RangeDecoder<'_>,
num_silk_frames: u8,
stereo: bool,
) -> Result<Self, Error> {
if !(1..=3).contains(&num_silk_frames) {
return Err(Error::MalformedPacket);
}
let mid = decode_channel_header(rd, num_silk_frames);
let side = if stereo {
Some(decode_channel_header(rd, num_silk_frames))
} else {
None
};
let per_frame_lbrr = if num_silk_frames == 1 {
PerFrameLbrr {
mid: u8::from(mid.lbrr_flag),
side: side.as_ref().map(|s| u8::from(s.lbrr_flag)).unwrap_or(0),
}
} else {
let mid_bits = if mid.lbrr_flag {
decode_per_frame_lbrr(rd, num_silk_frames)
} else {
0
};
let side_bits = match side {
Some(s) if s.lbrr_flag => decode_per_frame_lbrr(rd, num_silk_frames),
_ => 0,
};
PerFrameLbrr {
mid: mid_bits,
side: side_bits,
}
};
Ok(Self {
num_silk_frames,
mid,
side,
per_frame_lbrr,
})
}
pub fn mid_vad(&self, idx: u8) -> bool {
idx < self.num_silk_frames && (self.mid.vad_flags >> idx) & 1 == 1
}
pub fn side_vad(&self, idx: u8) -> bool {
match self.side {
Some(s) => idx < self.num_silk_frames && (s.vad_flags >> idx) & 1 == 1,
None => false,
}
}
pub fn mid_has_lbrr(&self, idx: u8) -> bool {
idx < self.num_silk_frames && (self.per_frame_lbrr.mid >> idx) & 1 == 1
}
pub fn side_has_lbrr(&self, idx: u8) -> bool {
self.side.is_some()
&& idx < self.num_silk_frames
&& (self.per_frame_lbrr.side >> idx) & 1 == 1
}
}
fn decode_channel_header(rd: &mut RangeDecoder<'_>, num_silk_frames: u8) -> SilkChannelHeader {
let mut vad_flags: u8 = 0;
for i in 0..num_silk_frames {
let bit = rd.dec_bit_logp(1) as u8;
vad_flags |= bit << i;
}
let lbrr_flag = rd.dec_bit_logp(1) != 0;
SilkChannelHeader {
vad_flags,
lbrr_flag,
}
}
fn decode_per_frame_lbrr(rd: &mut RangeDecoder<'_>, num_silk_frames: u8) -> u8 {
let icdf = per_frame_lbrr_pdf(num_silk_frames);
let k = rd.dec_icdf(icdf, 8);
(k + 1) as u8
}
pub fn per_frame_lbrr_pdf(num_silk_frames: u8) -> &'static [u8] {
match num_silk_frames {
2 => PER_FRAME_LBRR_40MS_ICDF,
3 => PER_FRAME_LBRR_60MS_ICDF,
_ => &[],
}
}
pub(crate) const PER_FRAME_LBRR_40MS_ICDF: &[u8] = &[203, 150, 0];
pub(crate) const PER_FRAME_LBRR_60MS_ICDF: &[u8] = &[215, 195, 166, 125, 110, 82, 0];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn table4_40ms_pdf_truncation_is_correct() {
let pdf = [0u32, 53, 53, 150];
assert_eq!(pdf.iter().sum::<u32>(), 256);
let fh: [u32; 3] = [53, 106, 256];
let derived: [u8; 3] = [
(256 - fh[0]) as u8,
(256 - fh[1]) as u8,
(256 - fh[2]) as u8,
];
assert_eq!(derived, [203u8, 150, 0]);
assert_eq!(PER_FRAME_LBRR_40MS_ICDF, &derived);
for w in PER_FRAME_LBRR_40MS_ICDF.windows(2) {
assert!(w[0] > w[1]);
}
assert_eq!(*PER_FRAME_LBRR_40MS_ICDF.last().unwrap(), 0);
}
#[test]
fn table4_60ms_pdf_truncation_is_correct() {
let pdf = [0u32, 41, 20, 29, 41, 15, 28, 82];
assert_eq!(pdf.iter().sum::<u32>(), 256);
let fh: [u32; 7] = [41, 61, 90, 131, 146, 174, 256];
let derived: [u8; 7] = [
(256 - fh[0]) as u8,
(256 - fh[1]) as u8,
(256 - fh[2]) as u8,
(256 - fh[3]) as u8,
(256 - fh[4]) as u8,
(256 - fh[5]) as u8,
(256 - fh[6]) as u8,
];
assert_eq!(derived, [215u8, 195, 166, 125, 110, 82, 0]);
assert_eq!(PER_FRAME_LBRR_60MS_ICDF, &derived);
for w in PER_FRAME_LBRR_60MS_ICDF.windows(2) {
assert!(w[0] > w[1]);
}
assert_eq!(*PER_FRAME_LBRR_60MS_ICDF.last().unwrap(), 0);
}
#[test]
fn per_frame_lbrr_pdf_dispatch() {
assert_eq!(per_frame_lbrr_pdf(2), PER_FRAME_LBRR_40MS_ICDF);
assert_eq!(per_frame_lbrr_pdf(3), PER_FRAME_LBRR_60MS_ICDF);
assert_eq!(per_frame_lbrr_pdf(1), &[] as &[u8]);
assert_eq!(per_frame_lbrr_pdf(0), &[] as &[u8]);
assert_eq!(per_frame_lbrr_pdf(4), &[] as &[u8]);
}
#[test]
fn silk_frame_count_dispatch_matches_section_4_2_2() {
assert_eq!(silk_frame_count(100), Some(1));
assert_eq!(silk_frame_count(200), Some(1));
assert_eq!(silk_frame_count(400), Some(2));
assert_eq!(silk_frame_count(600), Some(3));
assert_eq!(silk_frame_count(25), None);
assert_eq!(silk_frame_count(50), None);
assert_eq!(silk_frame_count(0), None);
assert_eq!(silk_frame_count(1234), None);
}
#[test]
fn decode_mono_10ms_consumes_two_bits() {
let buf = [0x55u8; 16];
let mut rd = RangeDecoder::new(&buf);
let tell0 = rd.tell();
let h = SilkHeaderBits::decode(&mut rd, 1, false).expect("decode");
let tell1 = rd.tell();
assert_eq!(tell1 - tell0, 2);
assert_eq!(h.num_silk_frames, 1);
assert!(h.side.is_none());
assert!(h.mid.vad_flags <= 1);
}
#[test]
fn decode_stereo_60ms_path_smokes() {
let buf = [0xFFu8; 32];
let mut rd = RangeDecoder::new(&buf);
let h = SilkHeaderBits::decode(&mut rd, 3, true).expect("decode");
assert_eq!(h.num_silk_frames, 3);
assert!(h.side.is_some());
assert!(h.mid.vad_flags < 8, "mid VAD {:b}", h.mid.vad_flags);
assert!(
h.side.unwrap().vad_flags < 8,
"side VAD {:b}",
h.side.unwrap().vad_flags
);
assert!(h.per_frame_lbrr.mid < 8);
assert!(h.per_frame_lbrr.side < 8);
}
#[test]
fn decode_rejects_invalid_silk_frame_count() {
let buf = [0u8; 4];
let mut rd = RangeDecoder::new(&buf);
assert_eq!(
SilkHeaderBits::decode(&mut rd, 0, false),
Err(Error::MalformedPacket)
);
let mut rd = RangeDecoder::new(&buf);
assert_eq!(
SilkHeaderBits::decode(&mut rd, 4, false),
Err(Error::MalformedPacket)
);
}
#[test]
fn decode_10ms_per_frame_lbrr_mirrors_global_flag_no_extra_bits() {
let buf = [0xFFu8; 8];
let mut rd = RangeDecoder::new(&buf);
let tell0 = rd.tell();
let h = SilkHeaderBits::decode(&mut rd, 1, false).expect("decode");
let tell1 = rd.tell();
assert_eq!(tell1 - tell0, 2);
assert!(h.mid.lbrr_flag, "mid LBRR flag should be 1");
assert_eq!(h.per_frame_lbrr.mid, 1);
assert_eq!(h.per_frame_lbrr.side, 0);
assert!(h.mid_has_lbrr(0));
assert!(!h.mid_has_lbrr(1));
assert!(!h.side_has_lbrr(0));
}
#[test]
fn decode_60ms_skips_per_frame_lbrr_when_global_flag_unset() {
let buf = [0x00u8; 16];
let mut rd = RangeDecoder::new(&buf);
let tell0 = rd.tell();
let h = SilkHeaderBits::decode(&mut rd, 3, true).expect("decode");
let tell1 = rd.tell();
assert_eq!(tell1 - tell0, 8);
assert!(!h.mid.lbrr_flag);
assert!(!h.side.unwrap().lbrr_flag);
assert_eq!(h.per_frame_lbrr.mid, 0);
assert_eq!(h.per_frame_lbrr.side, 0);
assert_eq!(h.mid.vad_flags, 0);
assert_eq!(h.side.unwrap().vad_flags, 0);
}
#[test]
fn vad_accessors_match_bitmap_for_mid_and_side() {
let h = SilkHeaderBits {
num_silk_frames: 3,
mid: SilkChannelHeader {
vad_flags: 0b101,
lbrr_flag: true,
},
side: Some(SilkChannelHeader {
vad_flags: 0b010,
lbrr_flag: false,
}),
per_frame_lbrr: PerFrameLbrr {
mid: 0b110,
side: 0,
},
};
assert!(h.mid_vad(0));
assert!(!h.mid_vad(1));
assert!(h.mid_vad(2));
assert!(!h.mid_vad(3));
assert!(!h.side_vad(0));
assert!(h.side_vad(1));
assert!(!h.side_vad(2));
assert!(!h.mid_has_lbrr(0));
assert!(h.mid_has_lbrr(1));
assert!(h.mid_has_lbrr(2));
assert!(!h.side_has_lbrr(0));
assert!(!h.side_has_lbrr(1));
assert!(!h.side_has_lbrr(2));
}
#[test]
fn vad_accessors_zero_for_missing_side_channel() {
let h = SilkHeaderBits {
num_silk_frames: 1,
mid: SilkChannelHeader {
vad_flags: 1,
lbrr_flag: true,
},
side: None,
per_frame_lbrr: PerFrameLbrr { mid: 1, side: 0 },
};
assert!(!h.side_vad(0));
assert!(!h.side_has_lbrr(0));
}
#[test]
fn decode_per_frame_lbrr_40ms_never_returns_zero() {
for b0 in 0u16..=255 {
for b1 in [0x00u8, 0xFFu8, 0x55, 0xAA, 0x33] {
let buf = [b0 as u8, b1, 0x11, 0x22, 0x44, 0x88, 0x10, 0x20];
let mut rd = RangeDecoder::new(&buf);
let v = decode_per_frame_lbrr(&mut rd, 2);
assert!((1..=3).contains(&v), "40ms LBRR {v} out of 1..=3");
}
}
}
#[test]
fn decode_per_frame_lbrr_60ms_in_range() {
for b0 in 0u16..=255 {
for b1 in [0x00u8, 0xFFu8, 0x55, 0xAA, 0x33] {
let buf = [b0 as u8, b1, 0x11, 0x22, 0x44, 0x88, 0x10, 0x20];
let mut rd = RangeDecoder::new(&buf);
let v = decode_per_frame_lbrr(&mut rd, 3);
assert!((1..=7).contains(&v), "60ms LBRR {v} out of 1..=7");
}
}
}
#[test]
fn decode_per_frame_lbrr_60ms_covers_full_symbol_set() {
let mut seen = [false; 8];
for b0 in 0u16..=255 {
let buf = [
b0 as u8,
(b0 as u8) ^ 0x5A,
0xC3,
0x3C,
0x96,
0x69,
0xAA,
0x55,
];
let mut rd = RangeDecoder::new(&buf);
let v = decode_per_frame_lbrr(&mut rd, 3);
seen[v as usize] = true;
}
assert!(!seen[0], "value 0 should be unreachable");
for (v, hit) in seen.iter().enumerate().skip(1) {
assert!(*hit, "value {v} never decoded in 60ms LBRR sweep");
}
}
}