use bitflags::bitflags;
use crate::silk::MAX_FRAMES_PER_PACKET;
use crate::silk::errors::SilkError;
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TocFlags: u8 {
const INBAND_FEC = 1 << 0;
const VAD0 = 1 << 1;
const VAD1 = 1 << 2;
const VAD2 = 1 << 3;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Toc {
pub frames_per_payload: usize,
pub flags: TocFlags,
}
impl Toc {
pub fn vad_flag(&self) -> bool {
self.flags
.intersects(TocFlags::VAD0 | TocFlags::VAD1 | TocFlags::VAD2)
}
#[must_use]
pub fn vad_flags(&self) -> [bool; MAX_FRAMES_PER_PACKET] {
let mut out = [false; MAX_FRAMES_PER_PACKET];
for (idx, flag) in [TocFlags::VAD0, TocFlags::VAD1, TocFlags::VAD2]
.iter()
.enumerate()
{
out[idx] = self.flags.contains(*flag);
}
out
}
#[must_use]
pub fn inband_fec_flag(&self) -> bool {
self.flags.contains(TocFlags::INBAND_FEC)
}
}
impl Default for Toc {
fn default() -> Self {
Self {
frames_per_payload: 1,
flags: TocFlags::empty(),
}
}
}
pub fn silk_get_toc(payload: &[u8], frames_per_payload: usize) -> Result<Toc, SilkError> {
if payload.is_empty() || frames_per_payload > MAX_FRAMES_PER_PACKET {
return Err(SilkError::DecInvalidFrameSize);
}
let mut toc = Toc {
frames_per_payload,
flags: TocFlags::empty(),
};
let mut flags =
(payload[0] >> (7 - frames_per_payload)) & ((1 << (frames_per_payload + 1)) - 1);
if flags & 1 != 0 {
toc.flags.insert(TocFlags::INBAND_FEC);
}
for frame_idx in (0..frames_per_payload).rev() {
flags >>= 1;
let voiced = flags & 1 != 0;
if voiced {
match frame_idx {
0 => toc.flags.insert(TocFlags::VAD0),
1 => toc.flags.insert(TocFlags::VAD1),
2 => toc.flags.insert(TocFlags::VAD2),
_ => {}
}
}
}
Ok(toc)
}
#[cfg(test)]
mod tests {
use super::{Toc, TocFlags, silk_get_toc};
use crate::silk::MAX_FRAMES_PER_PACKET;
use crate::silk::errors::SilkError;
#[test]
fn rejects_empty_payloads() {
let err = silk_get_toc(&[], 1);
assert_eq!(err, Err(SilkError::DecInvalidFrameSize));
}
#[test]
fn rejects_excess_frames_per_payload() {
let payload = [0u8; 1];
let err = silk_get_toc(&payload, 4);
assert_eq!(err, Err(SilkError::DecInvalidFrameSize));
}
#[test]
fn decodes_toc_flags_for_single_frame() {
let payload = [0b1000_0000u8];
let toc = silk_get_toc(&payload, 1).unwrap();
assert_eq!(
toc,
Toc {
frames_per_payload: 1,
flags: TocFlags::VAD0
}
);
assert!(toc.vad_flag());
assert_eq!(toc.vad_flags(), [true, false, false]);
assert!(!toc.inband_fec_flag());
}
#[test]
fn decodes_toc_flags_for_three_frames() {
let payload = [0b0010_1000u8];
let toc = silk_get_toc(&payload, 3).unwrap();
assert_eq!(
toc,
Toc {
frames_per_payload: 3,
flags: TocFlags::VAD2
}
);
assert!(!toc.inband_fec_flag());
assert!(toc.vad_flag());
assert_eq!(toc.vad_flags(), [false, false, true]);
}
#[test]
fn vad_flags_are_zeroed_for_unused_frames() {
let payload = [0b1100_0000u8]; let toc = silk_get_toc(&payload, 1).unwrap();
let mut expected = [false; MAX_FRAMES_PER_PACKET];
expected[0] = true;
assert_eq!(toc.vad_flags(), expected);
assert!(toc.inband_fec_flag());
}
}