use crate::bitdepth::{
BitDepthError, convert_float32_le_to_signed16_le, convert_float32_to_signed24,
};
use crate::packet::{Bandwidth, Mode};
use crate::resample;
use crate::silk::decoder as silk_decoder;
use log::{debug, trace};
const SILK_FRAME_SAMPLES: usize = 320;
const UPSAMPLE_FACTOR: usize = 3;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecoderError {
TooShortForTableOfContents,
UnsupportedFrameCode(u8),
UnsupportedConfigurationMode,
Silk(silk_decoder::DecodeError),
BitDepth(BitDepthError),
}
impl core::fmt::Display for DecoderError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::TooShortForTableOfContents => {
f.write_str("packet is too short to contain table of contents header")
}
Self::UnsupportedFrameCode(code) => {
write!(f, "unsupported frame code: {code}")
}
Self::UnsupportedConfigurationMode => f.write_str("unsupported configuration mode"),
Self::Silk(err) => write!(f, "silk decode error: {err}"),
Self::BitDepth(err) => write!(f, "bit depth conversion failed: {err:?}"),
}
}
}
impl core::error::Error for DecoderError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Silk(err) => Some(err),
Self::BitDepth(_err) => None,
_ => None,
}
}
}
impl From<silk_decoder::DecodeError> for DecoderError {
fn from(value: silk_decoder::DecodeError) -> Self {
Self::Silk(value)
}
}
impl From<BitDepthError> for DecoderError {
fn from(value: BitDepthError) -> Self {
Self::BitDepth(value)
}
}
#[derive(Debug, Clone, Copy)]
struct TableOfContentsHeader(u8);
impl TableOfContentsHeader {
fn new(byte: u8) -> Self {
Self(byte)
}
fn configuration(self) -> Configuration {
Configuration(self.0 >> 3)
}
fn is_stereo(self) -> bool {
(self.0 & 0b0000_0100) != 0
}
fn frame_code(self) -> FrameCountCodeDiscriminant {
match self.0 & 0b0000_0011 {
0 => FrameCountCodeDiscriminant::Single,
1 => FrameCountCodeDiscriminant::DoubleEqual,
2 => FrameCountCodeDiscriminant::DoubleDifferent,
_ => FrameCountCodeDiscriminant::Arbitrary,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum FrameCountCodeDiscriminant {
Single,
DoubleEqual,
DoubleDifferent,
Arbitrary,
}
#[derive(Debug, Clone, Copy)]
struct Configuration(u8);
impl Configuration {
fn mode(self) -> Option<Mode> {
let value = self.0;
match value {
0..=11 => Some(Mode::SILK),
12..=15 => Some(Mode::HYBRID),
16..=31 => Some(Mode::CELT),
_ => None,
}
}
fn frame_duration_nanoseconds(self) -> Option<u32> {
match self.0 {
16 | 20 | 24 | 28 => Some(2_500_000),
17 | 21 | 25 | 29 => Some(5_000_000),
0 | 4 | 8 | 12 | 14 | 18 | 22 | 26 | 30 => Some(10_000_000),
1 | 5 | 9 | 13 | 15 | 19 | 23 | 27 | 31 => Some(20_000_000),
2 | 6 => Some(40_000_000),
3 | 7 | 11 => Some(60_000_000),
_ => None,
}
}
fn bandwidth(self) -> Option<Bandwidth> {
match self.0 {
0..=3 => Some(Bandwidth::Narrow),
4..=7 => Some(Bandwidth::Medium),
8..=11 => Some(Bandwidth::Wide),
12..=13 => Some(Bandwidth::SuperWide),
14..=15 => Some(Bandwidth::Full),
16..=19 => Some(Bandwidth::Narrow),
20..=23 => Some(Bandwidth::Wide),
24..=27 => Some(Bandwidth::SuperWide),
28..=31 => Some(Bandwidth::Full),
_ => None,
}
}
}
pub struct Decoder {
silk_decoder: silk_decoder::Decoder,
silk_buffer: [f32; SILK_FRAME_SAMPLES],
}
impl Decoder {
pub fn new() -> Self {
Self {
silk_decoder: silk_decoder::DecoderBuilder::new().build(),
silk_buffer: [0.0; SILK_FRAME_SAMPLES],
}
}
fn decode_internal(&mut self, input: &[u8]) -> Result<(Bandwidth, bool), DecoderError> {
if input.is_empty() {
return Err(DecoderError::TooShortForTableOfContents);
}
let toc_header = TableOfContentsHeader::new(input[0]);
let configuration = toc_header.configuration();
let frame_code = toc_header.frame_code();
trace!(
"decode_internal: toc=0x{:02x}, frame_code={:?}, stereo={} configuration={:?}",
input[0],
frame_code,
toc_header.is_stereo(),
configuration
);
if frame_code != FrameCountCodeDiscriminant::Single {
debug!(
"decode_internal: unsupported frame code {:?} in header byte 0x{:02x}",
frame_code, input[0]
);
return Err(DecoderError::UnsupportedFrameCode(input[0] & 0b11));
}
let mode = configuration
.mode()
.ok_or(DecoderError::UnsupportedConfigurationMode)?;
if mode != Mode::SILK {
debug!(
"decode_internal: rejecting non-SILK mode {:?} from configuration {:?}",
mode, configuration
);
return Err(DecoderError::UnsupportedConfigurationMode);
}
let nanoseconds = configuration
.frame_duration_nanoseconds()
.ok_or(DecoderError::UnsupportedConfigurationMode)?;
let bandwidth = configuration
.bandwidth()
.ok_or(DecoderError::UnsupportedConfigurationMode)?;
let encoded_frame = &input[1..];
trace!(
"decode_internal: dispatching SILK frame with bandwidth {:?}, frame_ns={}, stereo={} (payload {} bytes)",
bandwidth,
nanoseconds,
toc_header.is_stereo(),
encoded_frame.len()
);
self.silk_decoder.decode(
encoded_frame,
&mut self.silk_buffer,
toc_header.is_stereo(),
nanoseconds,
bandwidth,
)?;
trace!(
"decode_internal: SILK decode complete (bandwidth {:?}, stereo={})",
bandwidth,
toc_header.is_stereo()
);
Ok((bandwidth, toc_header.is_stereo()))
}
pub fn decode(
&mut self,
input: &[u8],
out: &mut [u8],
) -> Result<(Bandwidth, bool), DecoderError> {
let (bandwidth, stereo) = self.decode_internal(input)?;
trace!(
"decode: converting frame to i16 PCM (bandwidth {:?}, stereo={}, out_len={})",
bandwidth,
stereo,
out.len()
);
convert_float32_le_to_signed16_le(&self.silk_buffer, out, UPSAMPLE_FACTOR)?;
Ok((bandwidth, stereo))
}
pub fn decode_float32(
&mut self,
input: &[u8],
out: &mut [f32],
) -> Result<(Bandwidth, bool), DecoderError> {
let (bandwidth, stereo) = self.decode_internal(input)?;
resample::up(&self.silk_buffer, out, UPSAMPLE_FACTOR);
trace!(
"decode_float32: upsampled frame (bandwidth {:?}, stereo={}, out_len={})",
bandwidth,
stereo,
out.len()
);
Ok((bandwidth, stereo))
}
pub fn decode_int24(
&mut self,
input: &[u8],
out: &mut [i32],
) -> Result<(Bandwidth, bool), DecoderError> {
let (bandwidth, stereo) = self.decode_internal(input)?;
convert_float32_to_signed24(&self.silk_buffer, out, UPSAMPLE_FACTOR)?;
Ok((bandwidth, stereo))
}
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_PACKET: &[u8] = &[0x48, 0x0B, 0xE4, 0xC1, 0x36, 0xEC, 0xC5, 0x80];
const STEREO_PACKET: &[u8] = &[0x4C, 0x0B, 0xE4, 0xC1, 0x36, 0xEC, 0xC5, 0x80];
const EXPECTED_FLOATS_PREFIX: &[f32] = &[
0.000023, 0.000025, 0.000027, -0.000018, 0.000025, -0.000021, 0.000021, -0.000024,
0.000021, 0.000021, -0.000022, -0.000026,
];
#[test]
fn decode_errors_when_packet_too_short() {
let mut decoder = Decoder::new();
let mut out = [0u8; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR * 2];
let err = decoder.decode(&[], &mut out).unwrap_err();
assert!(matches!(err, DecoderError::TooShortForTableOfContents));
}
#[test]
fn decode_errors_when_frame_code_unsupported() {
let mut decoder = Decoder::new();
let mut out = [0u8; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR * 2];
let packet = &[0x49, 0x00];
let err = decoder.decode(packet, &mut out).unwrap_err();
assert!(matches!(err, DecoderError::UnsupportedFrameCode(1)));
}
#[test]
fn decode_errors_when_configuration_not_silk() {
let mut decoder = Decoder::new();
let mut out = [0u8; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR * 2];
let packet = &[0x80, 0x00];
let err = decoder.decode(packet, &mut out).unwrap_err();
assert!(matches!(err, DecoderError::UnsupportedConfigurationMode));
}
#[test]
fn decode_float32_matches_expected_prefix() {
let mut decoder = Decoder::new();
let mut out = [0.0f32; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR];
let (bandwidth, stereo) = decoder
.decode_float32(TEST_PACKET, &mut out)
.expect("decoding should succeed");
assert_eq!(bandwidth, Bandwidth::Wide);
assert!(!stereo);
for (chunk, &expected) in out
.chunks_exact(UPSAMPLE_FACTOR)
.zip(EXPECTED_FLOATS_PREFIX.iter())
{
assert!((chunk[0] - expected).abs() < 1.0e-6);
}
}
#[test]
fn decode_int24_matches_expected_prefix() {
let mut decoder = Decoder::new();
let mut out = [0_i32; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR];
let (bandwidth, stereo) = decoder
.decode_int24(TEST_PACKET, &mut out)
.expect("decoding should succeed");
assert_eq!(bandwidth, Bandwidth::Wide);
assert!(!stereo);
const SCALE_FACTOR: f64 = 8_388_608.0;
for (sample, chunk) in decoder
.silk_buffer
.iter()
.zip(out.chunks_exact(UPSAMPLE_FACTOR))
{
let expected_scaled = libm::rint(f64::from(*sample) * SCALE_FACTOR) as i32;
assert_eq!(chunk, [expected_scaled; UPSAMPLE_FACTOR]);
}
}
#[test]
fn decode_propagates_silk_errors() {
let mut decoder = Decoder::new();
let mut out = [0.0f32; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR];
let err = decoder.decode_float32(STEREO_PACKET, &mut out).unwrap_err();
assert!(matches!(
err,
DecoderError::Silk(silk_decoder::DecodeError::StereoUnsupported)
));
}
#[test]
fn decode_returns_bandwidth_and_stereo_flag() {
let mut decoder = Decoder::new();
let mut out = [0u8; SILK_FRAME_SAMPLES * UPSAMPLE_FACTOR * 2];
let (bandwidth, stereo) = decoder
.decode(TEST_PACKET, &mut out)
.expect("decoding should succeed");
assert_eq!(bandwidth, Bandwidth::Wide);
assert!(!stereo);
assert!(out.iter().any(|&byte| byte != 0));
}
}