Skip to main content

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}