oxideav_opus/decoder.rs
1//! Top-level Opus packet → PCM orchestration — RFC 6716 §3 / §4.
2//!
3//! This module is the keystone that turns a raw Opus packet (a TOC byte
4//! plus one or more §3.2-packed Opus frames) into interleaved 48 kHz PCM
5//! samples. It sits above every per-stage SILK / CELT decoder in the
6//! crate and wires the §3.1 TOC parse, the §3.2 frame packing
7//! ([`crate::frames::OpusPacket`]), and the §4.2 / §4.3 per-frame mode
8//! dispatch ([`crate::framing::OpusFrameRouting`]) into one
9//! [`OpusDecoder::decode_packet`] call.
10//!
11//! ## What this module owns
12//!
13//! * The packet → frame split (delegated to [`OpusPacket::parse`]).
14//! * The §4.5 multi-frame loop: every Opus frame in a code-1 / code-2 /
15//! code-3 packet is decoded in order and its PCM appended to the
16//! output, so a 60 ms code-3 packet of three 20 ms frames yields one
17//! contiguous PCM buffer.
18//! * The §3.2.1 DTX / lost-frame marker handling: a zero-length frame
19//! slice contributes one Opus-frame worth of silence (the §4.6 PLC
20//! "fill with silence" floor — a real concealment model is a separate
21//! milestone).
22//! * The 48 kHz output sample-count accounting (RFC 7845 §5.1: the Opus
23//! decoder always emits 48 kHz regardless of the internal SILK / CELT
24//! sample rate).
25//! * The per-frame routing seam: each Opus frame is dispatched to
26//! [`Self::decode_silk_only_frame`], [`Self::decode_celt_only_frame`],
27//! or [`Self::decode_hybrid_frame`] based on its [`OpusFrameRouting`].
28//!
29//! ## What this module does not own
30//!
31//! * The §4.1 range-coder primitive ([`crate::range_decoder`]).
32//! * The per-stage SILK / CELT decode (the `silk_*` / `celt_*` modules).
33//! * Any container parsing (Ogg / RTP framing live in their own crates;
34//! this module consumes a bare Opus packet).
35//!
36//! ## Status of the per-frame audio decode
37//!
38//! The packet-level orchestration (TOC → framing → routing → 48 kHz PCM
39//! buffer layout) is complete and total over all 32 §3.1 configs and all
40//! four §3.2 frame-count codes. The per-frame audio decode is wired
41//! incrementally:
42//!
43//! * **Mono SILK-only** frames run the full §4.2 decode → PCM path: the
44//! §4.2.3 header bits, the §4.2.5 LBRR / §4.2.6 regular SILK frame loop
45//! (1 / 2 / 3 SILK frames per §4.2.2), each frame decoded in Table-5
46//! order via [`crate::silk_decode::decode_silk_frame`] with the
47//! inter-frame state threaded across them, then the §4.2.7.9 LTP / LPC
48//! synthesis ([`crate::silk_synthesis::synthesize_silk_frame`]) and the
49//! §4.2.9 (non-normative) resample to 48 kHz. The carried §4.2.7.9
50//! synthesis histories persist across the packet's Opus frames; the
51//! emitted PCM is real audio ([`FrameDecodeStatus::SilkParamsDecoded`]).
52//! * **Stereo SILK-only** frames run the full §4.2 interleaved decode →
53//! PCM path: the §4.2.3 two-channel header bits, the §4.2.5 / §4.2.6
54//! mid/side interleave (mid frame then side frame per 20 ms interval,
55//! the side frame skipped when the §4.2.7.2 mid-only flag is set), each
56//! channel's §4.2.7.9 synthesis with its own carried history, then the
57//! §4.2.8 mid/side → left/right unmixing
58//! ([`crate::silk_stereo::stereo_ms_to_lr`]) and the §4.2.9 resample,
59//! emitting interleaved L/R PCM
60//! ([`FrameDecodeStatus::SilkStereoDecoded`]). The §4.2.7.1 mono→stereo
61//! weight reset and the §4.5.2 SILK state reset are applied across
62//! packets.
63//! * **CELT-only / Hybrid** frames emit silence of the correct length
64//! flagged [`FrameDecodeStatus::LayerNotWired`] (CELT is gated on the
65//! §4.3.2.1 coarse-energy Laplace decode).
66//!
67//! Either way the multi-frame packet loop and the RFC 7845 §5.1 48 kHz
68//! sample-count accounting are exercised end-to-end.
69
70use crate::frames::OpusPacket;
71use crate::framing::{OperatingMode, OpusFrameRouting};
72use crate::toc::ChannelMapping;
73use crate::Error;
74
75/// Output sample rate of the Opus decoder, in Hz. Per RFC 7845 §5.1 the
76/// decoder always emits 48 kHz regardless of the internal SILK / CELT
77/// sample rate; the per-layer resamplers upsample to this rate.
78pub const OUTPUT_SAMPLE_RATE_HZ: u32 = 48_000;
79
80/// Output samples per millisecond per channel at [`OUTPUT_SAMPLE_RATE_HZ`].
81pub const OUTPUT_SAMPLES_PER_MS: u32 = OUTPUT_SAMPLE_RATE_HZ / 1000;
82
83/// Number of 48 kHz output samples (per channel) an Opus frame of the
84/// given duration produces.
85///
86/// `frame_size_tenths_ms` is the §3.1 Table 2 duration in tenths of a
87/// millisecond (25, 50, 100, 200, 400, 600). The 2.5 ms CELT case
88/// (`25` tenths) yields `25 * 48 / 10 = 120` samples per channel, which
89/// is exact; all six durations divide evenly.
90pub fn output_samples_per_channel(frame_size_tenths_ms: u16) -> usize {
91 // tenths-ms * (48 samples / ms) / 10 = tenths-ms * 48 / 10.
92 (frame_size_tenths_ms as usize * OUTPUT_SAMPLES_PER_MS as usize) / 10
93}
94
95/// Why a given Opus frame produced the samples it did.
96///
97/// The packet-level orchestration is complete, but the per-frame audio
98/// decode lands incrementally. This status lets a caller (and the
99/// crate's own tests) distinguish "decoded real audio" from "emitted
100/// silence because the layer's range-coded decode is not wired yet" or
101/// "emitted silence for a DTX / lost frame".
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum FrameDecodeStatus {
104 /// A §3.2.1 zero-length frame: DTX or a lost/packet-loss marker.
105 /// Per §4.6 the floor behaviour is to emit silence; a real PLC model
106 /// is a separate milestone.
107 DtxOrLost,
108 /// The frame's operating mode does not yet have a composed
109 /// sample-producing decode path in this crate, so silence of the
110 /// correct length was emitted. The variant carries the mode so the
111 /// caller knows which layer is pending.
112 LayerNotWired(OperatingMode),
113 /// A mono SILK-only frame whose full §4.2.7 bitstream (frame type,
114 /// gains, LSF chain, LTP, LCG seed, excitation) was decoded in
115 /// Table-5 order via [`crate::silk_decode::decode_silk_frame`], then
116 /// synthesized through the §4.2.7.9 LTP / LPC filters
117 /// ([`crate::silk_synthesis::synthesize_silk_frame`]) and resampled to
118 /// 48 kHz (§4.2.9, non-normative). The emitted PCM is real audio.
119 SilkParamsDecoded,
120 /// A **stereo** SILK-only frame whose §4.2.3 / §4.2.4 header bits and
121 /// the §4.2.5 / §4.2.6 interleaved mid/side SILK frames were decoded
122 /// in §4.2.2 order (mid frame then side frame per 20 ms interval, the
123 /// side frame skipped when the §4.2.7.2 mid-only flag is set), each
124 /// channel synthesized through the §4.2.7.9 filters, converted from
125 /// mid/side to left/right via §4.2.8 stereo unmixing
126 /// ([`crate::silk_stereo::stereo_ms_to_lr`]), then resampled to 48 kHz
127 /// (§4.2.9, non-normative). The emitted interleaved L/R PCM is real
128 /// audio.
129 SilkStereoDecoded,
130 /// A SILK-only frame whose §4.2.7 bitstream decode latched an error
131 /// (a malformed / truncated frame). Silence of the correct length was
132 /// emitted in its place per the §4.6 floor.
133 SilkDecodeError,
134 /// A CELT-only frame whose §4.3.7.1 silence flag was set: the real
135 /// range-coded frame prefix (silence + post-filter group) was decoded
136 /// and the §4.3.6→§4.3.7.2 synthesis backend was advanced with
137 /// all-zero band shapes / energies, emitting silence PCM while
138 /// carrying the MDCT overlap-add and de-emphasis state forward for the
139 /// next frame. (Distinct from [`Self::LayerNotWired`]: the bitstream
140 /// is actually consumed and the synthesis state is real, not stubbed.)
141 CeltSilence,
142 /// A CELT-only frame whose §4.3.7.1 prefix decode latched a range-coder
143 /// error (a malformed / truncated frame). Silence of the correct length
144 /// was emitted in its place per the §4.6 floor.
145 CeltDecodeError,
146 /// A **non-silent** CELT-only frame whose §4.3.7.1 prefix *and*
147 /// §4.3.2.1 coarse-energy were decoded from the real range coder:
148 /// the per-band coarse log-energy envelope was reconstructed (the 2-D
149 /// predictor recurrence in [`crate::celt_coarse_energy`]) and threaded
150 /// into the cross-frame predictor state. The remaining band-data
151 /// stages (bit allocation, §4.3.4 PVQ band shapes, §4.3.2.2 fine
152 /// energy) are not yet wired, so silence of the correct length is
153 /// still emitted and the synthesis backend's overlap-add / de-emphasis
154 /// state is advanced — but the coarse-energy *front half* of the
155 /// entropy decode is now real. (Distinct from
156 /// [`Self::LayerNotWired`]: the frame prefix and coarse energy are
157 /// actually consumed.)
158 CeltCoarseEnergyDecoded,
159 /// A **non-silent** CELT-only frame that additionally decoded the
160 /// §4.3.3 allocation *header* from the real range coder, on top of
161 /// the §4.3.7.1 prefix and §4.3.2.1 coarse energy: the §4.3.3 band
162 /// boosts ([`crate::celt_band_boost::decode_band_boosts`]), the
163 /// §4.3.3 allocation trim ([`crate::celt_alloc_trim::decode_alloc_trim`]),
164 /// and the §4.3.3 anti-collapse / skip / intensity-stereo /
165 /// dual-stereo reservations ([`crate::celt_reservations::reserve_block`])
166 /// were consumed in §4.3.3 order, advancing the range-coder position
167 /// through the entire signalled part of the allocation. The remaining
168 /// §4.3.3 implicit allocation (the `interp_bits2pulses` per-band
169 /// pulse / fine-energy split — reference-code-only, absent from the
170 /// RFC narrative body) plus the §4.3.4 PVQ band shapes and §4.3.2.2
171 /// fine energy are still pending, so silence of the correct length is
172 /// emitted and the synthesis backend's overlap-add / de-emphasis state
173 /// is advanced with all-zero bands. The *signalled* allocation
174 /// header is now real. (Distinct from
175 /// [`Self::CeltCoarseEnergyDecoded`]: the boost / trim / reservation
176 /// symbols are actually consumed.)
177 CeltAllocationDecoded,
178}
179
180/// The result of decoding one Opus frame: how many per-channel samples
181/// it contributed and why.
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub struct FrameOutcome {
184 /// Per-channel 48 kHz sample count this frame contributed.
185 pub samples_per_channel: usize,
186 /// Provenance of the samples (real audio vs silence and why).
187 pub status: FrameDecodeStatus,
188}
189
190/// Decoded audio for one Opus packet: interleaved 48 kHz PCM plus the
191/// per-frame outcomes.
192#[derive(Debug, Clone, PartialEq)]
193pub struct DecodedAudio {
194 /// Interleaved signed 16-bit PCM at 48 kHz. For stereo the layout is
195 /// `[L0, R0, L1, R1, …]`; for mono it is `[S0, S1, …]`. Length is
196 /// `total_samples_per_channel * channels`.
197 pub pcm: Vec<i16>,
198 /// Number of audio channels (1 for mono, 2 for stereo).
199 pub channels: u8,
200 /// Output sample rate in Hz (always [`OUTPUT_SAMPLE_RATE_HZ`]).
201 pub sample_rate_hz: u32,
202 /// Per-Opus-frame outcomes, in packet order. `outcomes.len()` equals
203 /// the packet's §3.2 frame count.
204 pub frame_outcomes: Vec<FrameOutcome>,
205}
206
207impl DecodedAudio {
208 /// Total per-channel 48 kHz sample count across every Opus frame in
209 /// the packet.
210 pub fn samples_per_channel(&self) -> usize {
211 self.pcm.len() / self.channels.max(1) as usize
212 }
213}
214
215/// Why an in-band FEC ([`OpusDecoder::decode_packet_fec`]) recovery
216/// produced the samples it did (RFC 6716 §2.1.7 / §4.2.5).
217///
218/// In-band FEC works by re-encoding the signal of the frame *prior* to a
219/// packet at a lower bitrate and carrying it as one or more §4.2.5 LBRR
220/// frames inside that packet. When a packet is lost, the decoder can
221/// recover the lost frame's audio from the LBRR frame(s) in the *next*
222/// successfully received packet (`decode_packet_fec`), rather than
223/// emitting pure silence / running pitch-based concealment.
224#[derive(Debug, Clone, Copy, PartialEq, Eq)]
225pub enum FecDecodeStatus {
226 /// The packet carried §4.2.5 LBRR frame(s) for the lost prior frame,
227 /// and they were decoded in Table-5 order and synthesized through the
228 /// §4.2.7.9 LTP / LPC filters into real recovered audio at 48 kHz. For
229 /// a stereo packet the recovered mid/side LBRR frames were unmixed via
230 /// §4.2.8.
231 Recovered,
232 /// The packet has no LBRR frame for the requested channel(s) (the
233 /// §4.2.4 LBRR flags are clear), so no FEC data is available. Silence
234 /// of the requested duration was emitted; the caller should fall back
235 /// to its own packet-loss concealment.
236 NoLbrr,
237 /// The packet is not a SILK-bearing mode (CELT-only carries no LBRR),
238 /// so FEC recovery is not possible. Silence was emitted.
239 NotSilk,
240 /// The packet's §4.2 LBRR bitstream was malformed / truncated. Silence
241 /// of the requested duration was emitted in its place.
242 DecodeError,
243}
244
245/// The result of an in-band FEC recovery for one lost packet
246/// ([`OpusDecoder::decode_packet_fec`]).
247#[derive(Debug, Clone, PartialEq)]
248pub struct FecRecovered {
249 /// Interleaved signed 16-bit PCM at 48 kHz, same layout as
250 /// [`DecodedAudio::pcm`]. Length is `samples_per_channel * channels`.
251 pub pcm: Vec<i16>,
252 /// Number of audio channels (1 for mono, 2 for stereo).
253 pub channels: u8,
254 /// Output sample rate in Hz (always [`OUTPUT_SAMPLE_RATE_HZ`]).
255 pub sample_rate_hz: u32,
256 /// Why the samples were produced (real recovery vs silence and why).
257 pub status: FecDecodeStatus,
258}
259
260/// Stateful Opus packet → PCM decoder.
261///
262/// One [`OpusDecoder`] is fed Opus packets in stream order via
263/// [`Self::decode_packet`]. The decoder is stateful because the SILK and
264/// CELT layers carry inter-frame state (LPC / LTP history, MDCT overlap,
265/// stereo unmixing memory, the §4.5.2 reset policy); the state lives here
266/// and is threaded into the per-frame decode as those paths land. Today
267/// the carried state is minimal (it grows as each layer is wired), but
268/// the type is the stable home for it.
269#[derive(Debug, Default)]
270pub struct OpusDecoder {
271 /// Channel count of the most recently decoded packet, if any. Used
272 /// only for the §4.5.2 mono↔stereo transition reset bookkeeping the
273 /// per-layer decoders will consult once wired.
274 last_channels: Option<u8>,
275 /// Mono SILK synthesis state (the §4.2.7.9 LTP / LPC histories),
276 /// carried across Opus frames in the stream. `None` until the first
277 /// mono SILK-only frame is synthesized; re-created (cleared per
278 /// §4.5.2) when the SILK bandwidth changes.
279 silk_synth_mono: Option<crate::silk_synthesis::SilkSynthState>,
280 /// Stereo SILK synthesis state: the §4.2.7.9 LTP / LPC histories for
281 /// the **mid** and **side** channels, carried across Opus frames.
282 /// `None` until the first stereo SILK-only frame; re-created when the
283 /// SILK bandwidth changes (a §4.5.2 reset).
284 silk_synth_stereo: Option<(
285 crate::silk_synthesis::SilkSynthState,
286 crate::silk_synthesis::SilkSynthState,
287 )>,
288 /// §4.2.8 stereo unmixing history (two prior mid samples, one prior
289 /// side sample, and the previous frame's prediction weights), carried
290 /// across Opus frames. `None` until the first stereo SILK-only frame;
291 /// reset (zeroed) on any §4.2.7.1 mono→stereo transition.
292 silk_stereo_unmix: Option<crate::silk_stereo::StereoUnmixState>,
293 /// Operating mode of the most recently decoded Opus frame, used to
294 /// drive the §4.5.2 SILK state-reset rule ("the SILK state is reset
295 /// before every SILK-only or Hybrid frame where the previous frame
296 /// was CELT-only"). `None` before the first frame / after a reset.
297 prev_mode: Option<OperatingMode>,
298 /// CELT synthesis backend state (the §4.3.7 MDCT overlap-add history
299 /// and §4.3.7.2 de-emphasis memory, per channel), carried across the
300 /// CELT frames of the stream. `None` until the first CELT-layer frame
301 /// is synthesized; re-created when the CELT frame size or channel
302 /// count changes (a §4.5.2-style reset, since the overlap geometry
303 /// depends on the frame size).
304 celt_synth: Option<crate::celt_synthesis::CeltSynthState>,
305 /// §4.3.2.1 CELT coarse-energy predictor state (the per-band
306 /// mean-removed `E[b][l-1]` history the inter-frame predictor reads),
307 /// carried across the CELT frames of the stream. Reset on a SILK→CELT
308 /// transition (§4.5.2) and whenever an intra frame is decoded (where
309 /// `alpha = 0` ignores the prior frame anyway). `None` until the first
310 /// CELT-layer frame whose coarse energy is reconstructed.
311 celt_coarse: Option<crate::celt_coarse_energy::CoarseEnergyState>,
312}
313
314impl OpusDecoder {
315 /// Construct a fresh decoder with no carried state (equivalent to the
316 /// post-`reset` state of §4.5.2).
317 pub fn new() -> Self {
318 Self::default()
319 }
320
321 /// Discard all inter-frame state, as after a container seek (the
322 /// §4.5.2 decoder reset). Leaves the decoder ready to decode a new
323 /// bitstream position as if it were the first packet.
324 pub fn reset(&mut self) {
325 *self = Self::default();
326 }
327
328 /// Decode one complete Opus packet into interleaved 48 kHz PCM.
329 ///
330 /// Performs the §3.1 TOC parse, the §3.2 frame split, and the §4.5
331 /// multi-frame loop, dispatching each Opus frame through its
332 /// [`OpusFrameRouting`] to the matching per-mode decode. Returns
333 /// [`Error::EmptyPacket`] for a zero-length packet (§3.1 R1) and
334 /// [`Error::MalformedPacket`] for any §3.2 framing violation.
335 pub fn decode_packet(&mut self, packet: &[u8]) -> Result<DecodedAudio, Error> {
336 let parsed = OpusPacket::parse(packet)?;
337 self.decode_parsed_packet(parsed)
338 }
339
340 /// Decode one complete Opus packet that uses RFC 6716 Appendix-B
341 /// self-delimited framing (the framing the first `N − 1` streams of
342 /// a multistream packet use, RFC 7845 §3). Behaves exactly like
343 /// [`Self::decode_packet`] otherwise — the only difference is how the
344 /// frame slices are recovered from the packet bytes.
345 pub fn decode_self_delimited_packet(&mut self, packet: &[u8]) -> Result<DecodedAudio, Error> {
346 let parsed = crate::framing_self_delim::parse_self_delimited(packet)?.packet;
347 self.decode_parsed_packet(parsed)
348 }
349
350 /// Shared decode body for both the regular ([`Self::decode_packet`])
351 /// and self-delimited ([`Self::decode_self_delimited_packet`]) entry
352 /// points: applies the §4.5.2 cross-packet state resets, then runs
353 /// the §4.5 multi-frame loop over the already-sliced frames.
354 fn decode_parsed_packet(&mut self, parsed: OpusPacket<'_>) -> Result<DecodedAudio, Error> {
355 let routing = OpusFrameRouting::from_toc(parsed.toc);
356 let channels = routing.channel_count();
357 let per_frame_samples = output_samples_per_channel(routing.frame_size_tenths_ms);
358
359 // §4.5.2 SILK state reset: the SILK decoder is reset before every
360 // SILK-only or Hybrid frame whose predecessor was CELT-only. We
361 // apply this at the Opus-packet boundary using the recorded
362 // previous operating mode. (Redundancy placement only moves the
363 // CELT reset, which doesn't affect the SILK reset, so we pass the
364 // safe NotPresent default here.)
365 if let Some(prev_mode) = self.prev_mode {
366 let reset = crate::mode_transition_reset::decide_state_resets(
367 prev_mode,
368 routing.operating_mode,
369 crate::celt_redundancy::RedundancyDecision::NotPresent,
370 );
371 if reset.silk {
372 if let Some(state) = self.silk_synth_mono.as_mut() {
373 state.reset();
374 }
375 if let Some((mid, side)) = self.silk_synth_stereo.as_mut() {
376 mid.reset();
377 side.reset();
378 }
379 if let Some(unmix) = self.silk_stereo_unmix.as_mut() {
380 unmix.reset();
381 }
382 }
383 }
384
385 // §4.2.7.1: "the previous weights are reset to zeros on any
386 // transition from mono to stereo." More generally the §4.2.8
387 // unmixing history (and the mid/side synthesis state) only makes
388 // sense within a contiguous stereo run; a channel-count change
389 // clears the carried stereo state so a stale mono / prior-stereo
390 // history can never leak across the transition.
391 if self.last_channels.is_some_and(|c| c != channels) {
392 if let Some(unmix) = self.silk_stereo_unmix.as_mut() {
393 unmix.reset();
394 }
395 if let Some((mid, side)) = self.silk_synth_stereo.as_mut() {
396 mid.reset();
397 side.reset();
398 }
399 }
400
401 self.last_channels = Some(channels);
402 self.prev_mode = Some(routing.operating_mode);
403
404 let frame_slices = parsed.frames();
405 let mut pcm: Vec<i16> =
406 Vec::with_capacity(frame_slices.len() * per_frame_samples * channels as usize);
407 let mut frame_outcomes = Vec::with_capacity(frame_slices.len());
408
409 for frame in frame_slices {
410 let outcome = self.decode_one_frame(frame, &routing, &mut pcm);
411 frame_outcomes.push(outcome);
412 }
413
414 Ok(DecodedAudio {
415 pcm,
416 channels,
417 sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
418 frame_outcomes,
419 })
420 }
421
422 /// Decode one Opus frame, appending its interleaved 48 kHz PCM to
423 /// `pcm` and returning the per-frame outcome.
424 fn decode_one_frame(
425 &mut self,
426 frame: &[u8],
427 routing: &OpusFrameRouting,
428 pcm: &mut Vec<i16>,
429 ) -> FrameOutcome {
430 let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
431 let channels = routing.channel_count();
432
433 // §3.2.1 zero-length frame: DTX / lost. §4.6 floor = silence.
434 if frame.is_empty() {
435 push_silence(pcm, per_channel, channels);
436 return FrameOutcome {
437 samples_per_channel: per_channel,
438 status: FrameDecodeStatus::DtxOrLost,
439 };
440 }
441
442 match routing.operating_mode {
443 OperatingMode::SilkOnly => self.decode_silk_only_frame(frame, routing, pcm),
444 OperatingMode::CeltOnly => self.decode_celt_only_frame(frame, routing, pcm),
445 OperatingMode::Hybrid => self.decode_hybrid_frame(frame, routing, pcm),
446 }
447 }
448
449 /// Decode one SILK-only Opus frame (§4.2).
450 ///
451 /// For a **mono** Opus frame this runs the real §4.2.3 header-bit
452 /// decode followed by the §4.2.5 LBRR / §4.2.6 regular SILK frame
453 /// loop, calling [`crate::silk_decode::decode_silk_frame`] for each
454 /// regular SILK frame in Table-5 order with the inter-frame state
455 /// (previous gain / lag / NLSF) threaded across the frames of the
456 /// Opus frame. The decoded parameters + excitation are then run
457 /// through the §4.2.7.9 LTP / LPC synthesis
458 /// ([`crate::silk_synthesis::synthesize_silk_frame`]) and the §4.2.9
459 /// (non-normative) resample to 48 kHz, producing real PCM
460 /// ([`FrameDecodeStatus::SilkParamsDecoded`]). A truncated / malformed
461 /// frame yields [`FrameDecodeStatus::SilkDecodeError`] and silence.
462 ///
463 /// A **stereo** Opus frame routes to
464 /// [`Self::decode_silk_only_stereo`], which runs the §4.2.6 mid/side
465 /// interleave with the §4.2.7.1 / §4.2.7.2 symbols enabled and the
466 /// §4.2.8 unmixing back half, emitting interleaved L/R PCM
467 /// ([`FrameDecodeStatus::SilkStereoDecoded`]).
468 fn decode_silk_only_frame(
469 &mut self,
470 frame: &[u8],
471 routing: &OpusFrameRouting,
472 pcm: &mut Vec<i16>,
473 ) -> FrameOutcome {
474 let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
475 let channels = routing.channel_count();
476 let pcm_start = pcm.len();
477 push_silence(pcm, per_channel, channels);
478
479 if channels == 2 {
480 let status = match self.decode_silk_only_stereo(frame, routing) {
481 Ok((left, right, bandwidth)) => {
482 // §4.2.9 (non-normative): resample each channel to the
483 // 48 kHz output rate, then write it interleaved
484 // (`[L0, R0, L1, R1, …]`) over the reserved silence.
485 resample_stereo_to_output_i16(
486 &left,
487 &right,
488 bandwidth,
489 &mut pcm[pcm_start..pcm_start + per_channel * 2],
490 );
491 FrameDecodeStatus::SilkStereoDecoded
492 }
493 Err(_) => FrameDecodeStatus::SilkDecodeError,
494 };
495 return FrameOutcome {
496 samples_per_channel: per_channel,
497 status,
498 };
499 }
500
501 let status = match self.decode_silk_only_mono(frame, routing) {
502 Ok((internal, bandwidth)) => {
503 // §4.2.9 (non-normative): resample the internal-rate
504 // signal to the 48 kHz decoder output rate and write it
505 // over the reserved silence region. The spec says "the
506 // resampler itself is non-normative, and a decoder can use
507 // any method it wants"; we use linear interpolation.
508 resample_internal_to_output_i16(
509 &internal,
510 bandwidth,
511 &mut pcm[pcm_start..pcm_start + per_channel],
512 );
513 FrameDecodeStatus::SilkParamsDecoded
514 }
515 Err(_) => FrameDecodeStatus::SilkDecodeError,
516 };
517 FrameOutcome {
518 samples_per_channel: per_channel,
519 status,
520 }
521 }
522
523 /// Decode the full §4.2 bitstream of one mono SILK-only Opus frame:
524 /// §4.2.3 header bits, the §4.2.5 LBRR frames, and the §4.2.6 regular
525 /// SILK frames, consuming every symbol in order. Returns `Ok(())`
526 /// when the whole frame decodes cleanly.
527 fn decode_silk_only_mono(
528 &mut self,
529 frame: &[u8],
530 routing: &OpusFrameRouting,
531 ) -> Result<(Vec<f32>, crate::toc::Bandwidth), Error> {
532 use crate::range_decoder::RangeDecoder;
533 use crate::silk_decode::{decode_silk_frame, SilkFrameConfig, SilkFrameDecoded};
534 use crate::silk_excitation::SilkFrameSize;
535 use crate::silk_frame::FrameKind;
536 use crate::silk_header::SilkHeaderBits;
537 use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
538
539 let bandwidth = routing
540 .silk_bandwidth
541 .ok_or(Error::MalformedPacket)?
542 .to_bandwidth();
543 let num_silk_frames = routing
544 .silk_frames_per_channel
545 .ok_or(Error::MalformedPacket)?;
546 // §4.2.2: each SILK frame is 20 ms, except a 10 ms Opus frame
547 // (one SILK frame of 10 ms).
548 let frame_size = if routing.frame_size_tenths_ms == 100 {
549 SilkFrameSize::TenMs
550 } else {
551 SilkFrameSize::TwentyMs
552 };
553
554 let mut rd = RangeDecoder::new(frame);
555
556 // §4.2.3 / §4.2.4 header bits (mono => stereo = false).
557 let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, false)?;
558
559 // §4.2.5 LBRR frames: one per SILK frame whose mid LBRR bit is
560 // set, in time-interval order. LBRR frames are independent of the
561 // regular-frame inter-frame state (they form their own sequence),
562 // but for this mono path we decode them to consume their bits and
563 // keep the range coder aligned with the regular frames that
564 // follow. Per §4.2.7.3 an LBRR frame is always active-coded.
565 let mut lbrr_prev_gain: Option<u8> = None;
566 let mut lbrr_prev_lag: Option<i32> = None;
567 let mut lbrr_first = true;
568 for idx in 0..num_silk_frames {
569 if !header.mid_has_lbrr(idx) {
570 continue;
571 }
572 let cfg = SilkFrameConfig {
573 bandwidth,
574 frame_size,
575 voice_active: true, // §4.2.7.3: LBRR uses the active PDF.
576 first_subframe_independent: lbrr_first || lbrr_prev_gain.is_none(),
577 previous_log_gain: lbrr_prev_gain,
578 previous_primary_lag: lbrr_prev_lag,
579 ltp_scaling_present: lbrr_first,
580 lsf_interp_after_reset: lbrr_first,
581 previous_nlsf_q15: None,
582 previous_nlsf_len: 0,
583 // Mono SILK-only path: no §4.2.7.1 / §4.2.7.2 stereo header.
584 stereo: None,
585 };
586 let decoded = decode_silk_frame(&mut rd, cfg)?;
587 lbrr_prev_gain = Some(decoded.gains.last_log_gain());
588 lbrr_prev_lag = Some(decoded.ltp.primary_lag());
589 lbrr_first = false;
590 let _ = FrameKind::Lbrr; // documents the §4.2.7.3 kind.
591 }
592
593 // §4.2.6 regular SILK frames: one per time interval, even when
594 // the VAD flag is unset. Inter-frame state threads across them.
595 let mut prev_gain: Option<u8> = None;
596 let mut prev_lag: Option<i32> = None;
597 let mut prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]> = None;
598 let mut prev_nlsf_len = 0usize;
599 let mut first = true;
600 let mut decoded_frames: Vec<SilkFrameDecoded> =
601 Vec::with_capacity(num_silk_frames as usize);
602 for idx in 0..num_silk_frames {
603 let cfg = SilkFrameConfig {
604 bandwidth,
605 frame_size,
606 voice_active: header.mid_vad(idx),
607 first_subframe_independent: first || prev_gain.is_none(),
608 previous_log_gain: prev_gain,
609 previous_primary_lag: prev_lag,
610 ltp_scaling_present: first,
611 lsf_interp_after_reset: first || prev_nlsf.is_none(),
612 previous_nlsf_q15: prev_nlsf,
613 previous_nlsf_len: prev_nlsf_len,
614 // Mono SILK-only path: no §4.2.7.1 / §4.2.7.2 stereo header.
615 stereo: None,
616 };
617 let decoded = decode_silk_frame(&mut rd, cfg)?;
618 prev_gain = Some(decoded.gains.last_log_gain());
619 prev_lag = Some(decoded.ltp.primary_lag());
620 prev_nlsf = Some(decoded.nlsf_q15);
621 prev_nlsf_len = decoded.d_lpc;
622 first = false;
623 decoded_frames.push(decoded);
624 }
625
626 if rd.has_error() {
627 return Err(Error::MalformedPacket);
628 }
629
630 // §4.2.7.9 synthesis: turn the decoded SILK frames into
631 // internal-rate (8/12/16 kHz) time-domain samples, threading the
632 // cross-Opus-frame §4.2.7.9 histories. The state is (re)created if
633 // absent or if the SILK bandwidth changed (a §4.5.2 reset).
634 let need_fresh = match &self.silk_synth_mono {
635 Some(s) => s.bandwidth() != bandwidth,
636 None => true,
637 };
638 if need_fresh {
639 self.silk_synth_mono = Some(SilkSynthState::new(bandwidth)?);
640 }
641 let state = self
642 .silk_synth_mono
643 .as_mut()
644 .expect("synth state set above");
645
646 let mut internal = Vec::new();
647 for decoded in &decoded_frames {
648 let frame_out = synthesize_silk_frame(bandwidth, frame_size, decoded, state)?;
649 internal.extend_from_slice(&frame_out);
650 }
651 Ok((internal, bandwidth))
652 }
653
654 /// Decode the full §4.2 bitstream of one **stereo** SILK-only Opus
655 /// frame and unmix it to left/right.
656 ///
657 /// The §4.2.2 stereo organisation interleaves the two channels: per
658 /// 20 ms interval the mid SILK frame is decoded, then the side SILK
659 /// frame (skipped when the §4.2.7.2 mid-only flag on the mid frame is
660 /// set). The §4.2.7.1 stereo prediction weights ride on the mid
661 /// frame. After both channels finish their §4.2.7.9 synthesis they are
662 /// converted from mid/side to left/right via §4.2.8
663 /// ([`crate::silk_stereo::stereo_ms_to_lr`]).
664 ///
665 /// LBRR frames (§4.2.5) precede the regular frames and are also
666 /// interleaved (mid then side per interval); they are decoded only to
667 /// keep the range coder aligned with the regular frames that follow.
668 ///
669 /// Returns `(left, right, bandwidth)` at the SILK internal rate.
670 #[allow(clippy::type_complexity)]
671 fn decode_silk_only_stereo(
672 &mut self,
673 frame: &[u8],
674 routing: &OpusFrameRouting,
675 ) -> Result<(Vec<f32>, Vec<f32>, crate::toc::Bandwidth), Error> {
676 use crate::range_decoder::RangeDecoder;
677 use crate::silk_decode::{decode_silk_frame, SilkFrameDecoded, StereoHeaderContext};
678 use crate::silk_excitation::SilkFrameSize;
679 use crate::silk_header::SilkHeaderBits;
680 use crate::silk_stereo::{stereo_ms_to_lr, StereoUnmixState, StereoWeightsQ13};
681 use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
682
683 let bandwidth = routing
684 .silk_bandwidth
685 .ok_or(Error::MalformedPacket)?
686 .to_bandwidth();
687 let num_silk_frames = routing
688 .silk_frames_per_channel
689 .ok_or(Error::MalformedPacket)?;
690 let frame_size = if routing.frame_size_tenths_ms == 100 {
691 SilkFrameSize::TenMs
692 } else {
693 SilkFrameSize::TwentyMs
694 };
695
696 let mut rd = RangeDecoder::new(frame);
697
698 // §4.2.3 / §4.2.4 header bits (stereo => both channels' VAD + LBRR
699 // flags, mid then side).
700 let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, true)?;
701
702 // §4.2.5 LBRR frames: per 20 ms interval, the mid LBRR frame (if
703 // present) then the side LBRR frame (if present), interleaved per
704 // §4.2.2. Decoded only to consume their bits. The §4.2.7.1 stereo
705 // weights ride on the mid LBRR frame; the §4.2.7.2 mid-only flag
706 // is present on the mid LBRR frame iff the side LBRR is unset for
707 // that interval.
708 let mut lbrr_mid = ChannelDecodeState::new();
709 let mut lbrr_side = ChannelDecodeState::new();
710 for idx in 0..num_silk_frames {
711 let mid_lbrr = header.mid_has_lbrr(idx);
712 let side_lbrr = header.side_has_lbrr(idx);
713 if mid_lbrr {
714 let stereo_ctx = StereoHeaderContext {
715 // §4.2.7.2: mid-only flag present on the mid frame iff
716 // the corresponding side channel is not coded.
717 has_mid_only_flag: !side_lbrr,
718 };
719 let decoded = decode_silk_frame(
720 &mut rd,
721 lbrr_mid.config(bandwidth, frame_size, true, Some(stereo_ctx)),
722 )?;
723 lbrr_mid.advance(&decoded);
724 // A set mid-only flag would forbid a coded side LBRR
725 // frame; the header LBRR flags already encode that, so we
726 // trust `side_lbrr` for the interleave decision.
727 if side_lbrr {
728 let decoded = decode_silk_frame(
729 &mut rd,
730 lbrr_side.config(bandwidth, frame_size, true, None),
731 )?;
732 lbrr_side.advance(&decoded);
733 }
734 } else if side_lbrr {
735 // Side-only LBRR (mid not coded): no stereo weights on a
736 // side frame per §4.2.7.1.
737 let decoded = decode_silk_frame(
738 &mut rd,
739 lbrr_side.config(bandwidth, frame_size, true, None),
740 )?;
741 lbrr_side.advance(&decoded);
742 }
743 }
744
745 // §4.2.6 regular SILK frames: per 20 ms interval, the mid frame
746 // then (unless the §4.2.7.2 mid-only flag is set) the side frame.
747 let mut mid_state = ChannelDecodeState::new();
748 let mut side_state = ChannelDecodeState::new();
749 let mut mid_frames: Vec<SilkFrameDecoded> = Vec::with_capacity(num_silk_frames as usize);
750 // Per-interval side frame: `Some(frame)` when coded, `None` when
751 // the side channel is skipped (mid-only flag set or side VAD path
752 // produced no frame). The §4.2.8 unmixer treats a `None` side as
753 // all-zero.
754 let mut side_frames: Vec<Option<SilkFrameDecoded>> =
755 Vec::with_capacity(num_silk_frames as usize);
756 // The §4.2.7.1 weights carried by the most-recent mid frame; the
757 // §4.2.8 unmix consumes the last interval's weights for the whole
758 // Opus frame (one set of weights per SILK frame, but the unmix
759 // runs once over the concatenated channel signal — we apply the
760 // first interval's weights, threading prev across intervals via
761 // the unmix state below).
762 let mut interval_weights: Vec<StereoWeightsQ13> =
763 Vec::with_capacity(num_silk_frames as usize);
764
765 for idx in 0..num_silk_frames {
766 let side_active = header.side_vad(idx);
767 // §4.2.7.2: the mid-only flag is present iff the side channel
768 // for this interval is NOT active (a regular frame with side
769 // VAD unset). When side VAD is set the side frame must be
770 // coded and the flag is omitted.
771 let stereo_ctx = StereoHeaderContext {
772 has_mid_only_flag: !side_active,
773 };
774 let mid_decoded = decode_silk_frame(
775 &mut rd,
776 mid_state.config(bandwidth, frame_size, header.mid_vad(idx), Some(stereo_ctx)),
777 )?;
778 // §4.2.7.1 weights ride on the mid frame.
779 let w = mid_decoded.stereo_pred.map(|p| StereoWeightsQ13 {
780 w0_q13: p.w0_q13,
781 w1_q13: p.w1_q13,
782 });
783 interval_weights.push(w.unwrap_or_default());
784 // §4.2.7.2: side coded iff side VAD set OR the mid-only flag is
785 // not set (mid-only flag present + cleared ⇒ side is coded).
786 let side_coded = side_active || mid_decoded.mid_only_flag == Some(false);
787 mid_state.advance(&mid_decoded);
788 mid_frames.push(mid_decoded);
789
790 if side_coded {
791 let side_decoded = decode_silk_frame(
792 &mut rd,
793 side_state.config(bandwidth, frame_size, header.side_vad(idx), None),
794 )?;
795 side_state.advance(&side_decoded);
796 side_frames.push(Some(side_decoded));
797 } else {
798 // §4.2.7.2 / §4.5.2: an uncoded side SILK frame clears the
799 // side LTP buffer; zeros feed the §4.2.8 unmixer.
800 side_frames.push(None);
801 }
802 }
803
804 if rd.has_error() {
805 return Err(Error::MalformedPacket);
806 }
807
808 // §4.2.7.9 synthesis for both channels, threading the cross-Opus-
809 // frame histories. (Re)create the state on a bandwidth change.
810 let need_fresh = match &self.silk_synth_stereo {
811 Some((m, _)) => m.bandwidth() != bandwidth,
812 None => true,
813 };
814 if need_fresh {
815 self.silk_synth_stereo = Some((
816 SilkSynthState::new(bandwidth)?,
817 SilkSynthState::new(bandwidth)?,
818 ));
819 }
820 let (mid_synth, side_synth) = self
821 .silk_synth_stereo
822 .as_mut()
823 .expect("stereo synth state set above");
824
825 // §4.2.8 stereo unmixing runs **per SILK frame** (per 20 ms
826 // interval), not once over the whole Opus frame: the spec defines
827 // the unmix over `j <= i < (j + n2)` where `j` is the SILK frame
828 // start and `n2` is "the total number of samples in the frame"
829 // (the SILK frame). Each interval carries its own §4.2.7.1 weights
830 // and restarts the 8 ms interpolation phase; the previous
831 // interval's weights and trailing samples thread through the
832 // carried `StereoUnmixState`. We therefore synthesize and unmix
833 // each interval in turn and concatenate the L/R outputs.
834 let unmix = self
835 .silk_stereo_unmix
836 .get_or_insert_with(StereoUnmixState::new);
837
838 let mut left = Vec::new();
839 let mut right = Vec::new();
840 for (idx, mid_frame) in mid_frames.iter().enumerate() {
841 let mid_out = synthesize_silk_frame(bandwidth, frame_size, mid_frame, mid_synth)?;
842 let n = mid_out.len();
843 let weights = interval_weights[idx];
844 let stereo = match &side_frames[idx] {
845 Some(side_frame) => {
846 let side_out =
847 synthesize_silk_frame(bandwidth, frame_size, side_frame, side_synth)?;
848 stereo_ms_to_lr(bandwidth, &mid_out, Some(&side_out), weights, unmix)?
849 }
850 None => {
851 // §4.2.7.2 / §4.5.2: an uncoded side SILK frame clears
852 // the side LTP buffer; zeros feed the §4.2.8 unmixer
853 // (`side = None` ⇒ side[i] treated as 0 everywhere).
854 side_synth.reset();
855 stereo_ms_to_lr(bandwidth, &mid_out, None, weights, unmix)?
856 }
857 };
858 debug_assert_eq!(stereo.left.len(), n);
859 left.extend_from_slice(&stereo.left);
860 right.extend_from_slice(&stereo.right);
861 }
862
863 Ok((left, right, bandwidth))
864 }
865
866 /// Decode the Table-56 CELT symbols that sit between the §4.3.2.1
867 /// coarse energy and the §4.3.4 residual: the §4.3.1 time-frequency
868 /// resolution, the §4.3.4.3 spread parameter, and the §4.3.3
869 /// signalled allocation header. All are read from the live range
870 /// coder in exact Table-56 order:
871 ///
872 /// 1. **`tf_change` / `tf_select`** (§4.3.1, `celt_tf_decode::decode_tf`):
873 /// the per-band time-frequency resolution flags and the gated
874 /// `tf_select` bit. These come immediately after coarse energy in
875 /// Table 56 and *must* be consumed before the allocation, or every
876 /// subsequent symbol reads from the wrong bitstream position.
877 /// 2. **`spread`** (§4.3.4.3, `celt_spreading::decode_spread`): the
878 /// 2-bit spread symbol (PDF `{7,2,21,2}/32`), Table-56-ordered
879 /// right before the dynamic allocation.
880 /// 3. **Band boosts** (§4.3.3, `celt_band_boost::decode_band_boosts`):
881 /// the per-band dynamic-allocation boost symbols over the coding
882 /// window `start..end`, fed the per-band cap vector `cap[]`
883 /// ([`crate::celt_cache_caps50::cap_for_band_bits`]) and the
884 /// per-band MDCT-bin counts.
885 /// 4. **Allocation trim** (§4.3.3, `celt_alloc_trim::decode_alloc_trim`):
886 /// the single trim symbol, gated on whether 6 bits still fit after
887 /// the boosts.
888 /// 5. **Reservations** (§4.3.3, `celt_reservations::reserve_block`):
889 /// the §4.3.3 anti-collapse / skip / intensity-stereo / dual-stereo
890 /// bit reservations. (`reserve_block` only *computes* the reserved
891 /// eighth-bit counts; the anti-collapse / skip / intensity / dual
892 /// *bits* themselves are decoded later in Table-56 order, after the
893 /// implicit allocation + residual, so nothing is read from the
894 /// coder here — but the reservation computation reads
895 /// `ec_tell_frac` at exactly this point and must run now to stay
896 /// faithful to the §4.3.3 ordering and to validate the running
897 /// budget.)
898 ///
899 /// Returns the decoded [`crate::celt_tf_decode::TfDecode`] and the
900 /// `spread` value (both needed by the pending §4.3.4 band-shape
901 /// decode) on success, or `Err(())` on a caller-side bookkeeping error
902 /// from one of the sub-decoders (a band-window / length mismatch,
903 /// never a malformed-bitstream signal — that surfaces through the
904 /// range coder's sticky error flag, which the caller checks via
905 /// `rd.has_error()`).
906 ///
907 /// The §4.3.3 *implicit* allocation (the reference-only
908 /// `interp_bits2pulses` per-band pulse / fine-energy split) is **not**
909 /// performed here: it reads nothing further from the range coder, so
910 /// stopping after the reservation block leaves the coder positioned
911 /// exactly where the §4.3.4 PVQ residual decode will resume once that
912 /// (currently docs-gapped) interpolation lands.
913 #[allow(clippy::too_many_arguments)]
914 fn decode_celt_tf_spread_allocation(
915 rd: &mut crate::range_decoder::RangeDecoder<'_>,
916 celt_size: crate::celt_band_layout::CeltFrameSize,
917 is_transient: bool,
918 channels: u8,
919 start: usize,
920 end: usize,
921 frame_size_bytes: u32,
922 ) -> Result<(crate::celt_tf_decode::TfDecode, u8), ()> {
923 use crate::celt_cache_caps50::CacheCapsStereo;
924
925 let is_stereo = channels == 2;
926 let stereo_axis = if is_stereo {
927 CacheCapsStereo::Stereo
928 } else {
929 CacheCapsStereo::Mono
930 };
931 let lm = celt_size.column_index() as u32;
932 let band_count = end - start;
933
934 // §4.3.1 (Table 56): tf_change / tf_select come immediately after
935 // coarse energy. Decode them from the live coder so the band
936 // boosts below read from the correct bitstream position.
937 let tf = crate::celt_tf_decode::decode_tf(rd, celt_size, is_transient, start, end);
938
939 // §4.3.4.3 (Table 56): the spread symbol is next, right before the
940 // dynamic allocation.
941 let spread = crate::celt_spreading::decode_spread(rd);
942
943 // §4.3.3 per-band cap[] and per-channel MDCT-bin counts over the
944 // coding window. Both are indexed by `band - start`.
945 let mut caps: Vec<u32> = Vec::with_capacity(band_count);
946 let mut n_bins: Vec<u32> = Vec::with_capacity(band_count);
947 for band in start..end {
948 let bins = crate::celt_band_layout::celt_band_bins_per_channel(band, celt_size)
949 .ok_or(())? as u32;
950 let cap = crate::celt_cache_caps50::cap_for_band_bits(
951 lm,
952 stereo_axis,
953 band as u32,
954 channels as u32,
955 bins,
956 )
957 .map_err(|_| ())?;
958 caps.push(cap);
959 n_bins.push(bins);
960 }
961
962 // Step 1: §4.3.3 band boosts.
963 let boosts = crate::celt_band_boost::decode_band_boosts(
964 rd,
965 start,
966 end,
967 &caps,
968 &n_bins,
969 frame_size_bytes,
970 )
971 .map_err(|_| ())?;
972
973 // Step 2: §4.3.3 allocation trim. The gate uses the running
974 // `ec_tell_frac` and the `total_boost` from step 1.
975 let _trim = crate::celt_alloc_trim::decode_alloc_trim(
976 rd,
977 rd.tell_frac(),
978 frame_size_bytes,
979 boosts.total_boost_eighth_bits,
980 )
981 .map_err(|_| ())?;
982
983 // Step 3: §4.3.3 reservations. These read the running
984 // `ec_tell_frac` *after* the trim symbol and only *compute* the
985 // reserved eighth-bit budget; they consume no further range-coder
986 // symbols at this point.
987 let _reservations = crate::celt_reservations::reserve_block(
988 frame_size_bytes,
989 rd.tell_frac(),
990 boosts.total_boost_eighth_bits,
991 celt_size,
992 is_transient,
993 is_stereo,
994 band_count as u32,
995 )
996 .map_err(|_| ())?;
997
998 Ok((tf, spread))
999 }
1000
1001 /// Decode one CELT-only Opus frame (§4.3).
1002 ///
1003 /// Decodes the §4.3.7.1 range-coded frame prefix (silence flag +
1004 /// post-filter group + transient + intra) from the real range coder.
1005 /// When the **silence** flag is set, the frame is fully wired
1006 /// end-to-end: the §4.3.6→§4.3.7.2 synthesis backend
1007 /// ([`crate::celt_synthesis::CeltSynthState`]) is advanced with
1008 /// all-zero band shapes and energies, producing silence PCM at the
1009 /// 48 kHz output rate while carrying the MDCT overlap-add and
1010 /// de-emphasis state forward for subsequent frames
1011 /// ([`FrameDecodeStatus::CeltSilence`]). The synthesis state is
1012 /// (re)built whenever the CELT frame size or channel count changes.
1013 ///
1014 /// Non-silent CELT frames still emit silence flagged
1015 /// [`FrameDecodeStatus::LayerNotWired`]: the §4.3.2.1 coarse-energy
1016 /// reconstruction recurrence (the 2-D predictor accumulation and its
1017 /// per-band mean baseline) is not yet available in the clean-room
1018 /// `docs/` material, so the band-energy envelope cannot be rebuilt.
1019 /// The Laplace symbol decoder ([`crate::celt_laplace`]) and the prefix
1020 /// decoder are in place; the missing piece is the reconstruction
1021 /// arithmetic feeding the per-band `log2_energy`.
1022 fn decode_celt_only_frame(
1023 &mut self,
1024 frame: &[u8],
1025 routing: &OpusFrameRouting,
1026 pcm: &mut Vec<i16>,
1027 ) -> FrameOutcome {
1028 use crate::celt_band_layout::CeltFrameSize;
1029
1030 let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
1031 let channels = routing.channel_count();
1032 let pcm_start = pcm.len();
1033 push_silence(pcm, per_channel, channels);
1034
1035 // The CELT layer needs a Table-55 frame size; a 40/60 ms frame
1036 // can never route here (those are SILK-only), so a `None` is a
1037 // routing invariant violation — fall back to the unwired floor.
1038 let Some(celt_size) =
1039 CeltFrameSize::from_frame_tenths_ms(routing.frame_size_tenths_ms as u32)
1040 else {
1041 return FrameOutcome {
1042 samples_per_channel: per_channel,
1043 status: FrameDecodeStatus::LayerNotWired(OperatingMode::CeltOnly),
1044 };
1045 };
1046
1047 // §4.3.7.1 frame prefix from the real range coder.
1048 let mut rd = crate::range_decoder::RangeDecoder::new(frame);
1049 let prefix = crate::celt_frame_prefix::decode_celt_frame_prefix(&mut rd);
1050 if rd.has_error() {
1051 return FrameOutcome {
1052 samples_per_channel: per_channel,
1053 status: FrameDecodeStatus::CeltDecodeError,
1054 };
1055 }
1056
1057 // Non-silent frames now decode the §4.3.2.1 coarse energy from the
1058 // range coder. The downstream band-data stages (bit allocation,
1059 // §4.3.4 PVQ band shapes, §4.3.2.2 fine energy) are not yet wired,
1060 // so we still emit the §4.6 floor and advance the synthesis state
1061 // with all-zero bands — but the coarse-energy front half of the
1062 // entropy decode is real, and the cross-frame predictor state is
1063 // threaded forward for the next frame.
1064 let final_status = if prefix.silence {
1065 FrameDecodeStatus::CeltSilence
1066 } else {
1067 // Reset the coarse-energy predictor on an intra frame (where
1068 // `alpha = 0` discards the prior frame anyway) or when no
1069 // state has been carried yet; otherwise reuse the threaded
1070 // history so the inter-frame predictor sees `E[b][l-1]`.
1071 if prefix.intra || self.celt_coarse.is_none() {
1072 self.celt_coarse = Some(crate::celt_coarse_energy::CoarseEnergyState::new());
1073 }
1074 let coarse = self.celt_coarse.as_mut().expect("just built");
1075 let start = crate::celt_band_layout::celt_first_coded_band(false);
1076 let end = crate::celt_band_layout::celt_end_coded_band();
1077 match coarse.decode_frame(&mut rd, celt_size, prefix.intra, start, end) {
1078 Ok(_frame) => {
1079 if rd.has_error() {
1080 return FrameOutcome {
1081 samples_per_channel: per_channel,
1082 status: FrameDecodeStatus::CeltDecodeError,
1083 };
1084 }
1085 // §4.3.1 TF + §4.3.4.3 spread + §4.3.3 allocation
1086 // header: the Table-56 symbols between coarse energy
1087 // and the §4.3.4 residual (tf_change / tf_select,
1088 // spread, band boosts, allocation trim, and the
1089 // anti-collapse / skip / intensity / dual
1090 // reservations), decoded in Table-56 order from the
1091 // same range coder. This advances the entropy decode
1092 // through everything the bitstream explicitly carries
1093 // before the (reference-only) implicit interpolation.
1094 match Self::decode_celt_tf_spread_allocation(
1095 &mut rd,
1096 celt_size,
1097 prefix.transient,
1098 channels,
1099 start,
1100 end,
1101 frame.len() as u32,
1102 ) {
1103 Ok((_tf, _spread)) => {
1104 if rd.has_error() {
1105 return FrameOutcome {
1106 samples_per_channel: per_channel,
1107 status: FrameDecodeStatus::CeltDecodeError,
1108 };
1109 }
1110 FrameDecodeStatus::CeltAllocationDecoded
1111 }
1112 Err(()) => {
1113 return FrameOutcome {
1114 samples_per_channel: per_channel,
1115 status: FrameDecodeStatus::CeltDecodeError,
1116 };
1117 }
1118 }
1119 }
1120 Err(_) => {
1121 return FrameOutcome {
1122 samples_per_channel: per_channel,
1123 status: FrameDecodeStatus::CeltDecodeError,
1124 };
1125 }
1126 }
1127 };
1128
1129 // Drive the synthesis backend with all-zero bands (the band shapes
1130 // are not yet decoded). For a silence frame this is the §4.5.1
1131 // behaviour; for a coarse-only frame it advances the overlap-add /
1132 // de-emphasis state while the band-data stages land.
1133 // (Re)build the CELT synthesis state if absent or if its geometry
1134 // no longer matches this frame's size / channel count.
1135 let needs_rebuild = match &self.celt_synth {
1136 Some(s) => {
1137 s.channels() != channels as usize
1138 || s.transform_half_len() != (celt_size.to_frame_tenths_ms() as usize * 48) / 10
1139 }
1140 None => true,
1141 };
1142 if needs_rebuild {
1143 match crate::celt_synthesis::CeltSynthState::new(celt_size, false, channels as usize) {
1144 Ok(s) => self.celt_synth = Some(s),
1145 Err(_) => {
1146 return FrameOutcome {
1147 samples_per_channel: per_channel,
1148 status: FrameDecodeStatus::CeltDecodeError,
1149 };
1150 }
1151 }
1152 }
1153 let synth = self.celt_synth.as_mut().expect("just built");
1154
1155 // All-zero per-band shapes and energies: one zero shape slice per
1156 // coded band (each of its Table-55 bin length) and a matching
1157 // zero-energy vector, for every channel.
1158 let coded_bands = synth.coded_bands();
1159 let first = synth.first_coded_band();
1160 let mut shape_storage: Vec<Vec<f64>> = Vec::with_capacity(coded_bands);
1161 for band in first..(first + coded_bands) {
1162 let bins = crate::celt_band_layout::celt_band_bins_per_channel(band, celt_size)
1163 .unwrap_or(0) as usize;
1164 shape_storage.push(vec![0.0_f64; bins]);
1165 }
1166 let shape_refs: Vec<&[f64]> = shape_storage.iter().map(Vec::as_slice).collect();
1167 let energies = vec![0.0_f64; coded_bands];
1168 let per_channel_args: Vec<(&[&[f64]], &[f64])> = (0..channels as usize)
1169 .map(|_| (shape_refs.as_slice(), energies.as_slice()))
1170 .collect();
1171
1172 match synth.synthesize_frame_interleaved_i16(&per_channel_args) {
1173 Ok(pcm_frame) => {
1174 let region = &mut pcm[pcm_start..pcm_start + per_channel * channels as usize];
1175 let n = region.len().min(pcm_frame.len());
1176 region[..n].copy_from_slice(&pcm_frame[..n]);
1177 FrameOutcome {
1178 samples_per_channel: per_channel,
1179 status: final_status,
1180 }
1181 }
1182 Err(_) => FrameOutcome {
1183 samples_per_channel: per_channel,
1184 status: FrameDecodeStatus::CeltDecodeError,
1185 },
1186 }
1187 }
1188
1189 /// Recover the audio of a **lost** Opus frame from the in-band FEC
1190 /// (§4.2.5 LBRR) data carried in the *next* successfully received
1191 /// packet (RFC 6716 §2.1.7).
1192 ///
1193 /// In-band FEC encodes a low-bitrate redundant copy of the signal
1194 /// immediately *prior* to a packet as one or more §4.2.5 LBRR frames
1195 /// inside that packet. When the application detects a packet loss and
1196 /// has the following packet in hand, it calls this method on that
1197 /// following packet to reconstruct the lost frame's audio instead of
1198 /// relying solely on silence / pitch-based concealment.
1199 ///
1200 /// The recovered PCM is returned at the 48 kHz output rate. The packet
1201 /// passed here is the one *after* the loss; only its §4.2.5 LBRR
1202 /// frames are decoded and synthesized (the packet's own regular frames
1203 /// are decoded later by an ordinary [`Self::decode_packet`] call).
1204 ///
1205 /// On success ([`FecDecodeStatus::Recovered`]) the SILK synthesis
1206 /// history is advanced to the recovered frame's state, so a subsequent
1207 /// [`Self::decode_packet`] on the same packet continues smoothly from
1208 /// the reconstructed signal. When the packet carries no LBRR data
1209 /// ([`FecDecodeStatus::NoLbrr`]), is CELT-only
1210 /// ([`FecDecodeStatus::NotSilk`]), or is malformed
1211 /// ([`FecDecodeStatus::DecodeError`]), silence of the lost frame's
1212 /// duration is returned and the caller falls back to its own
1213 /// concealment.
1214 ///
1215 /// Returns [`Error::EmptyPacket`] for a zero-length packet and
1216 /// [`Error::MalformedPacket`] for a §3.2 framing violation in the
1217 /// carrier packet.
1218 pub fn decode_packet_fec(&mut self, packet: &[u8]) -> Result<FecRecovered, Error> {
1219 let parsed = OpusPacket::parse(packet)?;
1220 let routing = OpusFrameRouting::from_toc(parsed.toc);
1221 let channels = routing.channel_count();
1222 // §4.2.5: an LBRR frame has the same frame size / bandwidth /
1223 // channel count as the carrier packet's regular frames, and covers
1224 // the equivalent prior interval(s); the recovered duration matches
1225 // the carrier's per-frame duration.
1226 let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
1227 let mut pcm = vec![0i16; per_channel * channels as usize];
1228
1229 // FEC only exists for SILK-bearing modes (§2.1.7 re-encodes the
1230 // SILK speech layer); a CELT-only packet carries no LBRR.
1231 if !matches!(
1232 routing.operating_mode,
1233 OperatingMode::SilkOnly | OperatingMode::Hybrid
1234 ) {
1235 return Ok(FecRecovered {
1236 pcm,
1237 channels,
1238 sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
1239 status: FecDecodeStatus::NotSilk,
1240 });
1241 }
1242
1243 // The first Opus frame of the packet carries the §4.2.5 LBRR
1244 // frames (LBRR frames precede the regular frames within a single
1245 // SILK-bearing Opus frame; a code-1/2/3 packet's later frames have
1246 // their own LBRR, but those cover intervals already adjacent to
1247 // received audio, so the canonical "previous packet was lost"
1248 // recovery uses the leading Opus frame's LBRR).
1249 let Some(&frame) = parsed.frames().first() else {
1250 return Ok(FecRecovered {
1251 pcm,
1252 channels,
1253 sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
1254 status: FecDecodeStatus::DecodeError,
1255 });
1256 };
1257 if frame.is_empty() {
1258 return Ok(FecRecovered {
1259 pcm,
1260 channels,
1261 sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
1262 status: FecDecodeStatus::NoLbrr,
1263 });
1264 }
1265
1266 let status = if channels == 2 {
1267 match self.decode_silk_fec_stereo(frame, &routing) {
1268 Ok(Some((left, right, bandwidth))) => {
1269 resample_stereo_to_output_i16(&left, &right, bandwidth, &mut pcm);
1270 FecDecodeStatus::Recovered
1271 }
1272 Ok(None) => FecDecodeStatus::NoLbrr,
1273 Err(_) => FecDecodeStatus::DecodeError,
1274 }
1275 } else {
1276 match self.decode_silk_fec_mono(frame, &routing) {
1277 Ok(Some((internal, bandwidth))) => {
1278 resample_internal_to_output_i16(&internal, bandwidth, &mut pcm);
1279 FecDecodeStatus::Recovered
1280 }
1281 Ok(None) => FecDecodeStatus::NoLbrr,
1282 Err(_) => FecDecodeStatus::DecodeError,
1283 }
1284 };
1285
1286 Ok(FecRecovered {
1287 pcm,
1288 channels,
1289 sample_rate_hz: OUTPUT_SAMPLE_RATE_HZ,
1290 status,
1291 })
1292 }
1293
1294 /// Decode and synthesize the §4.2.5 mono LBRR frame(s) of one
1295 /// SILK-bearing Opus frame into internal-rate recovered audio.
1296 ///
1297 /// Returns `Ok(Some((internal, bandwidth)))` with the recovered
1298 /// signal when at least one mid LBRR frame is present, `Ok(None)` when
1299 /// the §4.2.4 LBRR flags are all clear (no FEC data), or `Err` on a
1300 /// malformed bitstream.
1301 ///
1302 /// Unlike [`Self::decode_silk_only_mono`], which only consumed the
1303 /// LBRR bits to keep the range coder aligned, this path actually runs
1304 /// the §4.2.7.9 synthesis on the LBRR parameters. Per §4.2.5 the LBRR
1305 /// frames form their own independent sequence covering the prior
1306 /// interval(s), so synthesis starts from a **fresh** state (the lost
1307 /// frame's true history is, by definition, unavailable). On success
1308 /// the decoder's carried mono synthesis state is replaced with the
1309 /// recovered-frame history so the next real packet continues smoothly.
1310 fn decode_silk_fec_mono(
1311 &mut self,
1312 frame: &[u8],
1313 routing: &OpusFrameRouting,
1314 ) -> Result<Option<(Vec<f32>, crate::toc::Bandwidth)>, Error> {
1315 use crate::range_decoder::RangeDecoder;
1316 use crate::silk_decode::{decode_silk_frame, SilkFrameConfig, SilkFrameDecoded};
1317 use crate::silk_excitation::SilkFrameSize;
1318 use crate::silk_header::SilkHeaderBits;
1319 use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
1320
1321 let bandwidth = routing
1322 .silk_bandwidth
1323 .ok_or(Error::MalformedPacket)?
1324 .to_bandwidth();
1325 let num_silk_frames = routing
1326 .silk_frames_per_channel
1327 .ok_or(Error::MalformedPacket)?;
1328 let frame_size = if routing.frame_size_tenths_ms == 100 {
1329 SilkFrameSize::TenMs
1330 } else {
1331 SilkFrameSize::TwentyMs
1332 };
1333
1334 let mut rd = RangeDecoder::new(frame);
1335 let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, false)?;
1336
1337 // No LBRR data → no FEC recovery is possible.
1338 if !(0..num_silk_frames).any(|i| header.mid_has_lbrr(i)) {
1339 return Ok(None);
1340 }
1341
1342 // §4.2.5 LBRR frames are always active-coded and form their own
1343 // inter-frame sequence; decode every present LBRR frame in
1344 // interval order, threading the LBRR-local previous gain / lag /
1345 // NLSF state (the same Table-5 inter-frame dependencies as regular
1346 // frames, but over the LBRR sub-sequence).
1347 let mut prev_gain: Option<u8> = None;
1348 let mut prev_lag: Option<i32> = None;
1349 let mut prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]> = None;
1350 let mut prev_nlsf_len = 0usize;
1351 let mut first = true;
1352 let mut lbrr_frames: Vec<SilkFrameDecoded> = Vec::new();
1353 for idx in 0..num_silk_frames {
1354 if !header.mid_has_lbrr(idx) {
1355 continue;
1356 }
1357 let cfg = SilkFrameConfig {
1358 bandwidth,
1359 frame_size,
1360 voice_active: true, // §4.2.5: all LBRR frames are active.
1361 first_subframe_independent: first || prev_gain.is_none(),
1362 previous_log_gain: prev_gain,
1363 previous_primary_lag: prev_lag,
1364 ltp_scaling_present: first,
1365 lsf_interp_after_reset: first || prev_nlsf.is_none(),
1366 previous_nlsf_q15: prev_nlsf,
1367 previous_nlsf_len: prev_nlsf_len,
1368 stereo: None,
1369 };
1370 let decoded = decode_silk_frame(&mut rd, cfg)?;
1371 prev_gain = Some(decoded.gains.last_log_gain());
1372 prev_lag = Some(decoded.ltp.primary_lag());
1373 prev_nlsf = Some(decoded.nlsf_q15);
1374 prev_nlsf_len = decoded.d_lpc;
1375 first = false;
1376 lbrr_frames.push(decoded);
1377 }
1378
1379 if rd.has_error() {
1380 return Err(Error::MalformedPacket);
1381 }
1382 if lbrr_frames.is_empty() {
1383 return Ok(None);
1384 }
1385
1386 // §4.2.7.9 synthesis from a fresh state: the lost frame's true
1387 // history is unavailable, so the recovered signal is reconstructed
1388 // self-contained. The resulting history then becomes the carried
1389 // mono synthesis state for the following real packet.
1390 let mut state = SilkSynthState::new(bandwidth)?;
1391 let mut internal = Vec::new();
1392 for decoded in &lbrr_frames {
1393 let frame_out = synthesize_silk_frame(bandwidth, frame_size, decoded, &mut state)?;
1394 internal.extend_from_slice(&frame_out);
1395 }
1396 self.silk_synth_mono = Some(state);
1397 Ok(Some((internal, bandwidth)))
1398 }
1399
1400 /// Decode and synthesize the §4.2.5 **stereo** LBRR frame(s) of one
1401 /// SILK-bearing Opus frame into internal-rate recovered L/R audio.
1402 ///
1403 /// Mirrors [`Self::decode_silk_fec_mono`] for stereo: the §4.2.5 LBRR
1404 /// frames are interleaved (mid then side per 20 ms interval), each
1405 /// channel is synthesized from a fresh state, and the pair is unmixed
1406 /// to left/right via §4.2.8 with a fresh unmix history. The §4.2.7.1
1407 /// stereo prediction weights ride on the mid LBRR frame; the §4.2.7.2
1408 /// mid-only flag governs whether a side LBRR frame is present for the
1409 /// interval (mirroring the regular stereo path).
1410 ///
1411 /// Returns `Ok(Some((left, right, bandwidth)))` on recovery,
1412 /// `Ok(None)` when neither channel carries LBRR, or `Err` on a
1413 /// malformed bitstream. On success the carried stereo synthesis +
1414 /// unmix state is replaced with the recovered-frame state.
1415 #[allow(clippy::type_complexity)]
1416 fn decode_silk_fec_stereo(
1417 &mut self,
1418 frame: &[u8],
1419 routing: &OpusFrameRouting,
1420 ) -> Result<Option<(Vec<f32>, Vec<f32>, crate::toc::Bandwidth)>, Error> {
1421 use crate::range_decoder::RangeDecoder;
1422 use crate::silk_decode::{decode_silk_frame, SilkFrameDecoded, StereoHeaderContext};
1423 use crate::silk_excitation::SilkFrameSize;
1424 use crate::silk_header::SilkHeaderBits;
1425 use crate::silk_stereo::{stereo_ms_to_lr, StereoUnmixState, StereoWeightsQ13};
1426 use crate::silk_synthesis::{synthesize_silk_frame, SilkSynthState};
1427
1428 let bandwidth = routing
1429 .silk_bandwidth
1430 .ok_or(Error::MalformedPacket)?
1431 .to_bandwidth();
1432 let num_silk_frames = routing
1433 .silk_frames_per_channel
1434 .ok_or(Error::MalformedPacket)?;
1435 let frame_size = if routing.frame_size_tenths_ms == 100 {
1436 SilkFrameSize::TenMs
1437 } else {
1438 SilkFrameSize::TwentyMs
1439 };
1440
1441 let mut rd = RangeDecoder::new(frame);
1442 let header = SilkHeaderBits::decode(&mut rd, num_silk_frames, true)?;
1443
1444 let any_lbrr =
1445 (0..num_silk_frames).any(|i| header.mid_has_lbrr(i) || header.side_has_lbrr(i));
1446 if !any_lbrr {
1447 return Ok(None);
1448 }
1449
1450 // §4.2.5 interleaved LBRR decode: per 20 ms interval the mid LBRR
1451 // frame (if present, carrying the §4.2.7.1 weights + §4.2.7.2
1452 // mid-only flag) then the side LBRR frame (if present). Each
1453 // channel threads its own LBRR-local inter-frame state.
1454 let mut mid_state = ChannelDecodeState::new();
1455 let mut side_state = ChannelDecodeState::new();
1456 let mut mid_frames: Vec<SilkFrameDecoded> = Vec::new();
1457 let mut side_frames: Vec<Option<SilkFrameDecoded>> = Vec::new();
1458 let mut interval_weights: Vec<StereoWeightsQ13> = Vec::new();
1459
1460 for idx in 0..num_silk_frames {
1461 let mid_lbrr = header.mid_has_lbrr(idx);
1462 let side_lbrr = header.side_has_lbrr(idx);
1463 if !mid_lbrr {
1464 // §4.2.5 / §4.2.7.1: a side LBRR frame without a mid LBRR
1465 // frame carries no stereo weights; record a zero-weight
1466 // interval with the mid channel treated as silent.
1467 if side_lbrr {
1468 let side_decoded = decode_silk_frame(
1469 &mut rd,
1470 side_state.config(bandwidth, frame_size, true, None),
1471 )?;
1472 side_state.advance(&side_decoded);
1473 // Without a mid LBRR frame there is no mid signal for
1474 // this interval; the unmixer treats the missing mid as
1475 // a hole (handled by skipping the interval in synthesis
1476 // below — we still consume the bits for alignment).
1477 let _ = side_decoded;
1478 }
1479 continue;
1480 }
1481 // §4.2.7.2: the mid-only flag is present on the mid LBRR frame
1482 // iff the side LBRR frame for this interval is absent.
1483 let stereo_ctx = StereoHeaderContext {
1484 has_mid_only_flag: !side_lbrr,
1485 };
1486 let mid_decoded = decode_silk_frame(
1487 &mut rd,
1488 mid_state.config(bandwidth, frame_size, true, Some(stereo_ctx)),
1489 )?;
1490 let w = mid_decoded.stereo_pred.map(|p| StereoWeightsQ13 {
1491 w0_q13: p.w0_q13,
1492 w1_q13: p.w1_q13,
1493 });
1494 interval_weights.push(w.unwrap_or_default());
1495 let side_coded = side_lbrr || mid_decoded.mid_only_flag == Some(false);
1496 mid_state.advance(&mid_decoded);
1497 mid_frames.push(mid_decoded);
1498
1499 if side_coded {
1500 let side_decoded = decode_silk_frame(
1501 &mut rd,
1502 side_state.config(bandwidth, frame_size, true, None),
1503 )?;
1504 side_state.advance(&side_decoded);
1505 side_frames.push(Some(side_decoded));
1506 } else {
1507 side_frames.push(None);
1508 }
1509 }
1510
1511 if rd.has_error() {
1512 return Err(Error::MalformedPacket);
1513 }
1514 if mid_frames.is_empty() {
1515 return Ok(None);
1516 }
1517
1518 // §4.2.7.9 synthesis + §4.2.8 unmix from fresh state.
1519 let mut mid_synth = SilkSynthState::new(bandwidth)?;
1520 let mut side_synth = SilkSynthState::new(bandwidth)?;
1521 let mut unmix = StereoUnmixState::new();
1522 let mut left = Vec::new();
1523 let mut right = Vec::new();
1524 for (idx, mid_frame) in mid_frames.iter().enumerate() {
1525 let mid_out = synthesize_silk_frame(bandwidth, frame_size, mid_frame, &mut mid_synth)?;
1526 let weights = interval_weights[idx];
1527 let stereo = match &side_frames[idx] {
1528 Some(side_frame) => {
1529 let side_out =
1530 synthesize_silk_frame(bandwidth, frame_size, side_frame, &mut side_synth)?;
1531 stereo_ms_to_lr(bandwidth, &mid_out, Some(&side_out), weights, &mut unmix)?
1532 }
1533 None => {
1534 side_synth.reset();
1535 stereo_ms_to_lr(bandwidth, &mid_out, None, weights, &mut unmix)?
1536 }
1537 };
1538 left.extend_from_slice(&stereo.left);
1539 right.extend_from_slice(&stereo.right);
1540 }
1541
1542 self.silk_synth_stereo = Some((mid_synth, side_synth));
1543 self.silk_stereo_unmix = Some(unmix);
1544 Ok(Some((left, right, bandwidth)))
1545 }
1546
1547 /// Decode one Hybrid Opus frame (§4.2 SILK + §4.3 CELT). Currently
1548 /// emits silence; depends on both layer paths landing.
1549 fn decode_hybrid_frame(
1550 &mut self,
1551 _frame: &[u8],
1552 routing: &OpusFrameRouting,
1553 pcm: &mut Vec<i16>,
1554 ) -> FrameOutcome {
1555 let per_channel = output_samples_per_channel(routing.frame_size_tenths_ms);
1556 push_silence(pcm, per_channel, routing.channel_count());
1557 FrameOutcome {
1558 samples_per_channel: per_channel,
1559 status: FrameDecodeStatus::LayerNotWired(OperatingMode::Hybrid),
1560 }
1561 }
1562}
1563
1564/// Append `per_channel * channels` interleaved zero samples to `pcm`.
1565fn push_silence(pcm: &mut Vec<i16>, per_channel: usize, channels: u8) {
1566 pcm.resize(pcm.len() + per_channel * channels as usize, 0);
1567}
1568
1569/// Per-channel inter-frame decode state threaded across the SILK frames
1570/// of one Opus frame (§4.2.7.4 previous gain, §4.2.7.6.1 previous lag,
1571/// §4.2.7.5.5 previous NLSF base, and the "first SILK frame of this type"
1572/// flag). One instance is used for the mid channel and one for the side
1573/// channel (each channel's frames form an independent sequence).
1574pub(crate) struct ChannelDecodeState {
1575 prev_gain: Option<u8>,
1576 prev_lag: Option<i32>,
1577 prev_nlsf: Option<[i16; crate::silk_lsf_stage2::D_LPC_MAX]>,
1578 prev_nlsf_len: usize,
1579 first: bool,
1580}
1581
1582impl ChannelDecodeState {
1583 pub(crate) fn new() -> Self {
1584 Self {
1585 prev_gain: None,
1586 prev_lag: None,
1587 prev_nlsf: None,
1588 prev_nlsf_len: 0,
1589 first: true,
1590 }
1591 }
1592
1593 /// Build the [`crate::silk_decode::SilkFrameConfig`] for the next SILK
1594 /// frame in this channel's sequence, given the §4.2.4 VAD flag and the
1595 /// optional §4.2.7.1 / §4.2.7.2 stereo header context (present only on
1596 /// the mid channel).
1597 pub(crate) fn config(
1598 &self,
1599 bandwidth: crate::toc::Bandwidth,
1600 frame_size: crate::silk_excitation::SilkFrameSize,
1601 voice_active: bool,
1602 stereo: Option<crate::silk_decode::StereoHeaderContext>,
1603 ) -> crate::silk_decode::SilkFrameConfig {
1604 crate::silk_decode::SilkFrameConfig {
1605 bandwidth,
1606 frame_size,
1607 voice_active,
1608 first_subframe_independent: self.first || self.prev_gain.is_none(),
1609 previous_log_gain: self.prev_gain,
1610 previous_primary_lag: self.prev_lag,
1611 ltp_scaling_present: self.first,
1612 lsf_interp_after_reset: self.first || self.prev_nlsf.is_none(),
1613 previous_nlsf_q15: self.prev_nlsf,
1614 previous_nlsf_len: self.prev_nlsf_len,
1615 stereo,
1616 }
1617 }
1618
1619 /// Fold a freshly decoded SILK frame into the carried state, so the
1620 /// next frame in this channel's sequence predicts against it.
1621 pub(crate) fn advance(&mut self, decoded: &crate::silk_decode::SilkFrameDecoded) {
1622 self.prev_gain = Some(decoded.gains.last_log_gain());
1623 self.prev_lag = Some(decoded.ltp.primary_lag());
1624 self.prev_nlsf = Some(decoded.nlsf_q15);
1625 self.prev_nlsf_len = decoded.d_lpc;
1626 self.first = false;
1627 }
1628}
1629
1630/// Resample one Opus frame's internal-rate SILK samples (`internal`, at
1631/// the §4.2.1 SILK internal rate for `bandwidth`) to the 48 kHz decoder
1632/// output rate and write the result, converted to signed 16-bit PCM, into
1633/// `out` (whose length is the §3.1 48 kHz per-channel sample count).
1634///
1635/// Per RFC 6716 §4.2.9 "the resampler itself is non-normative, and a
1636/// decoder can use any method it wants to perform the resampling." We use
1637/// linear interpolation between adjacent internal-rate samples — a simple,
1638/// total method that introduces only the small distortion the §4.2.7.9
1639/// preamble explicitly permits ("small errors should only introduce
1640/// proportionally small distortions"). A bit-exact match to a particular
1641/// reference resampler is **not** attempted; the RFC defers the kernel
1642/// choice to the implementation.
1643///
1644/// The `internal`-to-`out` length ratio is the integer rate ratio (6 for
1645/// NB 8 kHz, 4 for MB 12 kHz, 3 for WB 16 kHz → 48 kHz), so the linear
1646/// interpolation positions are exact rationals; no fractional drift
1647/// accumulates across frames.
1648fn resample_internal_to_output_i16(
1649 internal: &[f32],
1650 bandwidth: crate::toc::Bandwidth,
1651 out: &mut [i16],
1652) {
1653 if out.is_empty() {
1654 return;
1655 }
1656 if internal.is_empty() {
1657 for o in out.iter_mut() {
1658 *o = 0;
1659 }
1660 return;
1661 }
1662 let in_len = internal.len();
1663 let out_len = out.len();
1664 // The internal-rate sample position for output sample `i` is
1665 // `i * in_len / out_len`. Linear-interpolate between the two
1666 // bracketing internal samples.
1667 let _ = bandwidth; // the rate ratio is implied by in_len / out_len.
1668 for (i, o) in out.iter_mut().enumerate() {
1669 let pos = (i as f64) * (in_len as f64) / (out_len as f64);
1670 let i0 = pos.floor() as usize;
1671 let frac = (pos - i0 as f64) as f32;
1672 let s0 = internal[i0.min(in_len - 1)];
1673 let s1 = internal[(i0 + 1).min(in_len - 1)];
1674 let v = s0 + (s1 - s0) * frac;
1675 *o = f32_to_i16(v);
1676 }
1677}
1678
1679/// Resample a stereo pair of internal-rate SILK channels (`left` /
1680/// `right`, both at the §4.2.1 SILK internal rate for `bandwidth`) to the
1681/// 48 kHz output rate and write them **interleaved** (`[L0, R0, L1, R1,
1682/// …]`) into `out` (length `2 * per_channel`).
1683///
1684/// Per RFC 6716 §4.2.9 the resampler is non-normative; we use the same
1685/// linear interpolation as the mono path on each channel independently.
1686fn resample_stereo_to_output_i16(
1687 left: &[f32],
1688 right: &[f32],
1689 bandwidth: crate::toc::Bandwidth,
1690 out: &mut [i16],
1691) {
1692 let per_channel = out.len() / 2;
1693 if per_channel == 0 {
1694 return;
1695 }
1696 // Resample each channel into a scratch buffer, then interleave.
1697 let mut l = vec![0i16; per_channel];
1698 let mut r = vec![0i16; per_channel];
1699 resample_internal_to_output_i16(left, bandwidth, &mut l);
1700 resample_internal_to_output_i16(right, bandwidth, &mut r);
1701 for i in 0..per_channel {
1702 out[2 * i] = l[i];
1703 out[2 * i + 1] = r[i];
1704 }
1705}
1706
1707/// Convert a nominal `[-1.0, 1.0]` float sample to signed 16-bit PCM,
1708/// rounding to nearest and clamping into the i16 range. The §4.2.7.9.2
1709/// output is already clamped to `[-1.0, 1.0]`; the clamp here is a
1710/// defensive backstop.
1711fn f32_to_i16(v: f32) -> i16 {
1712 let scaled = (v.clamp(-1.0, 1.0) * 32767.0).round();
1713 scaled as i16
1714}
1715
1716/// Convenience: the channel count for a [`ChannelMapping`].
1717pub fn channel_count(mapping: ChannelMapping) -> u8 {
1718 match mapping {
1719 ChannelMapping::Mono => 1,
1720 ChannelMapping::Stereo => 2,
1721 }
1722}
1723
1724#[cfg(test)]
1725mod tests {
1726 use super::*;
1727 use crate::toc::OpusTocByte;
1728
1729 /// Build a minimal code-0 packet: TOC byte + a non-empty single
1730 /// frame body. `config` is the 5-bit §3.1 config, `stereo` the s bit.
1731 fn code0_packet(config: u8, stereo: bool, body: &[u8]) -> Vec<u8> {
1732 let toc = (config << 3) | (if stereo { 1 << 2 } else { 0 });
1733 let mut p = vec![toc];
1734 p.extend_from_slice(body);
1735 p
1736 }
1737
1738 #[test]
1739 fn output_samples_per_channel_matches_table2_durations() {
1740 // (tenths-ms, expected 48 kHz samples/channel)
1741 let cases = [
1742 (25u16, 120usize), // 2.5 ms CELT
1743 (50, 240), // 5 ms
1744 (100, 480), // 10 ms
1745 (200, 960), // 20 ms
1746 (400, 1920), // 40 ms
1747 (600, 2880), // 60 ms
1748 ];
1749 for (tenths, expected) in cases {
1750 assert_eq!(
1751 output_samples_per_channel(tenths),
1752 expected,
1753 "tenths={tenths}"
1754 );
1755 }
1756 }
1757
1758 #[test]
1759 fn empty_packet_rejected() {
1760 let mut dec = OpusDecoder::new();
1761 assert_eq!(dec.decode_packet(&[]), Err(Error::EmptyPacket));
1762 }
1763
1764 #[test]
1765 fn silk_nb_mono_20ms_single_frame_pcm_length() {
1766 // config 1 = SILK NB 20 ms (200 tenths-ms), mono, code 0.
1767 let pkt = code0_packet(1, false, &[0x12, 0x34, 0x56]);
1768 let mut dec = OpusDecoder::new();
1769 let out = dec.decode_packet(&pkt).expect("decode");
1770 assert_eq!(out.channels, 1);
1771 assert_eq!(out.sample_rate_hz, OUTPUT_SAMPLE_RATE_HZ);
1772 assert_eq!(out.samples_per_channel(), 960);
1773 assert_eq!(out.pcm.len(), 960);
1774 assert_eq!(out.frame_outcomes.len(), 1);
1775 // A mono SILK-only frame now runs the real §4.2 bitstream decode;
1776 // the status is either a clean params-decoded or a decode-error
1777 // (a 3-byte arbitrary body may truncate mid-frame), never the
1778 // not-wired placeholder.
1779 assert!(
1780 matches!(
1781 out.frame_outcomes[0].status,
1782 FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkDecodeError
1783 ),
1784 "got {:?}",
1785 out.frame_outcomes[0].status
1786 );
1787 }
1788
1789 #[test]
1790 fn celt_only_stereo_pcm_is_interleaved_length() {
1791 // config 20 = CELT-only, second size in the NB/WB group; stereo.
1792 let pkt = code0_packet(20, true, &[0xaa, 0xbb]);
1793 let mut dec = OpusDecoder::new();
1794 let out = dec.decode_packet(&pkt).expect("decode");
1795 assert_eq!(out.channels, 2);
1796 // 2 channels interleaved => pcm len = 2 * samples_per_channel.
1797 assert_eq!(out.pcm.len(), 2 * out.samples_per_channel());
1798 let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
1799 // A CELT-only frame now decodes its §4.3.7.1 prefix and, when
1800 // non-silent, its §4.3.2.1 coarse energy from the real range
1801 // coder — so the status is one of the real CELT outcomes
1802 // (silence / coarse-energy-decoded / a decode error on a 2-byte
1803 // body), never the not-wired placeholder.
1804 assert!(
1805 matches!(
1806 out.frame_outcomes[0].status,
1807 FrameDecodeStatus::CeltSilence
1808 | FrameDecodeStatus::CeltCoarseEnergyDecoded
1809 | FrameDecodeStatus::CeltAllocationDecoded
1810 | FrameDecodeStatus::CeltDecodeError
1811 ),
1812 "got {:?}",
1813 out.frame_outcomes[0].status
1814 );
1815 assert_eq!(routing.operating_mode, OperatingMode::CeltOnly);
1816 }
1817
1818 #[test]
1819 fn code1_two_equal_frames_concatenate_pcm() {
1820 // config 0 = SILK NB 10 ms (100 tenths => 480 samples/ch), mono.
1821 // Code 1 = two equal frames; body must be even length.
1822 // config 0 (<< 3 = 0), mono, code 1 (0b01).
1823 let toc = 0b01u8;
1824 let mut pkt = vec![toc];
1825 pkt.extend_from_slice(&[1, 2, 3, 4]); // two 2-byte frames
1826 let mut dec = OpusDecoder::new();
1827 let out = dec.decode_packet(&pkt).expect("decode");
1828 assert_eq!(out.frame_outcomes.len(), 2);
1829 // Two 10 ms frames => 2 * 480 = 960 samples/channel.
1830 assert_eq!(out.samples_per_channel(), 960);
1831 assert_eq!(out.pcm.len(), 960);
1832 }
1833
1834 #[test]
1835 fn dtx_zero_length_frame_emits_silence_with_status() {
1836 // Code 3 VBR with a zero-length (DTX) frame. Build a code-3
1837 // packet by hand: TOC, frame-count byte, then VBR lengths.
1838 // Simpler: rely on code-2 unequal where the first frame length 0
1839 // is a valid DTX marker per §3.2.1.
1840 // config 0 (<< 3 = 0) SILK NB 10 ms mono, code 2 (0b10).
1841 let toc = 0b10u8;
1842 // code 2 body: a length prefix for frame 1, then frame1, then
1843 // frame2 is the remainder. Length 0 => frame1 is DTX.
1844 let pkt = vec![toc, 0x00, 0x07];
1845 let mut dec = OpusDecoder::new();
1846 let out = dec.decode_packet(&pkt).expect("decode");
1847 assert_eq!(out.frame_outcomes.len(), 2);
1848 assert_eq!(out.frame_outcomes[0].status, FrameDecodeStatus::DtxOrLost);
1849 // Both frames are 10 ms => 480 samples/channel each.
1850 assert_eq!(out.samples_per_channel(), 960);
1851 }
1852
1853 #[test]
1854 fn reset_clears_carried_channel_state() {
1855 let mut dec = OpusDecoder::new();
1856 let stereo = code0_packet(20, true, &[1, 2]);
1857 dec.decode_packet(&stereo).expect("decode");
1858 assert_eq!(dec.last_channels, Some(2));
1859 dec.reset();
1860 assert_eq!(dec.last_channels, None);
1861 }
1862
1863 #[test]
1864 fn celt_to_silk_transition_resets_silk_state() {
1865 // §4.5.2: the SILK state is reset before a SILK-only frame whose
1866 // predecessor was CELT-only. With CELT not yet wired (a CELT-only
1867 // packet emits silence and touches no SILK state), a SILK packet
1868 // followed by a CELT packet followed by the same SILK packet must
1869 // produce the *same* PCM as a fresh decoder running that SILK
1870 // packet once — because the §4.5.2 reset clears the carried
1871 // §4.2.7.9 history the first SILK packet left behind.
1872 let silk_body: Vec<u8> = (0..200u16)
1873 .map(|i| (i.wrapping_mul(149).wrapping_add(11) & 0xff) as u8)
1874 .collect();
1875 let silk_pkt = code0_packet(1, false, &silk_body); // config 1 = SILK NB 20 ms mono.
1876 let celt_pkt = code0_packet(17, false, &[0xaa, 0xbb]); // config 17 = CELT-only mono.
1877
1878 // Reference: a fresh decoder running the SILK packet once.
1879 let mut ref_dec = OpusDecoder::new();
1880 let reference = ref_dec.decode_packet(&silk_pkt).expect("decode");
1881
1882 // Sequence: SILK, then CELT (resets SILK state on the *next* SILK
1883 // frame), then SILK again. The third packet must match the
1884 // reference if and only if the §4.5.2 reset fired.
1885 let mut seq_dec = OpusDecoder::new();
1886 seq_dec.decode_packet(&silk_pkt).expect("decode");
1887 seq_dec.decode_packet(&celt_pkt).expect("decode");
1888 let after_reset = seq_dec.decode_packet(&silk_pkt).expect("decode");
1889
1890 // Only compare when the SILK frame actually synthesized audio.
1891 if reference.frame_outcomes[0].status == FrameDecodeStatus::SilkParamsDecoded {
1892 assert_eq!(
1893 after_reset.pcm, reference.pcm,
1894 "§4.5.2 CELT→SILK transition must reset SILK state"
1895 );
1896 }
1897 }
1898
1899 #[test]
1900 fn silk_to_silk_no_reset_threads_state() {
1901 // The complement of the §4.5.2 test: two consecutive SILK-only
1902 // packets (no CELT interlude) do NOT reset the SILK state, so the
1903 // second packet's output generally differs from a fresh-decoder
1904 // decode of that packet (the carried §4.2.7.9 history changes the
1905 // LPC/LTP synthesis). This pins that state actually threads when
1906 // it should.
1907 let silk_body: Vec<u8> = (0..200u16)
1908 .map(|i| (i.wrapping_mul(149).wrapping_add(11) & 0xff) as u8)
1909 .collect();
1910 let silk_pkt = code0_packet(1, false, &silk_body);
1911
1912 let mut fresh = OpusDecoder::new();
1913 let fresh_out = fresh.decode_packet(&silk_pkt).expect("decode");
1914
1915 let mut threaded = OpusDecoder::new();
1916 threaded.decode_packet(&silk_pkt).expect("decode");
1917 let second = threaded.decode_packet(&silk_pkt).expect("decode");
1918
1919 // Both decode to the same length; the carried state means the
1920 // second decode is at least a valid, finite PCM buffer.
1921 assert_eq!(second.pcm.len(), fresh_out.pcm.len());
1922 }
1923
1924 #[test]
1925 fn silk_mono_full_decode_consumes_bitstream_cleanly() {
1926 // A long pseudo-random SILK NB mono 20 ms body: the range coder
1927 // does not run out of bits, so the full §4.2 frame decodes and the
1928 // status is the clean params-decoded outcome (not a decode error).
1929 let body: Vec<u8> = (0..120u16)
1930 .map(|i| (i.wrapping_mul(101).wrapping_add(7) & 0xff) as u8)
1931 .collect();
1932 let pkt = code0_packet(1, false, &body); // config 1 = SILK NB 20 ms.
1933 let mut dec = OpusDecoder::new();
1934 let out = dec.decode_packet(&pkt).expect("decode");
1935 assert_eq!(out.frame_outcomes.len(), 1);
1936 assert_eq!(
1937 out.frame_outcomes[0].status,
1938 FrameDecodeStatus::SilkParamsDecoded,
1939 "a long SILK NB mono body should fully decode"
1940 );
1941 // PCM length is correct even though the samples are silence
1942 // (synthesis pending).
1943 assert_eq!(out.samples_per_channel(), 960);
1944 }
1945
1946 #[test]
1947 fn silk_mono_40ms_two_silk_frames_decode() {
1948 // config 2 = SILK NB 40 ms => 2 SILK frames per channel; mono.
1949 let body: Vec<u8> = (0..220u16)
1950 .map(|i| (i.wrapping_mul(53).wrapping_add(3) & 0xff) as u8)
1951 .collect();
1952 let pkt = code0_packet(2, false, &body);
1953 let mut dec = OpusDecoder::new();
1954 let out = dec.decode_packet(&pkt).expect("decode");
1955 let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
1956 assert_eq!(routing.silk_frames_per_channel, Some(2));
1957 // 40 ms => 1920 samples/channel; one Opus frame (code 0).
1958 assert_eq!(out.frame_outcomes.len(), 1);
1959 assert_eq!(out.samples_per_channel(), 1920);
1960 // The two-SILK-frame loop ran; the status reflects a SILK decode
1961 // (clean or truncated), never the not-wired placeholder.
1962 assert!(matches!(
1963 out.frame_outcomes[0].status,
1964 FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkDecodeError
1965 ));
1966 }
1967
1968 #[test]
1969 fn stereo_silk_only_decodes_to_interleaved_pcm() {
1970 // Stereo SILK now runs the full §4.2 interleaved mid/side decode +
1971 // §4.2.8 unmix. A long pseudo-random body decodes cleanly; the
1972 // output is interleaved L/R 48 kHz PCM.
1973 let body: Vec<u8> = (0..220u16)
1974 .map(|i| (i.wrapping_mul(137).wrapping_add(19) & 0xff) as u8)
1975 .collect();
1976 let pkt = code0_packet(1, true, &body); // config 1 = SILK NB 20 ms stereo.
1977 let mut dec = OpusDecoder::new();
1978 let out = dec.decode_packet(&pkt).expect("decode");
1979 assert_eq!(out.channels, 2);
1980 assert_eq!(out.samples_per_channel(), 960);
1981 assert_eq!(out.pcm.len(), 2 * 960);
1982 assert!(matches!(
1983 out.frame_outcomes[0].status,
1984 FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
1985 ));
1986 }
1987
1988 #[test]
1989 fn stereo_silk_clean_body_is_fully_decoded() {
1990 // A buffer long enough that the range coder never starves: the
1991 // interleaved mid/side decode + unmix completes, yielding the
1992 // stereo-decoded status (not a decode error, not not-wired).
1993 let body: Vec<u8> = (0..400u16)
1994 .map(|i| (i.wrapping_mul(97).wrapping_add(41) & 0xff) as u8)
1995 .collect();
1996 let pkt = code0_packet(1, true, &body);
1997 let mut dec = OpusDecoder::new();
1998 let out = dec.decode_packet(&pkt).expect("decode");
1999 assert_eq!(
2000 out.frame_outcomes[0].status,
2001 FrameDecodeStatus::SilkStereoDecoded,
2002 "a long stereo SILK NB body should fully decode"
2003 );
2004 // The output is finite and within i16 range by construction.
2005 assert_eq!(out.pcm.len(), 2 * 960);
2006 }
2007
2008 #[test]
2009 fn stereo_silk_40ms_two_intervals_decode() {
2010 // config 2 = SILK NB 40 ms => 2 SILK frames per channel; stereo.
2011 // The §4.2.2 interleave runs mid/side per 20 ms interval twice.
2012 let body: Vec<u8> = (0..480u16)
2013 .map(|i| (i.wrapping_mul(61).wrapping_add(7) & 0xff) as u8)
2014 .collect();
2015 let pkt = code0_packet(2, true, &body);
2016 let mut dec = OpusDecoder::new();
2017 let out = dec.decode_packet(&pkt).expect("decode");
2018 let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
2019 assert_eq!(routing.silk_frames_per_channel, Some(2));
2020 assert_eq!(out.channels, 2);
2021 // 40 ms => 1920 samples/channel interleaved.
2022 assert_eq!(out.samples_per_channel(), 1920);
2023 assert_eq!(out.pcm.len(), 2 * 1920);
2024 assert!(matches!(
2025 out.frame_outcomes[0].status,
2026 FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
2027 ));
2028 }
2029
2030 #[test]
2031 fn stereo_silk_60ms_three_intervals_per_interval_unmix() {
2032 // config 3 = SILK NB 60 ms => 3 SILK frames per channel; stereo.
2033 // Each 20 ms interval is unmixed separately (its own §4.2.7.1
2034 // weights + a fresh §4.2.8 interpolation phase), and the three
2035 // L/R interval outputs are concatenated. This pins the per-interval
2036 // unmix path for a multi-interval stereo frame.
2037 let body: Vec<u8> = (0..640u16)
2038 .map(|i| (i.wrapping_mul(73).wrapping_add(31) & 0xff) as u8)
2039 .collect();
2040 let pkt = code0_packet(3, true, &body);
2041 let mut dec = OpusDecoder::new();
2042 let out = dec.decode_packet(&pkt).expect("decode");
2043 let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
2044 assert_eq!(routing.silk_frames_per_channel, Some(3));
2045 assert_eq!(out.channels, 2);
2046 // 60 ms => 2880 samples/channel interleaved.
2047 assert_eq!(out.samples_per_channel(), 2880);
2048 assert_eq!(out.pcm.len(), 2 * 2880);
2049 assert!(matches!(
2050 out.frame_outcomes[0].status,
2051 FrameDecodeStatus::SilkStereoDecoded | FrameDecodeStatus::SilkDecodeError
2052 ));
2053 }
2054
2055 #[test]
2056 fn stereo_silk_state_threads_across_packets() {
2057 // Two consecutive stereo SILK packets thread the §4.2.7.9 + §4.2.8
2058 // histories: the second packet's output may differ from a fresh
2059 // decode, but both are valid finite buffers of equal length.
2060 let body: Vec<u8> = (0..300u16)
2061 .map(|i| (i.wrapping_mul(113).wrapping_add(23) & 0xff) as u8)
2062 .collect();
2063 let pkt = code0_packet(1, true, &body);
2064
2065 let mut fresh = OpusDecoder::new();
2066 let fresh_out = fresh.decode_packet(&pkt).expect("decode");
2067
2068 let mut threaded = OpusDecoder::new();
2069 threaded.decode_packet(&pkt).expect("decode");
2070 let second = threaded.decode_packet(&pkt).expect("decode");
2071 assert_eq!(second.pcm.len(), fresh_out.pcm.len());
2072 }
2073
2074 #[test]
2075 fn mono_to_stereo_transition_resets_stereo_state() {
2076 // §4.2.7.1: previous stereo weights reset on a mono→stereo
2077 // transition. A mono packet, then a stereo packet, then the same
2078 // stereo packet must leave the second stereo decode in a defined
2079 // state (no panic; correct length). The mono→stereo channel-count
2080 // change clears the carried stereo history.
2081 let mono_body: Vec<u8> = (0..200u16)
2082 .map(|i| (i.wrapping_mul(71).wrapping_add(5) & 0xff) as u8)
2083 .collect();
2084 let stereo_body: Vec<u8> = (0..300u16)
2085 .map(|i| (i.wrapping_mul(89).wrapping_add(11) & 0xff) as u8)
2086 .collect();
2087 let mono_pkt = code0_packet(1, false, &mono_body);
2088 let stereo_pkt = code0_packet(1, true, &stereo_body);
2089
2090 let mut dec = OpusDecoder::new();
2091 dec.decode_packet(&mono_pkt).expect("mono");
2092 let out = dec.decode_packet(&stereo_pkt).expect("stereo");
2093 assert_eq!(out.channels, 2);
2094 assert_eq!(out.pcm.len(), 2 * 960);
2095 }
2096
2097 #[test]
2098 fn pcm_length_matches_routing_for_every_config() {
2099 // Every Table-2 config decodes to a PCM buffer of the routing's
2100 // 48 kHz length × channels. Mono SILK-only configs now synthesize
2101 // real audio (§4.2.7.9); the still-unwired layers (CELT-only,
2102 // Hybrid, and stereo SILK) emit correct-length silence. This sweep
2103 // pins the length invariant for all 32 configs and the silence
2104 // invariant for the not-yet-wired ones.
2105 let mut dec = OpusDecoder::new();
2106 for config in 0u8..32 {
2107 for stereo in [false, true] {
2108 let pkt = code0_packet(config, stereo, &[0x55, 0x66, 0x77]);
2109 let out = dec.decode_packet(&pkt).expect("decode");
2110 let routing = OpusFrameRouting::from_toc(OpusTocByte::from_byte(pkt[0]));
2111 let expected = output_samples_per_channel(routing.frame_size_tenths_ms)
2112 * out.channels as usize;
2113 assert_eq!(out.pcm.len(), expected, "config {config} stereo {stereo}");
2114 // The unwired layers (everything except a successfully
2115 // synthesized mono or stereo SILK-only frame) still emit
2116 // silence.
2117 let is_wired_silk = matches!(
2118 out.frame_outcomes[0].status,
2119 FrameDecodeStatus::SilkParamsDecoded | FrameDecodeStatus::SilkStereoDecoded
2120 );
2121 if !is_wired_silk {
2122 assert!(
2123 out.pcm.iter().all(|&s| s == 0),
2124 "config {config} stereo {stereo} status {:?} should be silence",
2125 out.frame_outcomes[0].status
2126 );
2127 }
2128 // The decoder must be reset between configs so the carried
2129 // §4.2.7.9 synthesis history of one bandwidth doesn't leak
2130 // into the next.
2131 dec.reset();
2132 }
2133 }
2134 }
2135
2136 #[test]
2137 fn mono_silk_frame_can_emit_nonsilent_pcm() {
2138 // A long pseudo-random mono SILK NB 20 ms body decodes cleanly and
2139 // is synthesized through the §4.2.7.9 LTP/LPC filters + §4.2.9
2140 // resample; the emitted PCM is no longer forced to silence. (The
2141 // exact samples are not pinned — there is no codec-level bit-exact
2142 // fixture yet — but a clean params-decoded frame produces a
2143 // correctly-sized 48 kHz buffer.)
2144 let body: Vec<u8> = (0..200u16)
2145 .map(|i| (i.wrapping_mul(181).wrapping_add(13) & 0xff) as u8)
2146 .collect();
2147 let pkt = code0_packet(1, false, &body); // config 1 = SILK NB 20 ms.
2148 let mut dec = OpusDecoder::new();
2149 let out = dec.decode_packet(&pkt).expect("decode");
2150 assert_eq!(out.channels, 1);
2151 assert_eq!(out.samples_per_channel(), 960);
2152 if out.frame_outcomes[0].status == FrameDecodeStatus::SilkParamsDecoded {
2153 // A successfully synthesized frame produces a full-length
2154 // buffer; every sample is a valid i16 (no panic / overflow).
2155 assert_eq!(out.pcm.len(), 960);
2156 }
2157 }
2158
2159 /// Search for a CELT body whose §4.3.7.1 prefix decodes silence = 1
2160 /// with the post-filter off, so the frame takes the fully-wired
2161 /// silence synthesis path. Returns the body bytes appended after the
2162 /// TOC. The search is deterministic (fixed candidate set), so the
2163 /// chosen body is stable across runs.
2164 fn find_celt_silence_body() -> Vec<u8> {
2165 use crate::celt_frame_prefix::decode_celt_frame_prefix;
2166 use crate::range_decoder::RangeDecoder;
2167 // The silence flag is the {32767,1}/32768 "1" branch (probability
2168 // 2^-15), so a silent frame is rare in random bytes; sweep the
2169 // first two bytes (with a trailing zero run that keeps the
2170 // post-filter off) to find one deterministically.
2171 for b0 in 0u16..=255 {
2172 for b1 in 0u16..=255 {
2173 let buf = [b0 as u8, b1 as u8, 0, 0, 0, 0];
2174 let mut rd = RangeDecoder::new(&buf);
2175 let p = decode_celt_frame_prefix(&mut rd);
2176 if p.silence && p.post_filter.is_none() && !rd.has_error() {
2177 return buf.to_vec();
2178 }
2179 }
2180 }
2181 panic!("no CELT silence body found in the candidate set");
2182 }
2183
2184 #[test]
2185 fn celt_only_silence_frame_decodes_end_to_end() {
2186 // config 17 = CELT-only mono, 5 ms (Table-55 second column) →
2187 // 240 samples/channel at 48 kHz.
2188 let body = find_celt_silence_body();
2189 let pkt = code0_packet(17, false, &body);
2190 let mut dec = OpusDecoder::new();
2191 let out = dec.decode_packet(&pkt).expect("decode");
2192 assert_eq!(out.channels, 1);
2193 assert_eq!(out.samples_per_channel(), 240);
2194 assert_eq!(
2195 out.frame_outcomes[0].status,
2196 FrameDecodeStatus::CeltSilence,
2197 "silence-flagged CELT frame must take the wired synthesis path"
2198 );
2199 // The frame is silent: every emitted sample is zero (a zero-energy
2200 // band envelope synthesizes to a zero time-domain block, and the
2201 // overlap-add / de-emphasis of an all-zero history stays zero).
2202 assert_eq!(out.pcm.len(), 240);
2203 assert!(
2204 out.pcm.iter().all(|&s| s == 0),
2205 "silence frame must be all zero"
2206 );
2207 }
2208
2209 #[test]
2210 fn celt_silence_advances_synthesis_state() {
2211 // Two consecutive CELT silence frames both decode through the
2212 // wired path; the second reuses the carried CeltSynthState (no
2213 // rebuild), and both emit silence of the correct length.
2214 let body = find_celt_silence_body();
2215 let pkt = code0_packet(17, false, &body);
2216 let mut dec = OpusDecoder::new();
2217 let first = dec.decode_packet(&pkt).expect("decode");
2218 let second = dec.decode_packet(&pkt).expect("decode");
2219 assert_eq!(
2220 first.frame_outcomes[0].status,
2221 FrameDecodeStatus::CeltSilence
2222 );
2223 assert_eq!(
2224 second.frame_outcomes[0].status,
2225 FrameDecodeStatus::CeltSilence
2226 );
2227 assert!(second.pcm.iter().all(|&s| s == 0));
2228 }
2229
2230 #[test]
2231 fn celt_non_silent_frame_decodes_coarse_energy() {
2232 // A CELT body whose silence flag is clear now takes the
2233 // §4.3.2.1 coarse-energy decode path: the per-band log-energy
2234 // envelope is reconstructed from the real range coder, the
2235 // cross-frame predictor state is threaded, and the synthesis
2236 // backend is advanced with all-zero bands (the band-shape stages
2237 // are still pending). The frame must report
2238 // CeltCoarseEnergyDecoded — or CeltDecodeError if the short body
2239 // truncates mid-decode — never the not-wired placeholder, never
2240 // a panic, and emit silence of the correct length.
2241 use crate::celt_frame_prefix::decode_celt_frame_prefix;
2242 use crate::range_decoder::RangeDecoder;
2243 // Find a longer body with silence = 0 and no range-coder error in
2244 // the prefix (the 21-band coarse decode needs enough bytes to not
2245 // immediately truncate).
2246 let mut chosen: Option<Vec<u8>> = None;
2247 for b0 in 0u16..=255 {
2248 let buf = [
2249 b0 as u8, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
2250 ];
2251 let mut rd = RangeDecoder::new(&buf);
2252 let p = decode_celt_frame_prefix(&mut rd);
2253 if !p.silence && !rd.has_error() {
2254 chosen = Some(buf.to_vec());
2255 break;
2256 }
2257 }
2258 let body = chosen.expect("a non-silent CELT body exists in the candidate set");
2259 let pkt = code0_packet(17, false, &body);
2260 let mut dec = OpusDecoder::new();
2261 let out = dec.decode_packet(&pkt).expect("decode");
2262 assert!(
2263 matches!(
2264 out.frame_outcomes[0].status,
2265 FrameDecodeStatus::CeltCoarseEnergyDecoded
2266 | FrameDecodeStatus::CeltAllocationDecoded
2267 | FrameDecodeStatus::CeltDecodeError
2268 ),
2269 "got {:?}",
2270 out.frame_outcomes[0].status
2271 );
2272 assert_eq!(out.pcm.len(), 240);
2273 }
2274
2275 #[test]
2276 fn celt_coarse_energy_threads_predictor_across_frames() {
2277 // Two successive non-silent CELT-only inter frames must thread the
2278 // coarse-energy predictor state: after the first decodes, the
2279 // decoder carries a CoarseEnergyState; the second reuses it.
2280 use crate::celt_frame_prefix::decode_celt_frame_prefix;
2281 use crate::range_decoder::RangeDecoder;
2282 let mut chosen: Option<Vec<u8>> = None;
2283 for b0 in 0u16..=255 {
2284 let buf = [
2285 b0 as u8, 0x33, 0xcc, 0x55, 0xaa, 0x0f, 0xf0, 0x12, 0x9a, 0x4e,
2286 ];
2287 let mut rd = RangeDecoder::new(&buf);
2288 let p = decode_celt_frame_prefix(&mut rd);
2289 if !p.silence && !p.intra && !rd.has_error() {
2290 chosen = Some(buf.to_vec());
2291 break;
2292 }
2293 }
2294 // Not every leading byte yields a non-silent, non-intra prefix; if
2295 // none does, the threading invariant is still exercised by the
2296 // single-frame test above, so skip silently.
2297 if let Some(body) = chosen {
2298 let pkt = code0_packet(19, false, &body); // 20 ms CELT-only mono
2299 let mut dec = OpusDecoder::new();
2300 let first = dec.decode_packet(&pkt).expect("decode");
2301 // After a successful coarse decode the predictor state exists.
2302 // (A non-silent inter frame now also runs the §4.3.3 allocation
2303 // header, so the terminal status is `CeltAllocationDecoded`; a
2304 // truncated allocation header falls back to `CeltDecodeError`,
2305 // but the coarse predictor state was already threaded before
2306 // that point regardless.)
2307 if matches!(
2308 first.frame_outcomes[0].status,
2309 FrameDecodeStatus::CeltCoarseEnergyDecoded
2310 | FrameDecodeStatus::CeltAllocationDecoded
2311 ) {
2312 assert!(dec.celt_coarse.is_some());
2313 }
2314 let _second = dec.decode_packet(&pkt).expect("decode");
2315 }
2316 }
2317
2318 #[test]
2319 fn celt_non_silent_frame_decodes_allocation_header() {
2320 // On top of the §4.3.2.1 coarse energy, a non-silent CELT-only
2321 // frame now consumes the §4.3.3 *signalled* allocation header
2322 // (band boosts + alloc trim + reservations) from the same range
2323 // coder. With a body long enough to survive the 21-band coarse
2324 // decode plus the boost/trim symbols, the terminal status is
2325 // `CeltAllocationDecoded`; a body that truncates mid-header still
2326 // reports a real CELT outcome (never the not-wired placeholder),
2327 // never panics, and emits silence of the correct length.
2328 use crate::celt_frame_prefix::decode_celt_frame_prefix;
2329 use crate::range_decoder::RangeDecoder;
2330
2331 // A 20 ms CELT-only frame (config 19) has 21 coded bands; pick a
2332 // generous body so the allocation header has room to decode.
2333 let mut chosen: Option<Vec<u8>> = None;
2334 for b0 in 0u16..=255 {
2335 let buf = [
2336 b0 as u8, 0x91, 0x37, 0xc4, 0x6e, 0x2d, 0xa8, 0x5b, 0xf1, 0x0c, 0x93, 0x47, 0xbe,
2337 0x21,
2338 ];
2339 let mut rd = RangeDecoder::new(&buf);
2340 let p = decode_celt_frame_prefix(&mut rd);
2341 if !p.silence && !rd.has_error() {
2342 chosen = Some(buf.to_vec());
2343 break;
2344 }
2345 }
2346 let body = chosen.expect("a non-silent CELT body exists in the candidate set");
2347 let pkt = code0_packet(19, false, &body); // 20 ms CELT-only mono
2348 let mut dec = OpusDecoder::new();
2349 let out = dec.decode_packet(&pkt).expect("decode");
2350
2351 // Whatever the body's exact entropy content, the status must be a
2352 // real CELT outcome that reflects an actually-consumed bitstream,
2353 // and the per-channel length is the 20 ms 48 kHz count (960).
2354 assert!(
2355 matches!(
2356 out.frame_outcomes[0].status,
2357 FrameDecodeStatus::CeltAllocationDecoded
2358 | FrameDecodeStatus::CeltCoarseEnergyDecoded
2359 | FrameDecodeStatus::CeltDecodeError
2360 ),
2361 "got {:?}",
2362 out.frame_outcomes[0].status
2363 );
2364 assert_eq!(out.pcm.len(), 960);
2365 }
2366
2367 #[test]
2368 fn celt_tf_spread_allocation_advances_tell_past_coarse_energy() {
2369 // Direct exercise of the §4.3.1 TF + §4.3.4.3 spread + §4.3.3
2370 // allocation-header decoder: it must advance the range coder
2371 // strictly past where the §4.3.2.1 coarse energy left it (the
2372 // tf_change / spread / boost symbols consume real bits), and it
2373 // must not panic or report a caller-side bookkeeping error for a
2374 // well-formed band window.
2375 use crate::celt_band_layout::{celt_end_coded_band, celt_first_coded_band, CeltFrameSize};
2376 use crate::celt_coarse_energy::CoarseEnergyState;
2377 use crate::celt_frame_prefix::decode_celt_frame_prefix;
2378 use crate::range_decoder::RangeDecoder;
2379
2380 let body: [u8; 14] = [
2381 0x40, 0x91, 0x37, 0xc4, 0x6e, 0x2d, 0xa8, 0x5b, 0xf1, 0x0c, 0x93, 0x47, 0xbe, 0x21,
2382 ];
2383 let mut rd = RangeDecoder::new(&body);
2384 let prefix = decode_celt_frame_prefix(&mut rd);
2385 // The chosen first byte must not select silence for this test to
2386 // be meaningful; assert it so a table change can't silently void
2387 // the assertion.
2388 assert!(!prefix.silence, "test body must be non-silent");
2389
2390 let celt_size = CeltFrameSize::Ms20;
2391 let start = celt_first_coded_band(false);
2392 let end = celt_end_coded_band();
2393
2394 let mut coarse = CoarseEnergyState::new();
2395 coarse
2396 .decode_frame(&mut rd, celt_size, prefix.intra, start, end)
2397 .expect("coarse energy decodes");
2398 let tell_after_coarse = rd.tell_frac();
2399
2400 let (tf, spread) = OpusDecoder::decode_celt_tf_spread_allocation(
2401 &mut rd,
2402 celt_size,
2403 prefix.transient,
2404 1,
2405 start,
2406 end,
2407 body.len() as u32,
2408 )
2409 .expect("tf/spread/allocation header decodes without a bookkeeping error");
2410 let tell_after_alloc = rd.tell_frac();
2411
2412 // The TF decode produces one tf_change per coded band; the spread
2413 // symbol is one of the four §4.3.4.3 values.
2414 assert_eq!(tf.tf_change.len(), end - start);
2415 assert!(spread <= crate::celt_spreading::SPREAD_MAX);
2416
2417 // The TF + spread + band-boost symbols all read real bits, so the
2418 // tell must strictly advance past where coarse energy left it.
2419 assert!(
2420 tell_after_alloc > tell_after_coarse,
2421 "alloc tell {tell_after_alloc} must advance past coarse tell {tell_after_coarse}"
2422 );
2423 }
2424}