use crate::frames::OpusPacket;
use crate::framing::{OperatingMode, OpusFrameRouting};
use crate::toc::ChannelMapping;
use crate::Error;
pub const OUTPUT_SAMPLE_RATE_HZ: u32 = 48_000;
pub const OUTPUT_SAMPLES_PER_MS: u32 = OUTPUT_SAMPLE_RATE_HZ / 1000;
pub fn output_samples_per_channel(frame_size_tenths_ms: u16) -> usize {
(frame_size_tenths_ms as usize * OUTPUT_SAMPLES_PER_MS as usize) / 10
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameDecodeStatus {
DtxOrLost,
LayerNotWired(OperatingMode),
SilkParamsDecoded,
SilkStereoDecoded,
SilkDecodeError,
CeltSilence,
CeltDecodeError,
CeltCoarseEnergyDecoded,
CeltAllocationDecoded,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FrameOutcome {
pub samples_per_channel: usize,
pub status: FrameDecodeStatus,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DecodedAudio {
pub pcm: Vec<i16>,
pub channels: u8,
pub sample_rate_hz: u32,
pub frame_outcomes: Vec<FrameOutcome>,
}
impl DecodedAudio {
pub fn samples_per_channel(&self) -> usize {
self.pcm.len() / self.channels.max(1) as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FecDecodeStatus {
Recovered,
NoLbrr,
NotSilk,
DecodeError,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FecRecovered {
pub pcm: Vec<i16>,
pub channels: u8,
pub sample_rate_hz: u32,
pub status: FecDecodeStatus,
}
#[derive(Debug, Default)]
pub struct OpusDecoder {
last_channels: Option<u8>,
silk_synth_mono: Option<crate::silk_synthesis::SilkSynthState>,
silk_synth_stereo: Option<(
crate::silk_synthesis::SilkSynthState,
crate::silk_synthesis::SilkSynthState,
)>,
silk_stereo_unmix: Option<crate::silk_stereo::StereoUnmixState>,
prev_mode: Option<OperatingMode>,
celt_synth: Option<crate::celt_synthesis::CeltSynthState>,
celt_coarse: Option<crate::celt_coarse_energy::CoarseEnergyState>,
}
impl OpusDecoder {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
*self = Self::default();
}
pub fn decode_packet(&mut self, packet: &[u8]) -> Result<DecodedAudio, Error> {
let parsed = OpusPacket::parse(packet)?;
self.decode_parsed_packet(parsed)
}
pub fn decode_self_delimited_packet(&mut self, packet: &[u8]) -> Result<DecodedAudio, Error> {
let parsed = crate::framing_self_delim::parse_self_delimited(packet)?.packet;
self.decode_parsed_packet(parsed)
}
fn decode_parsed_packet(&mut self, parsed: OpusPacket<'_>) -> Result<DecodedAudio, Error> {
let routing = OpusFrameRouting::from_toc(parsed.toc);
let channels = routing.channel_count();
let per_frame_samples = output_samples_per_channel(routing.frame_size_tenths_ms);
if let Some(prev_mode) = self.prev_mode {
let reset = crate::mode_transition_reset::decide_state_resets(
prev_mode,
routing.operating_mode,
crate::celt_redundancy::RedundancyDecision::NotPresent,
);
if reset.silk {
if let Some(state) = self.silk_synth_mono.as_mut() {
state.reset();
}
if let Some((mid, side)) = self.silk_synth_stereo.as_mut() {
mid.reset();
side.reset();
}
if let Some(unmix) = self.silk_stereo_unmix.as_mut() {
unmix.reset();
}
}
}
if self.last_channels.is_some_and(|c| c != channels) {
if let Some(unmix) = self.silk_stereo_unmix.as_mut() {
unmix.reset();
}
if let Some((mid, side)) = self.silk_synth_stereo.as_mut() {
mid.reset();
side.reset();
}
}
self.last_channels = Some(channels);
self.prev_mode = Some(routing.operating_mode);
let frame_slices = parsed.frames();
let mut pcm: Vec<i16> =
Vec::with_capacity(frame_slices.len() * per_frame_samples * channels as usize);
let mut frame_outcomes = Vec::with_capacity(frame_slices.len());
for frame in frame_slices {
let outcome = self.decode_one_frame(frame, &routing, &mut pcm);
frame_outcomes.push(outcome);
}
Ok(DecodedAudio {
pcm,
channels,
sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
frame_outcomes,
})
}
fn decode_one_frame(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
pcm: &mut Vec<i16>,
) -> FrameOutcome {
let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
let channels = routing.channel_count();
if frame.is_empty() {
push_silence(pcm, per_channel, channels);
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::DtxOrLost,
};
}
match routing.operating_mode {
OperatingMode::SilkOnly => self.decode_silk_only_frame(frame, routing, pcm),
OperatingMode::CeltOnly => self.decode_celt_only_frame(frame, routing, pcm),
OperatingMode::Hybrid => self.decode_hybrid_frame(frame, routing, pcm),
}
}
fn decode_silk_only_frame(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
pcm: &mut Vec<i16>,
) -> FrameOutcome {
let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
let channels = routing.channel_count();
let pcm_start = pcm.len();
push_silence(pcm, per_channel, channels);
if channels == 2 {
let status = match self.decode_silk_only_stereo(frame, routing) {
Ok((left, right, bandwidth)) => {
resample_stereo_to_output_i16(
&left,
&right,
bandwidth,
&mut pcm[pcm_start..pcm_start + per_channel * 2],
);
FrameDecodeStatus::SilkStereoDecoded
}
Err(_) => FrameDecodeStatus::SilkDecodeError,
};
return FrameOutcome {
samples_per_channel: per_channel,
status,
};
}
let status = match self.decode_silk_only_mono(frame, routing) {
Ok((internal, bandwidth)) => {
resample_internal_to_output_i16(
&internal,
bandwidth,
&mut pcm[pcm_start..pcm_start + per_channel],
);
FrameDecodeStatus::SilkParamsDecoded
}
Err(_) => FrameDecodeStatus::SilkDecodeError,
};
FrameOutcome {
samples_per_channel: per_channel,
status,
}
}
fn decode_silk_only_mono(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
) -> Result<(Vec<f32>, crate::toc::Bandwidth), Error> {
use crate::range_decoder::RangeDecoder;
use crate::silk_decode::{decode_silk_frame, SilkFrameConfig, SilkFrameDecoded};
use crate::silk_excitation::SilkFrameSize;
use crate::silk_frame::FrameKind;
use crate::silk_header::SilkHeaderBits;
use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
let bandwidth = routing
.silk_bandwidth
.ok_or(Error::MalformedPacket)?
.to_bandwidth();
let num_silk_frames = routing
.silk_frames_per_channel
.ok_or(Error::MalformedPacket)?;
let frame_size = if routing.frame_size_tenths_ms == 100 {
SilkFrameSize::TenMs
} else {
SilkFrameSize::TwentyMs
};
let mut rd = RangeDecoder::new(frame);
let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, false)?;
let mut lbrr_prev_gain: Option<u8> = None;
let mut lbrr_prev_lag: Option<i32> = None;
let mut lbrr_first = true;
for idx in 0..num_silk_frames {
if !header.mid_has_lbrr(idx) {
continue;
}
let cfg = SilkFrameConfig {
bandwidth,
frame_size,
voice_active: true, first_subframe_independent: lbrr_first || lbrr_prev_gain.is_none(),
previous_log_gain: lbrr_prev_gain,
previous_primary_lag: lbrr_prev_lag,
ltp_scaling_present: lbrr_first,
lsf_interp_after_reset: lbrr_first,
previous_nlsf_q15: None,
previous_nlsf_len: 0,
stereo: None,
};
let decoded = decode_silk_frame(&mut rd, cfg)?;
lbrr_prev_gain = Some(decoded.gains.last_log_gain());
lbrr_prev_lag = Some(decoded.ltp.primary_lag());
lbrr_first = false;
let _ = FrameKind::Lbrr; }
let mut prev_gain: Option<u8> = None;
let mut prev_lag: Option<i32> = None;
let mut prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]> = None;
let mut prev_nlsf_len = 0usize;
let mut first = true;
let mut decoded_frames: Vec<SilkFrameDecoded> =
Vec::with_capacity(num_silk_frames as usize);
for idx in 0..num_silk_frames {
let cfg = SilkFrameConfig {
bandwidth,
frame_size,
voice_active: header.mid_vad(idx),
first_subframe_independent: first || prev_gain.is_none(),
previous_log_gain: prev_gain,
previous_primary_lag: prev_lag,
ltp_scaling_present: first,
lsf_interp_after_reset: first || prev_nlsf.is_none(),
previous_nlsf_q15: prev_nlsf,
previous_nlsf_len: prev_nlsf_len,
stereo: None,
};
let decoded = decode_silk_frame(&mut rd, cfg)?;
prev_gain = Some(decoded.gains.last_log_gain());
prev_lag = Some(decoded.ltp.primary_lag());
prev_nlsf = Some(decoded.nlsf_q15);
prev_nlsf_len = decoded.d_lpc;
first = false;
decoded_frames.push(decoded);
}
if rd.has_error() {
return Err(Error::MalformedPacket);
}
let need_fresh = match &self.silk_synth_mono {
Some(s) => s.bandwidth() != bandwidth,
None => true,
};
if need_fresh {
self.silk_synth_mono = Some(SilkSynthState::new(bandwidth)?);
}
let state = self
.silk_synth_mono
.as_mut()
.expect("synth state set above");
let mut internal = Vec::new();
for decoded in &decoded_frames {
let frame_out = synthesize_silk_frame(bandwidth, frame_size, decoded, state)?;
internal.extend_from_slice(&frame_out);
}
Ok((internal, bandwidth))
}
#[allow(clippy::type_complexity)]
fn decode_silk_only_stereo(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
) -> Result<(Vec<f32>, Vec<f32>, crate::toc::Bandwidth), Error> {
use crate::range_decoder::RangeDecoder;
use crate::silk_decode::{decode_silk_frame, SilkFrameDecoded, StereoHeaderContext};
use crate::silk_excitation::SilkFrameSize;
use crate::silk_header::SilkHeaderBits;
use crate::silk_stereo::{stereo_ms_to_lr, StereoUnmixState, StereoWeightsQ13};
use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
let bandwidth = routing
.silk_bandwidth
.ok_or(Error::MalformedPacket)?
.to_bandwidth();
let num_silk_frames = routing
.silk_frames_per_channel
.ok_or(Error::MalformedPacket)?;
let frame_size = if routing.frame_size_tenths_ms == 100 {
SilkFrameSize::TenMs
} else {
SilkFrameSize::TwentyMs
};
let mut rd = RangeDecoder::new(frame);
let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, true)?;
let mut lbrr_mid = ChannelDecodeState::new();
let mut lbrr_side = ChannelDecodeState::new();
for idx in 0..num_silk_frames {
let mid_lbrr = header.mid_has_lbrr(idx);
let side_lbrr = header.side_has_lbrr(idx);
if mid_lbrr {
let stereo_ctx = StereoHeaderContext {
has_mid_only_flag: !side_lbrr,
};
let decoded = decode_silk_frame(
&mut rd,
lbrr_mid.config(bandwidth, frame_size, true, Some(stereo_ctx)),
)?;
lbrr_mid.advance(&decoded);
if side_lbrr {
let decoded = decode_silk_frame(
&mut rd,
lbrr_side.config(bandwidth, frame_size, true, None),
)?;
lbrr_side.advance(&decoded);
}
} else if side_lbrr {
let decoded = decode_silk_frame(
&mut rd,
lbrr_side.config(bandwidth, frame_size, true, None),
)?;
lbrr_side.advance(&decoded);
}
}
let mut mid_state = ChannelDecodeState::new();
let mut side_state = ChannelDecodeState::new();
let mut mid_frames: Vec<SilkFrameDecoded> = Vec::with_capacity(num_silk_frames as usize);
let mut side_frames: Vec<Option<SilkFrameDecoded>> =
Vec::with_capacity(num_silk_frames as usize);
let mut interval_weights: Vec<StereoWeightsQ13> =
Vec::with_capacity(num_silk_frames as usize);
for idx in 0..num_silk_frames {
let side_active = header.side_vad(idx);
let stereo_ctx = StereoHeaderContext {
has_mid_only_flag: !side_active,
};
let mid_decoded = decode_silk_frame(
&mut rd,
mid_state.config(bandwidth, frame_size, header.mid_vad(idx), Some(stereo_ctx)),
)?;
let w = mid_decoded.stereo_pred.map(|p| StereoWeightsQ13 {
w0_q13: p.w0_q13,
w1_q13: p.w1_q13,
});
interval_weights.push(w.unwrap_or_default());
let side_coded = side_active || mid_decoded.mid_only_flag == Some(false);
mid_state.advance(&mid_decoded);
mid_frames.push(mid_decoded);
if side_coded {
let side_decoded = decode_silk_frame(
&mut rd,
side_state.config(bandwidth, frame_size, header.side_vad(idx), None),
)?;
side_state.advance(&side_decoded);
side_frames.push(Some(side_decoded));
} else {
side_frames.push(None);
}
}
if rd.has_error() {
return Err(Error::MalformedPacket);
}
let need_fresh = match &self.silk_synth_stereo {
Some((m, _)) => m.bandwidth() != bandwidth,
None => true,
};
if need_fresh {
self.silk_synth_stereo = Some((
SilkSynthState::new(bandwidth)?,
SilkSynthState::new(bandwidth)?,
));
}
let (mid_synth, side_synth) = self
.silk_synth_stereo
.as_mut()
.expect("stereo synth state set above");
let unmix = self
.silk_stereo_unmix
.get_or_insert_with(StereoUnmixState::new);
let mut left = Vec::new();
let mut right = Vec::new();
for (idx, mid_frame) in mid_frames.iter().enumerate() {
let mid_out = synthesize_silk_frame(bandwidth, frame_size, mid_frame, mid_synth)?;
let n = mid_out.len();
let weights = interval_weights[idx];
let stereo = match &side_frames[idx] {
Some(side_frame) => {
let side_out =
synthesize_silk_frame(bandwidth, frame_size, side_frame, side_synth)?;
stereo_ms_to_lr(bandwidth, &mid_out, Some(&side_out), weights, unmix)?
}
None => {
side_synth.reset();
stereo_ms_to_lr(bandwidth, &mid_out, None, weights, unmix)?
}
};
debug_assert_eq!(stereo.left.len(), n);
left.extend_from_slice(&stereo.left);
right.extend_from_slice(&stereo.right);
}
Ok((left, right, bandwidth))
}
#[allow(clippy::too_many_arguments)]
fn decode_celt_tf_spread_allocation(
rd: &mut crate::range_decoder::RangeDecoder<'_>,
celt_size: crate::celt_band_layout::CeltFrameSize,
is_transient: bool,
channels: u8,
start: usize,
end: usize,
frame_size_bytes: u32,
) -> Result<(crate::celt_tf_decode::TfDecode, u8), ()> {
use crate::celt_cache_caps50::CacheCapsStereo;
let is_stereo = channels == 2;
let stereo_axis = if is_stereo {
CacheCapsStereo::Stereo
} else {
CacheCapsStereo::Mono
};
let lm = celt_size.column_index() as u32;
let band_count = end - start;
let tf = crate::celt_tf_decode::decode_tf(rd, celt_size, is_transient, start, end);
let spread = crate::celt_spreading::decode_spread(rd);
let mut caps: Vec<u32> = Vec::with_capacity(band_count);
let mut n_bins: Vec<u32> = Vec::with_capacity(band_count);
for band in start..end {
let bins = crate::celt_band_layout::celt_band_bins_per_channel(band, celt_size)
.ok_or(())? as u32;
let cap = crate::celt_cache_caps50::cap_for_band_bits(
lm,
stereo_axis,
band as u32,
channels as u32,
bins,
)
.map_err(|_| ())?;
caps.push(cap);
n_bins.push(bins);
}
let boosts = crate::celt_band_boost::decode_band_boosts(
rd,
start,
end,
&caps,
&n_bins,
frame_size_bytes,
)
.map_err(|_| ())?;
let _trim = crate::celt_alloc_trim::decode_alloc_trim(
rd,
rd.tell_frac(),
frame_size_bytes,
boosts.total_boost_eighth_bits,
)
.map_err(|_| ())?;
let _reservations = crate::celt_reservations::reserve_block(
frame_size_bytes,
rd.tell_frac(),
boosts.total_boost_eighth_bits,
celt_size,
is_transient,
is_stereo,
band_count as u32,
)
.map_err(|_| ())?;
Ok((tf, spread))
}
fn decode_celt_only_frame(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
pcm: &mut Vec<i16>,
) -> FrameOutcome {
use crate::celt_band_layout::CeltFrameSize;
let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
let channels = routing.channel_count();
let pcm_start = pcm.len();
push_silence(pcm, per_channel, channels);
let Some(celt_size) =
CeltFrameSize::from_frame_tenths_ms(routing.frame_size_tenths_ms as u32)
else {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::LayerNotWired(OperatingMode::CeltOnly),
};
};
let mut rd = crate::range_decoder::RangeDecoder::new(frame);
let prefix = crate::celt_frame_prefix::decode_celt_frame_prefix(&mut rd);
if rd.has_error() {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
let final_status = if prefix.silence {
FrameDecodeStatus::CeltSilence
} else {
if prefix.intra || self.celt_coarse.is_none() {
self.celt_coarse = Some(crate::celt_coarse_energy::CoarseEnergyState::new());
}
let coarse = self.celt_coarse.as_mut().expect("just built");
let start = crate::celt_band_layout::celt_first_coded_band(false);
let end = crate::celt_band_layout::celt_end_coded_band();
match coarse.decode_frame(&mut rd, celt_size, prefix.intra, start, end) {
Ok(_frame) => {
if rd.has_error() {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
match Self::decode_celt_tf_spread_allocation(
&mut rd,
celt_size,
prefix.transient,
channels,
start,
end,
frame.len() as u32,
) {
Ok((_tf, _spread)) => {
if rd.has_error() {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
FrameDecodeStatus::CeltAllocationDecoded
}
Err(()) => {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
}
}
Err(_) => {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
}
};
let needs_rebuild = match &self.celt_synth {
Some(s) => {
s.channels() != channels as usize
|| s.transform_half_len() != (celt_size.to_frame_tenths_ms() as usize * 48) / 10
}
None => true,
};
if needs_rebuild {
match crate::celt_synthesis::CeltSynthState::new(celt_size, false, channels as usize) {
Ok(s) => self.celt_synth = Some(s),
Err(_) => {
return FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
};
}
}
}
let synth = self.celt_synth.as_mut().expect("just built");
let coded_bands = synth.coded_bands();
let first = synth.first_coded_band();
let mut shape_storage: Vec<Vec<f64>> = Vec::with_capacity(coded_bands);
for band in first..(first + coded_bands) {
let bins = crate::celt_band_layout::celt_band_bins_per_channel(band, celt_size)
.unwrap_or(0) as usize;
shape_storage.push(vec![0.0_f64; bins]);
}
let shape_refs: Vec<&[f64]> = shape_storage.iter().map(Vec::as_slice).collect();
let energies = vec![0.0_f64; coded_bands];
let per_channel_args: Vec<(&[&[f64]], &[f64])> = (0..channels as usize)
.map(|_| (shape_refs.as_slice(), energies.as_slice()))
.collect();
match synth.synthesize_frame_interleaved_i16(&per_channel_args) {
Ok(pcm_frame) => {
let region = &mut pcm[pcm_start..pcm_start + per_channel * channels as usize];
let n = region.len().min(pcm_frame.len());
region[..n].copy_from_slice(&pcm_frame[..n]);
FrameOutcome {
samples_per_channel: per_channel,
status: final_status,
}
}
Err(_) => FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::CeltDecodeError,
},
}
}
pub fn decode_packet_fec(&mut self, packet: &[u8]) -> Result<FecRecovered, Error> {
let parsed = OpusPacket::parse(packet)?;
let routing = OpusFrameRouting::from_toc(parsed.toc);
let channels = routing.channel_count();
let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
let mut pcm = vec![0i16; per_channel * channels as usize];
if !matches!(
routing.operating_mode,
OperatingMode::SilkOnly | OperatingMode::Hybrid
) {
return Ok(FecRecovered {
pcm,
channels,
sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
status: FecDecodeStatus::NotSilk,
});
}
let Some(&frame) = parsed.frames().first() else {
return Ok(FecRecovered {
pcm,
channels,
sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
status: FecDecodeStatus::DecodeError,
});
};
if frame.is_empty() {
return Ok(FecRecovered {
pcm,
channels,
sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
status: FecDecodeStatus::NoLbrr,
});
}
let status = if channels == 2 {
match self.decode_silk_fec_stereo(frame, &routing) {
Ok(Some((left, right, bandwidth))) => {
resample_stereo_to_output_i16(&left, &right, bandwidth, &mut pcm);
FecDecodeStatus::Recovered
}
Ok(None) => FecDecodeStatus::NoLbrr,
Err(_) => FecDecodeStatus::DecodeError,
}
} else {
match self.decode_silk_fec_mono(frame, &routing) {
Ok(Some((internal, bandwidth))) => {
resample_internal_to_output_i16(&internal, bandwidth, &mut pcm);
FecDecodeStatus::Recovered
}
Ok(None) => FecDecodeStatus::NoLbrr,
Err(_) => FecDecodeStatus::DecodeError,
}
};
Ok(FecRecovered {
pcm,
channels,
sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
status,
})
}
fn decode_silk_fec_mono(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
) -> Result<Option<(Vec<f32>, crate::toc::Bandwidth)>, Error> {
use crate::range_decoder::RangeDecoder;
use crate::silk_decode::{decode_silk_frame, SilkFrameConfig, SilkFrameDecoded};
use crate::silk_excitation::SilkFrameSize;
use crate::silk_header::SilkHeaderBits;
use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
let bandwidth = routing
.silk_bandwidth
.ok_or(Error::MalformedPacket)?
.to_bandwidth();
let num_silk_frames = routing
.silk_frames_per_channel
.ok_or(Error::MalformedPacket)?;
let frame_size = if routing.frame_size_tenths_ms == 100 {
SilkFrameSize::TenMs
} else {
SilkFrameSize::TwentyMs
};
let mut rd = RangeDecoder::new(frame);
let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, false)?;
if !(0..num_silk_frames).any(|i| header.mid_has_lbrr(i)) {
return Ok(None);
}
let mut prev_gain: Option<u8> = None;
let mut prev_lag: Option<i32> = None;
let mut prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]> = None;
let mut prev_nlsf_len = 0usize;
let mut first = true;
let mut lbrr_frames: Vec<SilkFrameDecoded> = Vec::new();
for idx in 0..num_silk_frames {
if !header.mid_has_lbrr(idx) {
continue;
}
let cfg = SilkFrameConfig {
bandwidth,
frame_size,
voice_active: true, first_subframe_independent: first || prev_gain.is_none(),
previous_log_gain: prev_gain,
previous_primary_lag: prev_lag,
ltp_scaling_present: first,
lsf_interp_after_reset: first || prev_nlsf.is_none(),
previous_nlsf_q15: prev_nlsf,
previous_nlsf_len: prev_nlsf_len,
stereo: None,
};
let decoded = decode_silk_frame(&mut rd, cfg)?;
prev_gain = Some(decoded.gains.last_log_gain());
prev_lag = Some(decoded.ltp.primary_lag());
prev_nlsf = Some(decoded.nlsf_q15);
prev_nlsf_len = decoded.d_lpc;
first = false;
lbrr_frames.push(decoded);
}
if rd.has_error() {
return Err(Error::MalformedPacket);
}
if lbrr_frames.is_empty() {
return Ok(None);
}
let mut state = SilkSynthState::new(bandwidth)?;
let mut internal = Vec::new();
for decoded in &lbrr_frames {
let frame_out = synthesize_silk_frame(bandwidth, frame_size, decoded, &mut state)?;
internal.extend_from_slice(&frame_out);
}
self.silk_synth_mono = Some(state);
Ok(Some((internal, bandwidth)))
}
#[allow(clippy::type_complexity)]
fn decode_silk_fec_stereo(
&mut self,
frame: &[u8],
routing: &OpusFrameRouting,
) -> Result<Option<(Vec<f32>, Vec<f32>, crate::toc::Bandwidth)>, Error> {
use crate::range_decoder::RangeDecoder;
use crate::silk_decode::{decode_silk_frame, SilkFrameDecoded, StereoHeaderContext};
use crate::silk_excitation::SilkFrameSize;
use crate::silk_header::SilkHeaderBits;
use crate::silk_stereo::{stereo_ms_to_lr, StereoUnmixState, StereoWeightsQ13};
use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
let bandwidth = routing
.silk_bandwidth
.ok_or(Error::MalformedPacket)?
.to_bandwidth();
let num_silk_frames = routing
.silk_frames_per_channel
.ok_or(Error::MalformedPacket)?;
let frame_size = if routing.frame_size_tenths_ms == 100 {
SilkFrameSize::TenMs
} else {
SilkFrameSize::TwentyMs
};
let mut rd = RangeDecoder::new(frame);
let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, true)?;
let any_lbrr =
(0..num_silk_frames).any(|i| header.mid_has_lbrr(i) || header.side_has_lbrr(i));
if !any_lbrr {
return Ok(None);
}
let mut mid_state = ChannelDecodeState::new();
let mut side_state = ChannelDecodeState::new();
let mut mid_frames: Vec<SilkFrameDecoded> = Vec::new();
let mut side_frames: Vec<Option<SilkFrameDecoded>> = Vec::new();
let mut interval_weights: Vec<StereoWeightsQ13> = Vec::new();
for idx in 0..num_silk_frames {
let mid_lbrr = header.mid_has_lbrr(idx);
let side_lbrr = header.side_has_lbrr(idx);
if !mid_lbrr {
if side_lbrr {
let side_decoded = decode_silk_frame(
&mut rd,
side_state.config(bandwidth, frame_size, true, None),
)?;
side_state.advance(&side_decoded);
let _ = side_decoded;
}
continue;
}
let stereo_ctx = StereoHeaderContext {
has_mid_only_flag: !side_lbrr,
};
let mid_decoded = decode_silk_frame(
&mut rd,
mid_state.config(bandwidth, frame_size, true, Some(stereo_ctx)),
)?;
let w = mid_decoded.stereo_pred.map(|p| StereoWeightsQ13 {
w0_q13: p.w0_q13,
w1_q13: p.w1_q13,
});
interval_weights.push(w.unwrap_or_default());
let side_coded = side_lbrr || mid_decoded.mid_only_flag == Some(false);
mid_state.advance(&mid_decoded);
mid_frames.push(mid_decoded);
if side_coded {
let side_decoded = decode_silk_frame(
&mut rd,
side_state.config(bandwidth, frame_size, true, None),
)?;
side_state.advance(&side_decoded);
side_frames.push(Some(side_decoded));
} else {
side_frames.push(None);
}
}
if rd.has_error() {
return Err(Error::MalformedPacket);
}
if mid_frames.is_empty() {
return Ok(None);
}
let mut mid_synth = SilkSynthState::new(bandwidth)?;
let mut side_synth = SilkSynthState::new(bandwidth)?;
let mut unmix = StereoUnmixState::new();
let mut left = Vec::new();
let mut right = Vec::new();
for (idx, mid_frame) in mid_frames.iter().enumerate() {
let mid_out = synthesize_silk_frame(bandwidth, frame_size, mid_frame, &mut mid_synth)?;
let weights = interval_weights[idx];
let stereo = match &side_frames[idx] {
Some(side_frame) => {
let side_out =
synthesize_silk_frame(bandwidth, frame_size, side_frame, &mut side_synth)?;
stereo_ms_to_lr(bandwidth, &mid_out, Some(&side_out), weights, &mut unmix)?
}
None => {
side_synth.reset();
stereo_ms_to_lr(bandwidth, &mid_out, None, weights, &mut unmix)?
}
};
left.extend_from_slice(&stereo.left);
right.extend_from_slice(&stereo.right);
}
self.silk_synth_stereo = Some((mid_synth, side_synth));
self.silk_stereo_unmix = Some(unmix);
Ok(Some((left, right, bandwidth)))
}
fn decode_hybrid_frame(
&mut self,
_frame: &[u8],
routing: &OpusFrameRouting,
pcm: &mut Vec<i16>,
) -> FrameOutcome {
let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
push_silence(pcm, per_channel, routing.channel_count());
FrameOutcome {
samples_per_channel: per_channel,
status: FrameDecodeStatus::LayerNotWired(OperatingMode::Hybrid),
}
}
}
fn push_silence(pcm: &mut Vec<i16>, per_channel: usize, channels: u8) {
pcm.resize(pcm.len() + per_channel * channels as usize, 0);
}
pub(crate) struct ChannelDecodeState {
prev_gain: Option<u8>,
prev_lag: Option<i32>,
prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]>,
prev_nlsf_len: usize,
first: bool,
}
impl ChannelDecodeState {
pub(crate) fn new() -> Self {
Self {
prev_gain: None,
prev_lag: None,
prev_nlsf: None,
prev_nlsf_len: 0,
first: true,
}
}
pub(crate) fn config(
&self,
bandwidth: crate::toc::Bandwidth,
frame_size: crate::silk_excitation::SilkFrameSize,
voice_active: bool,
stereo: Option<crate::silk_decode::StereoHeaderContext>,
) -> crate::silk_decode::SilkFrameConfig {
crate::silk_decode::SilkFrameConfig {
bandwidth,
frame_size,
voice_active,
first_subframe_independent: self.first || self.prev_gain.is_none(),
previous_log_gain: self.prev_gain,
previous_primary_lag: self.prev_lag,
ltp_scaling_present: self.first,
lsf_interp_after_reset: self.first || self.prev_nlsf.is_none(),
previous_nlsf_q15: self.prev_nlsf,
previous_nlsf_len: self.prev_nlsf_len,
stereo,
}
}
pub(crate) fn advance(&mut self, decoded: &crate::silk_decode::SilkFrameDecoded) {
self.prev_gain = Some(decoded.gains.last_log_gain());
self.prev_lag = Some(decoded.ltp.primary_lag());
self.prev_nlsf = Some(decoded.nlsf_q15);
self.prev_nlsf_len = decoded.d_lpc;
self.first = false;
}
}
fn resample_internal_to_output_i16(
internal: &[f32],
bandwidth: crate::toc::Bandwidth,
out: &mut [i16],
) {
if out.is_empty() {
return;
}
if internal.is_empty() {
for o in out.iter_mut() {
*o = 0;
}
return;
}
let in_len = internal.len();
let out_len = out.len();
let _ = bandwidth; for (i, o) in out.iter_mut().enumerate() {
let pos = (i as f64) * (in_len as f64) / (out_len as f64);
let i0 = pos.floor() as usize;
let frac = (pos - i0 as f64) as f32;
let s0 = internal[i0.min(in_len - 1)];
let s1 = internal[(i0 + 1).min(in_len - 1)];
let v = s0 + (s1 - s0) * frac;
*o = f32_to_i16(v);
}
}
fn resample_stereo_to_output_i16(
left: &[f32],
right: &[f32],
bandwidth: crate::toc::Bandwidth,
out: &mut [i16],
) {
let per_channel = out.len() / 2;
if per_channel == 0 {
return;
}
let mut l = vec![0i16; per_channel];
let mut r = vec![0i16; per_channel];
resample_internal_to_output_i16(left, bandwidth, &mut l);
resample_internal_to_output_i16(right, bandwidth, &mut r);
for i in 0..per_channel {
out[2 * i] = l[i];
out[2 * i + 1] = r[i];
}
}
fn f32_to_i16(v: f32) -> i16 {
let scaled = (v.clamp(-1.0, 1.0) * 32767.0).round();
scaled as i16
}
pub fn channel_count(mapping: ChannelMapping) -> u8 {
match mapping {
ChannelMapping::Mono => 1,
ChannelMapping::Stereo => 2,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::toc::OpusTocByte;
fn code0_packet(config: u8, stereo: bool, body: &[u8]) -> Vec<u8> {
let toc = (config << 3) | (if stereo { 1 << 2 } else { 0 });
let mut p = vec![toc];
p.extend_from_slice(body);
p
}
#[test]
fn output_samples_per_channel_matches_table2_durations() {
let cases = [
(25u16, 120usize), (50, 240), (100, 480), (200, 960), (400, 1920), (600, 2880), ];
for (tenths, expected) in cases {
assert_eq!(
output_samples_per_channel(tenths),
expected,
"tenths={tenths}"
);
}
}
#[test]
fn empty_packet_rejected() {
let mut dec = OpusDecoder::new();
assert_eq!(dec.decode_packet(&[]), Err(Error::EmptyPacket));
}
#[test]
fn silk_nb_mono_20ms_single_frame_pcm_length() {
let pkt = code0_packet(1, false, &[0x12, 0x34, 0x56]);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.channels, 1);
assert_eq!(out.sample_rate_hz, OUTPUT_SAMPLE_RATE_HZ);
assert_eq!(out.samples_per_channel(), 960);
assert_eq!(out.pcm.len(), 960);
assert_eq!(out.frame_outcomes.len(), 1);
assert!(
matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkDecodeError
),
"got {:?}",
out.frame_outcomes[0].status
);
}
#[test]
fn celt_only_stereo_pcm_is_interleaved_length() {
let pkt = code0_packet(20, true, &[0xaa, 0xbb]);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.channels, 2);
assert_eq!(out.pcm.len(), 2 * out.samples_per_channel());
let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
assert!(
matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::CeltSilence
| FrameDecodeStatus::CeltCoarseEnergyDecoded
| FrameDecodeStatus::CeltAllocationDecoded
| FrameDecodeStatus::CeltDecodeError
),
"got {:?}",
out.frame_outcomes[0].status
);
assert_eq!(routing.operating_mode, OperatingMode::CeltOnly);
}
#[test]
fn code1_two_equal_frames_concatenate_pcm() {
let toc = 0b01u8;
let mut pkt = vec![toc];
pkt.extend_from_slice(&[1, 2, 3, 4]); let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.frame_outcomes.len(), 2);
assert_eq!(out.samples_per_channel(), 960);
assert_eq!(out.pcm.len(), 960);
}
#[test]
fn dtx_zero_length_frame_emits_silence_with_status() {
let toc = 0b10u8;
let pkt = vec![toc, 0x00, 0x07];
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.frame_outcomes.len(), 2);
assert_eq!(out.frame_outcomes[0].status, FrameDecodeStatus::DtxOrLost);
assert_eq!(out.samples_per_channel(), 960);
}
#[test]
fn reset_clears_carried_channel_state() {
let mut dec = OpusDecoder::new();
let stereo = code0_packet(20, true, &[1, 2]);
dec.decode_packet(&stereo).expect("decode");
assert_eq!(dec.last_channels, Some(2));
dec.reset();
assert_eq!(dec.last_channels, None);
}
#[test]
fn celt_to_silk_transition_resets_silk_state() {
let silk_body: Vec<u8> = (0..200u16)
.map(|i| (i.wrapping_mul(149).wrapping_add(11) & 0xff) as u8)
.collect();
let silk_pkt = code0_packet(1, false, &silk_body); let celt_pkt = code0_packet(17, false, &[0xaa, 0xbb]);
let mut ref_dec = OpusDecoder::new();
let reference = ref_dec.decode_packet(&silk_pkt).expect("decode");
let mut seq_dec = OpusDecoder::new();
seq_dec.decode_packet(&silk_pkt).expect("decode");
seq_dec.decode_packet(&celt_pkt).expect("decode");
let after_reset = seq_dec.decode_packet(&silk_pkt).expect("decode");
if reference.frame_outcomes[0].status == FrameDecodeStatus::SilkParamsDecoded {
assert_eq!(
after_reset.pcm, reference.pcm,
"§4.5.2 CELT→SILK transition must reset SILK state"
);
}
}
#[test]
fn silk_to_silk_no_reset_threads_state() {
let silk_body: Vec<u8> = (0..200u16)
.map(|i| (i.wrapping_mul(149).wrapping_add(11) & 0xff) as u8)
.collect();
let silk_pkt = code0_packet(1, false, &silk_body);
let mut fresh = OpusDecoder::new();
let fresh_out = fresh.decode_packet(&silk_pkt).expect("decode");
let mut threaded = OpusDecoder::new();
threaded.decode_packet(&silk_pkt).expect("decode");
let second = threaded.decode_packet(&silk_pkt).expect("decode");
assert_eq!(second.pcm.len(), fresh_out.pcm.len());
}
#[test]
fn silk_mono_full_decode_consumes_bitstream_cleanly() {
let body: Vec<u8> = (0..120u16)
.map(|i| (i.wrapping_mul(101).wrapping_add(7) & 0xff) as u8)
.collect();
let pkt = code0_packet(1, false, &body); let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.frame_outcomes.len(), 1);
assert_eq!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkParamsDecoded,
"a long SILK NB mono body should fully decode"
);
assert_eq!(out.samples_per_channel(), 960);
}
#[test]
fn silk_mono_40ms_two_silk_frames_decode() {
let body: Vec<u8> = (0..220u16)
.map(|i| (i.wrapping_mul(53).wrapping_add(3) & 0xff) as u8)
.collect();
let pkt = code0_packet(2, false, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
assert_eq!(routing.silk_frames_per_channel, Some(2));
assert_eq!(out.frame_outcomes.len(), 1);
assert_eq!(out.samples_per_channel(), 1920);
assert!(matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkDecodeError
));
}
#[test]
fn stereo_silk_only_decodes_to_interleaved_pcm() {
let body: Vec<u8> = (0..220u16)
.map(|i| (i.wrapping_mul(137).wrapping_add(19) & 0xff) as u8)
.collect();
let pkt = code0_packet(1, true, &body); let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.channels, 2);
assert_eq!(out.samples_per_channel(), 960);
assert_eq!(out.pcm.len(), 2 * 960);
assert!(matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
));
}
#[test]
fn stereo_silk_clean_body_is_fully_decoded() {
let body: Vec<u8> = (0..400u16)
.map(|i| (i.wrapping_mul(97).wrapping_add(41) & 0xff) as u8)
.collect();
let pkt = code0_packet(1, true, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkStereoDecoded,
"a long stereo SILK NB body should fully decode"
);
assert_eq!(out.pcm.len(), 2 * 960);
}
#[test]
fn stereo_silk_40ms_two_intervals_decode() {
let body: Vec<u8> = (0..480u16)
.map(|i| (i.wrapping_mul(61).wrapping_add(7) & 0xff) as u8)
.collect();
let pkt = code0_packet(2, true, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
assert_eq!(routing.silk_frames_per_channel, Some(2));
assert_eq!(out.channels, 2);
assert_eq!(out.samples_per_channel(), 1920);
assert_eq!(out.pcm.len(), 2 * 1920);
assert!(matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
));
}
#[test]
fn stereo_silk_60ms_three_intervals_per_interval_unmix() {
let body: Vec<u8> = (0..640u16)
.map(|i| (i.wrapping_mul(73).wrapping_add(31) & 0xff) as u8)
.collect();
let pkt = code0_packet(3, true, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
assert_eq!(routing.silk_frames_per_channel, Some(3));
assert_eq!(out.channels, 2);
assert_eq!(out.samples_per_channel(), 2880);
assert_eq!(out.pcm.len(), 2 * 2880);
assert!(matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
));
}
#[test]
fn stereo_silk_state_threads_across_packets() {
let body: Vec<u8> = (0..300u16)
.map(|i| (i.wrapping_mul(113).wrapping_add(23) & 0xff) as u8)
.collect();
let pkt = code0_packet(1, true, &body);
let mut fresh = OpusDecoder::new();
let fresh_out = fresh.decode_packet(&pkt).expect("decode");
let mut threaded = OpusDecoder::new();
threaded.decode_packet(&pkt).expect("decode");
let second = threaded.decode_packet(&pkt).expect("decode");
assert_eq!(second.pcm.len(), fresh_out.pcm.len());
}
#[test]
fn mono_to_stereo_transition_resets_stereo_state() {
let mono_body: Vec<u8> = (0..200u16)
.map(|i| (i.wrapping_mul(71).wrapping_add(5) & 0xff) as u8)
.collect();
let stereo_body: Vec<u8> = (0..300u16)
.map(|i| (i.wrapping_mul(89).wrapping_add(11) & 0xff) as u8)
.collect();
let mono_pkt = code0_packet(1, false, &mono_body);
let stereo_pkt = code0_packet(1, true, &stereo_body);
let mut dec = OpusDecoder::new();
dec.decode_packet(&mono_pkt).expect("mono");
let out = dec.decode_packet(&stereo_pkt).expect("stereo");
assert_eq!(out.channels, 2);
assert_eq!(out.pcm.len(), 2 * 960);
}
#[test]
fn pcm_length_matches_routing_for_every_config() {
let mut dec = OpusDecoder::new();
for config in 0u8..32 {
for stereo in [false, true] {
let pkt = code0_packet(config, stereo, &[0x55, 0x66, 0x77]);
let out = dec.decode_packet(&pkt).expect("decode");
let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
let expected = output_samples_per_channel(routing.frame_size_tenths_ms)
* out.channels as usize;
assert_eq!(out.pcm.len(), expected, "config {config} stereo {stereo}");
let is_wired_silk = matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkStereoDecoded
);
if !is_wired_silk {
assert!(
out.pcm.iter().all(|&s| s == 0),
"config {config} stereo {stereo} status {:?} should be silence",
out.frame_outcomes[0].status
);
}
dec.reset();
}
}
}
#[test]
fn mono_silk_frame_can_emit_nonsilent_pcm() {
let body: Vec<u8> = (0..200u16)
.map(|i| (i.wrapping_mul(181).wrapping_add(13) & 0xff) as u8)
.collect();
let pkt = code0_packet(1, false, &body); let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.channels, 1);
assert_eq!(out.samples_per_channel(), 960);
if out.frame_outcomes[0].status == FrameDecodeStatus::SilkParamsDecoded {
assert_eq!(out.pcm.len(), 960);
}
}
fn find_celt_silence_body() -> Vec<u8> {
use crate::celt_frame_prefix::decode_celt_frame_prefix;
use crate::range_decoder::RangeDecoder;
for b0 in 0u16..=255 {
for b1 in 0u16..=255 {
let buf = [b0 as u8, b1 as u8, 0, 0, 0, 0];
let mut rd = RangeDecoder::new(&buf);
let p = decode_celt_frame_prefix(&mut rd);
if p.silence && p.post_filter.is_none() && !rd.has_error() {
return buf.to_vec();
}
}
}
panic!("no CELT silence body found in the candidate set");
}
#[test]
fn celt_only_silence_frame_decodes_end_to_end() {
let body = find_celt_silence_body();
let pkt = code0_packet(17, false, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert_eq!(out.channels, 1);
assert_eq!(out.samples_per_channel(), 240);
assert_eq!(
out.frame_outcomes[0].status,
FrameDecodeStatus::CeltSilence,
"silence-flagged CELT frame must take the wired synthesis path"
);
assert_eq!(out.pcm.len(), 240);
assert!(
out.pcm.iter().all(|&s| s == 0),
"silence frame must be all zero"
);
}
#[test]
fn celt_silence_advances_synthesis_state() {
let body = find_celt_silence_body();
let pkt = code0_packet(17, false, &body);
let mut dec = OpusDecoder::new();
let first = dec.decode_packet(&pkt).expect("decode");
let second = dec.decode_packet(&pkt).expect("decode");
assert_eq!(
first.frame_outcomes[0].status,
FrameDecodeStatus::CeltSilence
);
assert_eq!(
second.frame_outcomes[0].status,
FrameDecodeStatus::CeltSilence
);
assert!(second.pcm.iter().all(|&s| s == 0));
}
#[test]
fn celt_non_silent_frame_decodes_coarse_energy() {
use crate::celt_frame_prefix::decode_celt_frame_prefix;
use crate::range_decoder::RangeDecoder;
let mut chosen: Option<Vec<u8>> = None;
for b0 in 0u16..=255 {
let buf = [
b0 as u8, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
];
let mut rd = RangeDecoder::new(&buf);
let p = decode_celt_frame_prefix(&mut rd);
if !p.silence && !rd.has_error() {
chosen = Some(buf.to_vec());
break;
}
}
let body = chosen.expect("a non-silent CELT body exists in the candidate set");
let pkt = code0_packet(17, false, &body);
let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert!(
matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::CeltCoarseEnergyDecoded
| FrameDecodeStatus::CeltAllocationDecoded
| FrameDecodeStatus::CeltDecodeError
),
"got {:?}",
out.frame_outcomes[0].status
);
assert_eq!(out.pcm.len(), 240);
}
#[test]
fn celt_coarse_energy_threads_predictor_across_frames() {
use crate::celt_frame_prefix::decode_celt_frame_prefix;
use crate::range_decoder::RangeDecoder;
let mut chosen: Option<Vec<u8>> = None;
for b0 in 0u16..=255 {
let buf = [
b0 as u8, 0x33, 0xcc, 0x55, 0xaa, 0x0f, 0xf0, 0x12, 0x9a, 0x4e,
];
let mut rd = RangeDecoder::new(&buf);
let p = decode_celt_frame_prefix(&mut rd);
if !p.silence && !p.intra && !rd.has_error() {
chosen = Some(buf.to_vec());
break;
}
}
if let Some(body) = chosen {
let pkt = code0_packet(19, false, &body); let mut dec = OpusDecoder::new();
let first = dec.decode_packet(&pkt).expect("decode");
if matches!(
first.frame_outcomes[0].status,
FrameDecodeStatus::CeltCoarseEnergyDecoded
| FrameDecodeStatus::CeltAllocationDecoded
) {
assert!(dec.celt_coarse.is_some());
}
let _second = dec.decode_packet(&pkt).expect("decode");
}
}
#[test]
fn celt_non_silent_frame_decodes_allocation_header() {
use crate::celt_frame_prefix::decode_celt_frame_prefix;
use crate::range_decoder::RangeDecoder;
let mut chosen: Option<Vec<u8>> = None;
for b0 in 0u16..=255 {
let buf = [
b0 as u8, 0x91, 0x37, 0xc4, 0x6e, 0x2d, 0xa8, 0x5b, 0xf1, 0x0c, 0x93, 0x47, 0xbe,
0x21,
];
let mut rd = RangeDecoder::new(&buf);
let p = decode_celt_frame_prefix(&mut rd);
if !p.silence && !rd.has_error() {
chosen = Some(buf.to_vec());
break;
}
}
let body = chosen.expect("a non-silent CELT body exists in the candidate set");
let pkt = code0_packet(19, false, &body); let mut dec = OpusDecoder::new();
let out = dec.decode_packet(&pkt).expect("decode");
assert!(
matches!(
out.frame_outcomes[0].status,
FrameDecodeStatus::CeltAllocationDecoded
| FrameDecodeStatus::CeltCoarseEnergyDecoded
| FrameDecodeStatus::CeltDecodeError
),
"got {:?}",
out.frame_outcomes[0].status
);
assert_eq!(out.pcm.len(), 960);
}
#[test]
fn celt_tf_spread_allocation_advances_tell_past_coarse_energy() {
use crate::celt_band_layout::{celt_end_coded_band, celt_first_coded_band, CeltFrameSize};
use crate::celt_coarse_energy::CoarseEnergyState;
use crate::celt_frame_prefix::decode_celt_frame_prefix;
use crate::range_decoder::RangeDecoder;
let body: [u8; 14] = [
0x40, 0x91, 0x37, 0xc4, 0x6e, 0x2d, 0xa8, 0x5b, 0xf1, 0x0c, 0x93, 0x47, 0xbe, 0x21,
];
let mut rd = RangeDecoder::new(&body);
let prefix = decode_celt_frame_prefix(&mut rd);
assert!(!prefix.silence, "test body must be non-silent");
let celt_size = CeltFrameSize::Ms20;
let start = celt_first_coded_band(false);
let end = celt_end_coded_band();
let mut coarse = CoarseEnergyState::new();
coarse
.decode_frame(&mut rd, celt_size, prefix.intra, start, end)
.expect("coarse energy decodes");
let tell_after_coarse = rd.tell_frac();
let (tf, spread) = OpusDecoder::decode_celt_tf_spread_allocation(
&mut rd,
celt_size,
prefix.transient,
1,
start,
end,
body.len() as u32,
)
.expect("tf/spread/allocation header decodes without a bookkeeping error");
let tell_after_alloc = rd.tell_frac();
assert_eq!(tf.tf_change.len(), end - start);
assert!(spread <= crate::celt_spreading::SPREAD_MAX);
assert!(
tell_after_alloc > tell_after_coarse,
"alloc tell {tell_after_alloc} must advance past coarse tell {tell_after_coarse}"
);
}
}