Skip to main content

opus_pure/
decoder.rs

1//! The Opus decoder.
2
3use crate::celt::{self, CeltDecoder};
4use crate::config::{Bandwidth, OpusMode};
5use crate::range_coder::RangeCoder;
6use crate::repacketizer;
7use crate::silk;
8use crate::soft_clip::{SoftClip, float_to_i16};
9use crate::toc::{
10    bandwidth_from_toc, celt_endband_for_bandwidth, channels_from_toc, frame_duration_ms_from_toc,
11    mode_from_toc,
12};
13use crate::{Error, Result};
14
15/// An Opus decoder: Opus packets in, PCM out.
16///
17/// One decoder handles one stream, and almost everything it needs is carried
18/// between packets rather than contained in them: filter histories, the
19/// overlap-add buffer, the resampler, and which layer coded the previous frame.
20/// So the same instance has to be fed the whole stream in order, and handing a
21/// packet to a fresh decoder does not produce the same audio as decoding it in
22/// sequence.
23///
24/// A packet says for itself how long it is and which bandwidth and layer it
25/// used, so a decoder needs no configuration beyond the rate and channel count
26/// the caller wants back. It follows the stream wherever the encoder went,
27/// including mode and bandwidth changes mid-stream.
28///
29/// Missing packets are expected rather than exceptional. Call
30/// [`decode`](Self::decode) with an empty slice to conceal a loss, or
31/// [`decode_fec`](Self::decode_fec) on the *following* packet to recover the
32/// gap from a redundant copy if the encoder coded one.
33///
34/// ```
35/// use opus_pure::{Application, OpusDecoder, OpusEncoder};
36///
37/// let mut encoder = OpusEncoder::new(48_000, 2, Application::Audio)?;
38/// let mut decoder = OpusDecoder::new(48_000, 2)?;
39///
40/// let mut packet = vec![0u8; 4000];
41/// let n = encoder.encode(&vec![0.0f32; 960 * 2], 960, &mut packet)?;
42///
43/// let mut pcm = vec![0.0f32; 960 * 2];
44/// assert_eq!(decoder.decode(&packet[..n], 960, &mut pcm)?, 960);
45/// assert_eq!(decoder.decode(&[], 960, &mut pcm)?, 960);   // conceal a loss
46/// # Ok::<(), opus_pure::Error>(())
47/// ```
48pub struct OpusDecoder {
49    /// Bits the SILK layer consumed in the last hybrid packet.
50    ///
51    /// Not part of the public API: this exists so `reference/speed/split` can
52    /// measure how a hybrid packet divides between its two layers, which is not
53    /// otherwise observable from outside. Off unless the `probe` feature is on,
54    /// and what it exposes can change or disappear without a version bump.
55    #[cfg(feature = "probe")]
56    pub probe_silk_bits: i32,
57    /// The last hybrid packet's total bits, the denominator for
58    /// [`probe_silk_bits`](Self::probe_silk_bits). Not public API, on the same
59    /// terms.
60    #[cfg(feature = "probe")]
61    pub probe_total_bits: i32,
62    celt_dec: CeltDecoder,
63    silk_dec: silk::dec_api::SilkDecoder,
64    sampling_rate: i32,
65    channels: usize,
66
67    prev_mode: Option<OpusMode>,
68    frame_size: usize,
69
70    stream_channels: usize,
71
72    silk_resampler: silk::resampler::SilkResampler,
73    // Second resampler for the SILK stereo right channel (L uses silk_resampler).
74    silk_resampler_r: silk::resampler::SilkResampler,
75
76    prev_internal_rate: i32,
77
78    /// Carries the soft-clipping curve between packets for the 16-bit output
79    /// path. libopus keeps the same state on its decoder (`softclip_mem`).
80    softclip: SoftClip,
81    /// Float scratch the 16-bit entry points decode into before converting.
82    w_pcm_f32: Vec<f32>,
83
84    w_pcm_i16: Vec<i16>,
85    w_silk_out: Vec<f32>,
86    w_pcm_resampled: Vec<i16>,
87    w_celt_out: Vec<f32>,
88
89    // SILK per-frame history: libopus prepends the previous frame's last two
90    // decoded samples (`sStereo.sMid`) and feeds the resampler from offset 1, a
91    // 1-internal-sample delay line. Replicated here so our SILK output aligns
92    // with the reference across every bandwidth (was leading by 1 internal
93    // sample = 3/4/6 output samples at WB/MB/NB).
94    silk_s_mid: [i16; 2],
95
96    /// Range-coder state left by the last decoded frame; read through
97    /// [`final_range`](Self::final_range).
98    last_range: u32,
99
100    /// Output gain, in Q8 dB. Applied to every decoded sample; 0 is unity.
101    ///
102    /// This is libopus's `OPUS_SET_GAIN`, and the reason it exists is
103    /// [`OpusHead::output_gain_q8`](crate::OpusHead::output_gain_q8): RFC 7845
104    /// §5.1 puts a gain in the Ogg header and says players SHOULD apply it, but
105    /// nothing in a container can reach inside a decoder to do so. Copy it
106    /// across after reading the header and the stream plays at the loudness its
107    /// author asked for.
108    ///
109    /// Applied before the soft clip on the 16-bit path, as libopus does, so a
110    /// gain that pushes the signal past full scale is clipped rather than
111    /// wrapped.
112    pub gain_q8: i32,
113
114    // libopus st->prev_redundancy: the previous frame carried a SILK->CELT
115    // redundant frame (redundancy && !celt_to_silk). Suppresses the CELT reset on
116    // the following mode change (the redundant frame already primed CELT state).
117    prev_redundancy: bool,
118
119    /// libopus `st->DecControl.internalSampleRate`: the rate the SILK layer ran
120    /// at in the last frame that carried one. Concealment reuses it instead of
121    /// re-deriving it from the packet bandwidth, because libopus only assigns
122    /// `internalSampleRate` when it has a packet in hand (opus_decoder.c:423) —
123    /// during a mode-switch cross-fade the packet in hand belongs to the *new*
124    /// mode and would give the wrong answer.
125    silk_internal_rate: i32,
126    /// libopus `st->end`: the CELT end band the last real frame set. Concealment
127    /// keeps it for the same reason — libopus's `st->bandwidth` is 0 on that
128    /// path, so the `CELT_SET_END_BAND` block is skipped (opus_decoder.c:546).
129    celt_end_band: usize,
130    /// libopus `pcm_transition`: 5 ms of *previous*-mode audio, synthesised by
131    /// concealment at a SILK<->CELT switch and cross-faded over the head of the
132    /// new frame. Interleaved.
133    w_transition: Vec<f32>,
134    /// Concealment scratch. The SILK PLC cannot produce a frame shorter than
135    /// 10 ms, so a shorter request is concealed here and only its head is kept.
136    w_plc: Vec<f32>,
137    /// Concealment scratch for the hybrid high band, which is summed onto the
138    /// SILK concealment rather than replacing it (libopus `celt_accum`).
139    w_plc_celt: Vec<f32>,
140}
141
142/// Shows the decoder's configuration and omits its coding state, for the same
143/// reason [`OpusEncoder`](crate::OpusEncoder)'s does.
144impl std::fmt::Debug for OpusDecoder {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        f.debug_struct("OpusDecoder")
147            .field("sampling_rate", &self.sampling_rate)
148            .field("channels", &self.channels)
149            .field("final_range", &self.last_range)
150            .field("gain_q8", &self.gain_q8)
151            .finish_non_exhaustive()
152    }
153}
154
155impl OpusDecoder {
156    /// Create a decoder producing `sampling_rate` Hz and `channels` channels.
157    ///
158    /// The rate must be one of 8000, 12000, 16000, 24000 or 48000, and the
159    /// channel count 1 or 2; anything else is
160    /// [`Error::InvalidArgument`].
161    ///
162    /// Neither has to match how the stream was encoded. These describe the PCM
163    /// the caller wants back, and the decoder resamples and mixes to reach it,
164    /// so a mono stream decodes to stereo and a 48 kHz one decodes to 16 kHz.
165    /// Requesting 48000 avoids a resampling step on the way out.
166    ///
167    /// For more than two channels, see
168    /// [`OpusMSDecoder`](crate::OpusMSDecoder).
169    pub fn new(sampling_rate: i32, channels: usize) -> Result<Self> {
170        if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
171            return Err(Error::InvalidArgument("Invalid sampling rate"));
172        }
173        if ![1, 2].contains(&channels) {
174            return Err(Error::InvalidArgument("Invalid number of channels"));
175        }
176
177        let mode = celt::modes::default_mode();
178        let mut celt_dec = CeltDecoder::new(mode, channels);
179        // CELT only has the 48 kHz mode; a lower API rate decimates its output.
180        celt_dec.set_downsample((48_000 / sampling_rate) as usize);
181
182        let mut silk_dec = silk::dec_api::SilkDecoder::new();
183        silk_dec.init(sampling_rate.min(16000), channels as i32);
184        silk_dec.channel_state[0].fs_api_hz = sampling_rate;
185
186        Ok(Self {
187            #[cfg(feature = "probe")]
188            probe_silk_bits: 0,
189            #[cfg(feature = "probe")]
190            probe_total_bits: 0,
191            celt_dec,
192            silk_dec,
193            sampling_rate,
194            channels,
195            prev_mode: None,
196            frame_size: 0,
197            stream_channels: channels,
198            silk_resampler: silk::resampler::SilkResampler::default(),
199            silk_resampler_r: silk::resampler::SilkResampler::default(),
200            prev_internal_rate: 0,
201
202            // SILK internal scratch: max frame is 60 ms at the 16 kHz WB internal
203            // rate (960 samples/ch), i.e. 1920 stereo. Sized like the sibling
204            // buffers below for headroom — the old fixed 640 overflowed on any
205            // 60 ms SILK frame (panic decoding valid streams).
206            w_pcm_i16: vec![0i16; 5760 * channels],
207
208            w_silk_out: vec![0.0f32; 5760 * channels],
209            w_pcm_resampled: vec![0i16; 5760 * channels],
210            softclip: SoftClip::new(channels),
211            w_pcm_f32: Vec::new(),
212            w_celt_out: vec![0.0f32; 5760 * channels],
213            silk_s_mid: [0; 2],
214            last_range: 0,
215            gain_q8: 0,
216            prev_redundancy: false,
217            silk_internal_rate: 16_000,
218            celt_end_band: 21,
219            w_transition: Vec::new(),
220            w_plc: Vec::new(),
221            w_plc_celt: Vec::new(),
222        })
223    }
224
225    /// Write one decoded SILK frame into `output`, resampling to the API rate.
226    ///
227    /// Always through the resampler, even where the API rate already equals
228    /// SILK's internal one. Its copy path is not a plain copy: it still carries
229    /// the `delay_matrix_dec` input delay, 4, 9 and 12 samples at 8, 12 and
230    /// 16 kHz, and `silk_Decode` calls `silk_resampler` unconditionally for
231    /// exactly that reason. Short-circuiting it put every SILK-only stream that
232    /// many samples ahead of the reference decoder. `base` is an index into `output` in
233    /// interleaved samples; the return is output samples per channel.
234    ///
235    /// `stereo` selects the true L/R low band that `dec_api` reconstructs from
236    /// mid/side. A mono frame in a stereo stream is duplicated to both channels,
237    /// but is still pushed through the right-channel resampler as well, so that
238    /// resampler's state stays continuous for the next stereo packet.
239    fn render_silk_frame(
240        &mut self,
241        output: &mut [f32],
242        base: usize,
243        decoded_samples: usize,
244        stereo: bool,
245        internal_rate: i32,
246    ) -> usize {
247        let ratio = self.sampling_rate as f64 / internal_rate as f64;
248        let out_len = (decoded_samples as f64 * ratio) as usize;
249        debug_assert!(out_len <= self.w_pcm_resampled.len());
250        let channels = self.channels;
251
252        // How many whole output samples actually fit, decided once. These loops
253        // are the entire SILK output path, and testing the bound inside them
254        // cost both the branch and any chance of vectorising the conversion:
255        // profiled against libopus, this function was eight times the
256        // reference's cost for work the reference does in a single pass.
257        // Callers size `output` in whole frames, so `fit` is `out_len` in
258        // practice and the clamp only reproduces the old truncation.
259        let fit = out_len.min(output.len().saturating_sub(base) / channels);
260        let out = &mut output[base..base + fit * channels];
261
262        if stereo {
263            self.silk_resampler.process(
264                &mut self.w_pcm_resampled[..out_len],
265                &self.silk_dec.l_out[..decoded_samples],
266                decoded_samples as i32,
267            );
268            for (frame, &v) in out
269                .as_chunks_mut::<2>()
270                .0
271                .iter_mut()
272                .zip(&self.w_pcm_resampled[..fit])
273            {
274                frame[0] = v as f32 / 32768.0;
275            }
276            // Right (reuse the scratch)
277            self.silk_resampler_r.process(
278                &mut self.w_pcm_resampled[..out_len],
279                &self.silk_dec.r_out[..decoded_samples],
280                decoded_samples as i32,
281            );
282            for (frame, &v) in out
283                .as_chunks_mut::<2>()
284                .0
285                .iter_mut()
286                .zip(&self.w_pcm_resampled[..fit])
287            {
288                frame[1] = v as f32 / 32768.0;
289            }
290        } else {
291            {
292                let (silk_res, pcm_i16, pcm_out) = (
293                    &mut self.silk_resampler,
294                    &self.w_pcm_i16,
295                    &mut self.w_pcm_resampled,
296                );
297                silk_res.process(
298                    &mut pcm_out[..out_len],
299                    &pcm_i16[1..1 + decoded_samples],
300                    decoded_samples as i32,
301                );
302            }
303            if channels == 1 {
304                for (o, &v) in out.iter_mut().zip(&self.w_pcm_resampled[..fit]) {
305                    *o = v as f32 / 32768.0;
306                }
307            } else {
308                for (frame, &v) in out
309                    .as_chunks_mut::<2>()
310                    .0
311                    .iter_mut()
312                    .zip(&self.w_pcm_resampled[..fit])
313                {
314                    let f = v as f32 / 32768.0;
315                    frame[0] = f;
316                    frame[1] = f;
317                }
318                // Stereo output, mono packet: also run the mono signal
319                // through the RIGHT-channel resampler so its state stays
320                // continuous for the next stereo packet (libopus
321                // dec_API.c:351-355). Its output overwrites channel 1,
322                // which is numerically ~identical to the left here.
323                self.silk_resampler_r.process(
324                    &mut self.w_pcm_resampled[..out_len],
325                    &self.w_pcm_i16[1..1 + decoded_samples],
326                    decoded_samples as i32,
327                );
328                for (frame, &v) in out
329                    .as_chunks_mut::<2>()
330                    .0
331                    .iter_mut()
332                    .zip(&self.w_pcm_resampled[..fit])
333                {
334                    frame[1] = v as f32 / 32768.0;
335                }
336            }
337        }
338        out_len
339    }
340
341    /// Packet-loss concealment for a lost frame (empty/None packet). Runs the
342    /// SILK PLC (LTP+LPC extrapolation) for the last-known SILK/hybrid mode,
343    /// resamples to the output rate, and sums the CELT high band's own
344    /// concealment on top when that mode was hybrid. Mono conceal is duplicated
345    /// to both channels on a stereo output.
346    ///
347    /// Also drives the cross-fade at a SILK<->CELT mode switch, where libopus
348    /// calls it for 5 ms of *previous*-mode audio (see [`Self::fill_transition`]).
349    fn decode_plc(&mut self, frame_size: usize, output: &mut [f32]) -> Result<usize> {
350        // "Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5
351        // (CELT), 10, or 20" (opus_decoder.c:344): a request longer than 20 ms
352        // is concealed in 20 ms pieces, because 20 ms is the longest frame CELT
353        // has. Its decode buffer holds exactly one, and the pitch branch of
354        // concealment indexes `DECODE_BUFFER_SIZE - MAX_PERIOD - n`, which goes
355        // negative past that. Concealing a lost 40 or 60 ms packet is an
356        // ordinary thing to ask a decoder for, and it reached that subtraction:
357        // found by the `decode_stream` fuzz target, pinned in
358        // `robustness.rs::concealment_longer_than_a_celt_frame_is_chunked`.
359        debug_assert!(output.len() >= frame_size * self.channels);
360        let longest = (self.sampling_rate / 50) as usize;
361        if frame_size > longest {
362            let mut done = 0usize;
363            while done < frame_size {
364                let take = longest.min(frame_size - done);
365                let span = done * self.channels..(done + take) * self.channels;
366                self.decode_plc(take, &mut output[span])?;
367                done += take;
368            }
369            return Ok(frame_size);
370        }
371
372        let out_samples = frame_size * self.channels;
373        for v in output.iter_mut().take(out_samples) {
374            *v = 0.0;
375        }
376        // libopus opus_decoder.c:331 — conceal in the last mode that actually
377        // produced audio, which is CELT when the previous frame ended on a
378        // SILK->CELT redundant frame.
379        //
380        // Before any packet has been decoded there is no such mode, and libopus
381        // returns the silence above without touching a decoder (`if (mode == 0)`
382        // at opus_decoder.c:334). Concealing in a guessed mode instead produces
383        // the same silence but leaves SILK's state advanced by a frame — a bumped
384        // `lossCnt`, a rotated output history, a stepped PLC seed — so the first
385        // real packet decoded its LPC coefficients through the after-loss
386        // bandwidth expansion that libopus had no reason to apply.
387        let Some(prev_mode) = self.prev_mode else {
388            return Ok(frame_size);
389        };
390        let mode = if self.prev_redundancy {
391            OpusMode::CeltOnly
392        } else {
393            prev_mode
394        };
395        if mode == OpusMode::CeltOnly {
396            // CELT packet-loss concealment (noise-based celt_decode_lost): real
397            // attenuating audio instead of silence.
398            self.celt_dec
399                .conceal_lost_bands(frame_size, output, 0, self.celt_end_band);
400            self.prev_mode = Some(mode);
401            return Ok(frame_size);
402        }
403
404        // "The SILK PLC cannot produce frames of less than 10 ms"
405        // (opus_decoder.c:420): a shorter request still runs a 10 ms
406        // concealment, and only its head reaches the caller. That happens on
407        // every mode-switch cross-fade, which asks for 5 ms.
408        let want_ms = (frame_size as i32 * 1000 / self.sampling_rate).max(1);
409        let frame_ms = want_ms.max(10);
410        let internal_rate = self.silk_internal_rate;
411        if internal_rate != self.prev_internal_rate {
412            self.silk_resampler.init(internal_rate, self.sampling_rate);
413            self.silk_resampler_r
414                .init(internal_rate, self.sampling_rate);
415            self.prev_internal_rate = internal_rate;
416        }
417        let n_silk = match frame_ms {
418            40 => 2,
419            60 => 3,
420            _ => 1,
421        };
422        let internal_frame = (frame_ms * internal_rate / 1000) as usize;
423        let internal_sub = internal_frame / n_silk;
424        // libopus carries the previous frame's channel configuration through a
425        // concealed frame, so a stereo stream conceals both channels and rebuilds
426        // L/R the same way a decoded frame does. Forcing mono here instead let the
427        // image collapse to the centre for the length of the concealment.
428        self.silk_dec.produce_lr = self.channels == 2 && self.silk_dec.n_channels_internal == 2;
429
430        // SILK writes a whole `frame_ms` here; `output` only gets its head.
431        let plc_samples = (frame_ms as usize * self.sampling_rate as usize) / 1000;
432        let need = plc_samples * self.channels;
433        let mut scratch = std::mem::take(&mut self.w_plc);
434        if scratch.len() < need {
435            scratch.resize(need, 0.0);
436        }
437        scratch[..need].fill(0.0);
438        let conceal = self.conceal_silk(&mut scratch, frame_ms, n_silk, internal_sub);
439        if conceal.is_ok() {
440            let copy = out_samples.min(need);
441            output[..copy].copy_from_slice(&scratch[..copy]);
442        }
443        self.w_plc = scratch;
444        conceal?;
445
446        // Hybrid: the CELT layer conceals its own high band and sums onto the
447        // SILK output, exactly as `celt_accum` does on the decode path
448        // (opus_decoder.c:599 with data == NULL).
449        if mode == OpusMode::Hybrid {
450            let mut celt = std::mem::take(&mut self.w_plc_celt);
451            if celt.len() < out_samples {
452                celt.resize(out_samples, 0.0);
453            }
454            self.celt_dec.conceal_lost_bands(
455                frame_size,
456                &mut celt,
457                HYBRID_START_BAND,
458                self.celt_end_band,
459            );
460            for (o, c) in output[..out_samples].iter_mut().zip(&celt[..out_samples]) {
461                *o += *c;
462            }
463            self.w_plc_celt = celt;
464        }
465
466        self.prev_mode = Some(mode);
467        Ok(frame_size)
468    }
469
470    /// The SILK half of [`Self::decode_plc`]: `n_silk` concealed internal frames
471    /// resampled into `out` (interleaved, `frame_ms` worth).
472    fn conceal_silk(
473        &mut self,
474        out: &mut [f32],
475        frame_ms: i32,
476        n_silk: usize,
477        internal_sub: usize,
478    ) -> Result<()> {
479        let mut off = 0usize; // output samples/ch written so far
480        for sf in 0..n_silk {
481            let mut rc = RangeCoder::new_decoder(&[]);
482            let n16 = internal_sub;
483            if n16 + 2 > self.w_pcm_i16.len() {
484                return Err(Error::InvalidPacket("opus PLC: frame exceeds buffer"));
485            }
486            self.w_pcm_i16[0] = self.silk_s_mid[0];
487            self.w_pcm_i16[1] = self.silk_s_mid[1];
488            let ret = self.silk_dec.decode(
489                &mut rc,
490                &mut self.w_pcm_i16[2..n16 + 2],
491                silk::decode_frame::FLAG_PACKET_LOST,
492                sf == 0,
493                frame_ms,
494                self.silk_internal_rate,
495            );
496            if ret < 0 {
497                return Err(Error::Internal("SILK PLC failed"));
498            }
499            let dec = ret as usize;
500            if dec >= 2 {
501                self.silk_s_mid[0] = self.w_pcm_i16[dec];
502                self.silk_s_mid[1] = self.w_pcm_i16[dec + 1];
503            }
504            // A stereo stream conceals both channels and reconstructs L/R the
505            // same way a decoded frame does. Writing the mid to both outputs
506            // instead collapses the image for the length of the concealment,
507            // which at a mode switch is audible as the stereo field snapping to
508            // the centre for one 5 ms window. That reconstruction is exactly
509            // what render_silk_frame does, so concealment shares it.
510            let stereo = self.channels == 2 && self.silk_dec.produce_lr;
511            let base = off * self.channels;
512            off += self.render_silk_frame(out, base, dec, stereo, self.silk_internal_rate);
513        }
514        Ok(())
515    }
516
517    /// libopus opus_decoder.c:417 — the SILK layer carries no state across a
518    /// CELT-only stretch, so it restarts from scratch when the stream comes
519    /// back to it. Without this the first SILK frame after a CELT run predicts
520    /// from LPC/LTP history that belongs to whatever came before the CELT run.
521    fn reset_silk_after_celt_only(&mut self) {
522        if self.prev_mode != Some(OpusMode::CeltOnly) {
523            return;
524        }
525        for ch in 0..2 {
526            silk::init_decoder::silk_init_decoder(&mut self.silk_dec.channel_state[ch]);
527        }
528        self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
529        self.silk_dec.s_stereo_mid = [0; 2];
530        self.silk_dec.s_stereo_side = [0; 2];
531        self.silk_dec.prev_decode_only_middle = 0;
532        self.silk_s_mid = [0; 2];
533    }
534
535    /// libopus `pcm_transition` (opus_decoder.c:388 and :540). A SILK<->CELT
536    /// switch with no redundancy hands the new layer no history to overlap-add
537    /// against, so its first samples start from silence. libopus covers the seam
538    /// by concealing 5 ms in the *previous* mode and cross-fading that over the
539    /// head of the frame.
540    ///
541    /// The concealment call is a synthesis side-channel, not a decoded frame, so
542    /// `prev_mode` / `prev_redundancy` are restored afterwards. libopus leaves
543    /// them equal too: `transition` already implies `prev_redundancy` is clear,
544    /// and the recursive call re-stores the same `prev_mode` it read.
545    fn fill_transition(&mut self, sub_frame_size: usize, end_band: usize) -> Result<()> {
546        let n = ((self.sampling_rate / 200) as usize).min(sub_frame_size);
547        let need = n * self.channels;
548        let mut buf = std::mem::take(&mut self.w_transition);
549        if buf.len() < need {
550            buf.resize(need, 0.0);
551        }
552        let saved_mode = self.prev_mode;
553        let saved_redundancy = self.prev_redundancy;
554        let saved_end_band = std::mem::replace(&mut self.celt_end_band, end_band);
555        let r = self.decode_plc(n, &mut buf);
556        self.w_transition = buf;
557        self.prev_mode = saved_mode;
558        self.prev_redundancy = saved_redundancy;
559        self.celt_end_band = saved_end_band;
560        r.map(|_| ())
561    }
562
563    /// Blend the concealed previous-mode head from [`Self::fill_transition`]
564    /// into the start of `region` (opus_decoder.c:660): the first 2.5 ms comes
565    /// from the concealment outright, the next 2.5 ms cross-fades into the
566    /// decoded frame. A frame shorter than 5 ms has no room for both, so it
567    /// gets the cross-fade alone.
568    fn apply_transition(&self, region: &mut [f32], sub_frame_size: usize) {
569        let f5 = (self.sampling_rate / 200) as usize;
570        let f2_5 = f5 / 2;
571        let inc = (48_000 / self.sampling_rate) as usize;
572        let window = celt::modes::default_mode().window;
573        let ch = self.channels;
574        let trans = &self.w_transition;
575        let head = if sub_frame_size >= f5 {
576            region[..f2_5 * ch].copy_from_slice(&trans[..f2_5 * ch]);
577            f2_5
578        } else {
579            0
580        };
581        for i in 0..f2_5 {
582            let w = window[i * inc] * window[i * inc];
583            for c in 0..ch {
584                let idx = (head + i) * ch + c;
585                region[idx] = w * region[idx] + (1.0 - w) * trans[idx];
586            }
587        }
588    }
589
590    /// Forward-error-correction decode: reconstruct a LOST frame from the
591    /// low-bitrate redundancy (LBRR) embedded in the NEXT received `packet`.
592    ///
593    /// The SILK decoder runs in `FLAG_DECODE_LBRR` mode, which self-selects: it
594    /// decodes the redundant copy when the packet carries one for this frame,
595    /// and extrapolates as for a lost frame when it does not. After this call
596    /// the caller decodes `packet` normally for the following frame.
597    ///
598    /// Redundancy only ever covers one SILK frame, so when `frame_size` is
599    /// longer than the packet's own frames the excess ahead of it is concealed
600    /// and only the tail is recovered. A CELT-only packet, or one arriving
601    /// while the stream is in CELT-only mode, carries no redundancy at all and
602    /// falls back to plain concealment.
603    /// Per-packet internal channel switch (libopus `dec_API.c:119-166`).
604    ///
605    /// Returns whether SILK should produce L/R directly for this packet. All
606    /// three decode paths (FEC, normal, PLC) need exactly this bookkeeping, so
607    /// it lives here once rather than being repeated at each of them.
608    fn setup_silk_channels(&mut self, packet_channels: usize) -> bool {
609        let silk_lr = self.channels == 2 && packet_channels == 2;
610        self.silk_dec.produce_lr = silk_lr;
611        let prev_internal_ch = self.silk_dec.n_channels_internal;
612        if packet_channels as i32 > prev_internal_ch {
613            // mono -> stereo: reset the side channel decoder.
614            silk::init_decoder::silk_init_decoder(&mut self.silk_dec.channel_state[1]);
615        }
616        if silk_lr && prev_internal_ch == 1 {
617            // Switching to stereo: clear stereo prediction/side history and
618            // seed the right-channel resampler from the (continuous) left.
619            self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
620            self.silk_dec.s_stereo_side = [0; 2];
621            self.silk_resampler_r = self.silk_resampler.clone();
622        }
623        self.silk_dec.n_channels_internal = packet_channels as i32;
624        silk_lr
625    }
626
627    /// The sample rate this decoder was created with, in Hz.
628    pub fn sample_rate(&self) -> i32 {
629        self.sampling_rate
630    }
631
632    /// The channel count this decoder was created with.
633    pub fn channels(&self) -> usize {
634        self.channels
635    }
636
637    /// Range-coder state left by the last decoded frame (libopus
638    /// `OPUS_GET_FINAL_RANGE`).
639    ///
640    /// A decoder that has read a packet correctly ends in exactly the state the
641    /// encoder ended in, so comparing this against
642    /// [`OpusEncoder::final_range`](crate::OpusEncoder::final_range) is a cheap
643    /// check that the two agree bit for bit. That is what the RFC 6716 test
644    /// vectors compare, and what tells a desync apart from a merely
645    /// disappointing decode. It is not needed to decode audio.
646    pub fn final_range(&self) -> u32 {
647        self.last_range
648    }
649
650    /// Samples per channel in the last packet decoded from real data (libopus
651    /// `OPUS_GET_LAST_PACKET_DURATION`), or 0 before the first one.
652    ///
653    /// Concealed and FEC-recovered frames do not change it, so after a loss it
654    /// still reports the last packet that actually arrived. To ask the same
655    /// question of a packet you are holding but have not decoded — which is
656    /// what a muxer or a jitter buffer wants — use
657    /// [`packet::samples`](crate::packet::samples) instead; it reads the TOC
658    /// and needs no decoder at all.
659    pub fn last_packet_duration(&self) -> usize {
660        self.frame_size
661    }
662
663    /// Discard everything the decoder has learned, keeping its settings.
664    ///
665    /// This is libopus's `OPUS_RESET_STATE`, and the moment to call it is
666    /// between two unrelated streams sharing one decoder. Almost everything
667    /// interesting in an Opus decoder is carried *between* packets — the LTP
668    /// and LPC histories, the overlap-add buffer, the resampler, which layer
669    /// coded the previous frame — so a second stream started on a used decoder
670    /// begins by blending into the end of the first.
671    ///
672    /// Equivalent to building a new decoder with the same sample rate and
673    /// channel count, and carrying [`gain_q8`](Self::gain_q8) across. It resets
674    /// in place and allocates nothing, so a player can call it at every loop
675    /// point.
676    pub fn reset_state(&mut self) -> Result<()> {
677        // Exhaustive, so a field added to the decoder does not compile until
678        // this says how it resets. Each is set to what `new` gives it.
679        let Self {
680            #[cfg(feature = "probe")]
681            probe_silk_bits,
682            #[cfg(feature = "probe")]
683            probe_total_bits,
684            celt_dec,
685            silk_dec,
686            sampling_rate,
687            channels,
688            prev_mode,
689            frame_size,
690            stream_channels,
691            silk_resampler,
692            silk_resampler_r,
693            prev_internal_rate,
694            softclip,
695            w_pcm_f32,
696            w_pcm_i16,
697            w_silk_out,
698            w_pcm_resampled,
699            w_celt_out,
700            silk_s_mid,
701            last_range,
702            gain_q8: _,
703            prev_redundancy,
704            silk_internal_rate,
705            celt_end_band,
706            w_transition,
707            w_plc,
708            w_plc_celt,
709        } = self;
710        #[cfg(feature = "probe")]
711        {
712            *probe_silk_bits = 0;
713            *probe_total_bits = 0;
714        }
715        // The rate and channel count are settings, as is the CELT downsample
716        // factor derived from the rate, which `reset` keeps.
717        celt_dec.reset();
718        celt_dec.set_stream_channels(*channels);
719        // The SILK decoder holds no heap memory, so a new one costs no
720        // allocation.
721        *silk_dec = silk::dec_api::SilkDecoder::new();
722        silk_dec.init((*sampling_rate).min(16000), *channels as i32);
723        silk_dec.channel_state[0].fs_api_hz = *sampling_rate;
724        *prev_mode = None;
725        *frame_size = 0;
726        *stream_channels = *channels;
727        *silk_resampler = silk::resampler::SilkResampler::default();
728        *silk_resampler_r = silk::resampler::SilkResampler::default();
729        *prev_internal_rate = 0;
730        softclip.reset();
731        *silk_s_mid = [0; 2];
732        *last_range = 0;
733        *prev_redundancy = false;
734        *silk_internal_rate = 16_000;
735        *celt_end_band = 21;
736        // Scratch starts as `new` leaves it, zeroed or empty, with its
737        // capacity kept.
738        w_pcm_i16.fill(0);
739        w_silk_out.fill(0.0);
740        w_pcm_resampled.fill(0);
741        w_celt_out.fill(0.0);
742        w_pcm_f32.clear();
743        w_transition.clear();
744        w_plc.clear();
745        w_plc_celt.clear();
746        Ok(())
747    }
748
749    /// Decode one packet into `frame_size` samples per channel of float PCM,
750    /// returning how many it produced.
751    ///
752    /// `output` is interleaved and must hold `frame_size * channels` samples.
753    /// An empty `input` means a lost packet and runs packet-loss concealment.
754    ///
755    /// The output is **not** bounded by ±1: the codec rings, and a signal
756    /// mastered near full scale comes back slightly over it. libopus behaves
757    /// the same way. Convert to integer PCM with
758    /// [`decode_s16`](Self::decode_s16), which handles that, or apply
759    /// [`SoftClip`] yourself if you need the float and are converting later.
760    pub fn decode(&mut self, input: &[u8], frame_size: usize, output: &mut [f32]) -> Result<usize> {
761        self.decode_native(input, frame_size, output, false)
762    }
763
764    /// Decode one packet into `frame_size` samples per channel of 16-bit PCM,
765    /// returning how many it produced.
766    ///
767    /// Soft-clips before converting, so the result is inside the 16-bit range
768    /// without the broadband distortion that saturating there would cause, and
769    /// without a step at the packet boundary when a peak straddles one. This is
770    /// what libopus's `opus_decode` does and `opus_decode_float` does not, and
771    /// it is the reason to prefer this entry point over converting the float
772    /// output by hand. See [`SoftClip`] for what the curve is.
773    ///
774    /// ```
775    /// # use opus_pure::{Application, OpusDecoder, OpusEncoder};
776    /// # let mut encoder = OpusEncoder::new(48_000, 2, Application::Audio)?;
777    /// # let mut packet = vec![0u8; 4000];
778    /// # let n = encoder.encode_s16(&vec![0i16; 960 * 2], 960, &mut packet)?;
779    /// let mut decoder = OpusDecoder::new(48_000, 2)?;
780    /// let mut pcm = vec![0i16; 960 * 2];
781    /// let samples = decoder.decode_s16(&packet[..n], 960, &mut pcm)?;
782    /// # assert_eq!(samples, 960);
783    /// # Ok::<(), opus_pure::Error>(())
784    /// ```
785    pub fn decode_s16(
786        &mut self,
787        input: &[u8],
788        frame_size: usize,
789        output: &mut [i16],
790    ) -> Result<usize> {
791        self.decode_as_s16(frame_size, output, |d, pcm| {
792            d.decode_native(input, frame_size, pcm, true)
793        })
794    }
795
796    /// Reconstruct the previous packet from this one's in-band FEC, as float.
797    ///
798    /// Call this when a packet is lost and the packet *after* it has arrived:
799    /// SILK and hybrid streams can carry a low-rate copy of the frame before,
800    /// which reconstructs it far better than concealment can. Falls back to
801    /// concealment when the packet carries no such copy.
802    pub fn decode_fec(
803        &mut self,
804        packet: &[u8],
805        frame_size: usize,
806        output: &mut [f32],
807    ) -> Result<usize> {
808        self.decode_fec_native(packet, frame_size, output, false)
809    }
810
811    /// [`decode_fec`](Self::decode_fec) into 16-bit PCM, soft-clipped the same
812    /// way [`decode_s16`](Self::decode_s16) is.
813    pub fn decode_fec_s16(
814        &mut self,
815        packet: &[u8],
816        frame_size: usize,
817        output: &mut [i16],
818    ) -> Result<usize> {
819        self.decode_as_s16(frame_size, output, |d, pcm| {
820            d.decode_fec_native(packet, frame_size, pcm, true)
821        })
822    }
823
824    /// Run `decode` into the float scratch, then convert what it produced.
825    ///
826    /// The scratch is moved out of `self` and back because the decode needs
827    /// `&mut self` and a buffer that lives on it at the same time; it stays
828    /// allocated between calls either way.
829    fn decode_as_s16(
830        &mut self,
831        frame_size: usize,
832        output: &mut [i16],
833        decode: impl FnOnce(&mut Self, &mut [f32]) -> Result<usize>,
834    ) -> Result<usize> {
835        let capacity = frame_size * self.channels;
836        if output.len() < capacity {
837            return Err(Error::buffer_too_small(capacity, output.len()));
838        }
839        let mut pcm = std::mem::take(&mut self.w_pcm_f32);
840        pcm.clear();
841        pcm.resize(capacity, 0.0);
842        let result = decode(self, &mut pcm);
843        if let Ok(produced) = result {
844            let n = produced * self.channels;
845            for (o, &s) in output[..n].iter_mut().zip(&pcm[..n]) {
846                *o = float_to_i16(s);
847            }
848        }
849        self.w_pcm_f32 = pcm;
850        result
851    }
852
853    /// Decode as float, then either apply the soft-clipping curve or clear it.
854    ///
855    /// Clearing on the float path is deliberate and matches libopus
856    /// (`opus_decode_native`): a curve left half-applied by a 16-bit call would
857    /// otherwise bend the start of the next frame a caller asked for in float,
858    /// where nothing is going to clip it.
859    pub(crate) fn decode_native(
860        &mut self,
861        input: &[u8],
862        frame_size: usize,
863        output: &mut [f32],
864        soft_clip: bool,
865    ) -> Result<usize> {
866        let produced = self.decode_impl(input, frame_size, output)?;
867        self.finish(&mut output[..produced * self.channels], soft_clip);
868        Ok(produced)
869    }
870
871    /// [`decode_native`](Self::decode_native) for the FEC path.
872    fn decode_fec_native(
873        &mut self,
874        packet: &[u8],
875        frame_size: usize,
876        output: &mut [f32],
877        soft_clip: bool,
878    ) -> Result<usize> {
879        let produced = self.decode_fec_impl(packet, frame_size, output)?;
880        self.finish(&mut output[..produced * self.channels], soft_clip);
881        Ok(produced)
882    }
883
884    fn finish(&mut self, pcm: &mut [f32], soft_clip: bool) {
885        // libopus `opus_decode_native`: the gain goes on before the soft clip,
886        // so boosting past full scale is clipped rather than wrapped. The
887        // constant converts Q8 dB into an exponent of two —
888        // `10^(g/(20*256)) == 2^(g * log2(10) / 5120)`.
889        if self.gain_q8 != 0 {
890            let gain = (self.gain_q8 as f32 * 6.488_141e-4).exp2();
891            for s in pcm.iter_mut() {
892                *s *= gain;
893            }
894        }
895        if soft_clip {
896            self.softclip.apply(pcm);
897        } else {
898            self.softclip.reset();
899        }
900    }
901
902    fn decode_fec_impl(
903        &mut self,
904        packet: &[u8],
905        frame_size: usize,
906        output: &mut [f32],
907    ) -> Result<usize> {
908        let capacity = frame_size * self.channels;
909        if output.len() < capacity {
910            return Err(Error::buffer_too_small(capacity, output.len()));
911        }
912        if packet.is_empty() {
913            return self.decode_plc(frame_size, output);
914        }
915        let toc = packet[0];
916        let mode = mode_from_toc(toc);
917        if mode == OpusMode::CeltOnly || self.prev_mode == Some(OpusMode::CeltOnly) {
918            return self.decode_plc(frame_size, output);
919        }
920        let packet_frame_ms = frame_duration_ms_from_toc(toc);
921        let packet_frame_size = (packet_frame_ms * self.sampling_rate / 1000) as usize;
922        if packet_frame_size == 0 || frame_size < packet_frame_size {
923            return self.decode_plc(frame_size, output);
924        }
925
926        // The redundancy lives in the packet's FIRST frame; anything the request
927        // covers ahead of it has no redundant copy and is concealed instead.
928        let lead = frame_size - packet_frame_size;
929        if lead > 0 {
930            self.decode_plc(lead, &mut output[..lead * self.channels])?;
931        }
932        let base = lead * self.channels;
933        for v in output[base..capacity].iter_mut() {
934            *v = 0.0;
935        }
936
937        let (_, frames, _) = crate::repacketizer::parse_packet(packet, false)?;
938        let payload = frames[0];
939
940        let bandwidth = bandwidth_from_toc(toc);
941        let packet_channels = channels_from_toc(toc);
942        let internal_rate = if mode == OpusMode::Hybrid {
943            16000
944        } else {
945            match bandwidth {
946                Bandwidth::Narrowband => 8000,
947                Bandwidth::Mediumband => 12000,
948                _ => 16000,
949            }
950        };
951        if internal_rate != self.prev_internal_rate {
952            self.silk_resampler.init(internal_rate, self.sampling_rate);
953            self.silk_resampler_r
954                .init(internal_rate, self.sampling_rate);
955            self.prev_internal_rate = internal_rate;
956        }
957        self.silk_internal_rate = internal_rate;
958
959        // Same channel bookkeeping as a normal SILK frame: a redundant frame is
960        // an ordinary coded frame, so a stereo one has to reconstruct L/R rather
961        // than collapse to the mid.
962        let silk_lr = self.setup_silk_channels(packet_channels);
963
964        // A 40 or 60 ms packet holds two or three SILK frames, each redundantly
965        // coded in its own right; libopus keeps calling the SILK decoder until
966        // the requested duration is filled.
967        let n_silk = match packet_frame_ms {
968            40 => 2,
969            60 => 3,
970            _ => 1,
971        };
972        let internal_sub_frame = (packet_frame_ms * internal_rate / 1000) as usize / n_silk;
973        let pcm_i16_len = internal_sub_frame * self.channels;
974        if pcm_i16_len + 2 > self.w_pcm_i16.len() {
975            return Err(Error::InvalidPacket("opus FEC: frame exceeds buffer"));
976        }
977
978        let mut rc = RangeCoder::new_decoder(payload);
979        let mut written = 0usize;
980        for sf in 0..n_silk {
981            let s_mid = self.silk_s_mid;
982            let ret = {
983                let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
984                pcm_i16[0] = s_mid[0];
985                pcm_i16[1] = s_mid[1];
986                silk_dec.decode(
987                    &mut rc,
988                    &mut pcm_i16[2..pcm_i16_len + 2],
989                    silk::decode_frame::FLAG_DECODE_LBRR,
990                    sf == 0,
991                    packet_frame_ms,
992                    internal_rate,
993                )
994            };
995            if ret < 0 {
996                return Err(Error::Internal("SILK FEC failed"));
997            }
998            let decoded_samples = ret as usize;
999            if decoded_samples >= 2 {
1000                self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1001                self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1002            }
1003            written += self.render_silk_frame(
1004                output,
1005                base + written * self.channels,
1006                decoded_samples,
1007                silk_lr,
1008                internal_rate,
1009            );
1010        }
1011
1012        // Hybrid: the redundancy only ever covers the SILK low band, so the CELT
1013        // high band conceals itself and is summed on top, as it is for a lost
1014        // frame (opus_decoder.c passes NULL to the CELT decoder here).
1015        if mode == OpusMode::Hybrid {
1016            let tail = capacity - base;
1017            let mut celt = std::mem::take(&mut self.w_plc_celt);
1018            if celt.len() < tail {
1019                celt.resize(tail, 0.0);
1020            }
1021            self.celt_dec.conceal_lost_bands(
1022                packet_frame_size,
1023                &mut celt,
1024                HYBRID_START_BAND,
1025                self.celt_end_band,
1026            );
1027            for (o, c) in output[base..capacity].iter_mut().zip(&celt[..tail]) {
1028                *o += *c;
1029            }
1030            self.w_plc_celt = celt;
1031        }
1032
1033        self.prev_mode = Some(mode);
1034        self.prev_redundancy = false;
1035        Ok(frame_size)
1036    }
1037
1038    fn decode_impl(
1039        &mut self,
1040        input: &[u8],
1041        frame_size: usize,
1042        output: &mut [f32],
1043    ) -> Result<usize> {
1044        // `frame_size` is the room available in `output`, counted per channel.
1045        // libopus takes that on trust because C hands it a bare pointer; here
1046        // the slice knows its own length, so hold the caller to what they
1047        // declared rather than letting a short buffer truncate the decode.
1048        let capacity = frame_size * self.channels;
1049        if output.len() < capacity {
1050            return Err(Error::buffer_too_small(capacity, output.len()));
1051        }
1052        // Lost packet (data==NULL / empty) -> packet-loss concealment.
1053        if input.is_empty() {
1054            return self.decode_plc(frame_size, output);
1055        }
1056
1057        let toc = input[0];
1058        let mode = mode_from_toc(toc);
1059        let packet_channels = channels_from_toc(toc);
1060        let bandwidth = bandwidth_from_toc(toc);
1061        let frame_duration_ms = frame_duration_ms_from_toc(toc);
1062
1063        // Every packet decodes through this one decoder, whatever its channel
1064        // count. A stream may switch between mono and stereo at any packet, and
1065        // libopus keeps a single decoder across those switches so that the SILK
1066        // stereo/resampler state and the CELT overlap-add, prefilter and
1067        // preemphasis histories stay one continuous chain. Rendering to a
1068        // different output channel count happens *inside* each layer, where the
1069        // reference does it:
1070        //
1071        //   mono packet, stereo output (C=1, CC=2) — SILK emits the mid through
1072        //   both channels' resamplers; CELT re-runs its inverse MDCT per output
1073        //   channel off the single decoded spectrum.
1074        //
1075        //   stereo packet, mono output (C=2, CC=1) — SILK emits the mid, which
1076        //   *is* (L+R)/2 by construction, and never reconstructs L/R; CELT sums
1077        //   the two spectra before a single inverse MDCT.
1078        //
1079        // Both are `stream_channels` on the CELT decoder and `n_channels_internal`
1080        // on the SILK one; neither needs a second decoder.
1081
1082        // One packet parser for the whole crate. `repacketizer::parse_packet`
1083        // is the port of libopus `opus_packet_parse_impl`, and `decode_fec` and
1084        // the repacketizer already went through it; the copy that used to live
1085        // here had drifted from it, accepting frames past the 1275-byte limit
1086        // of RFC 6716 §3.4 and rejecting the zero-length DTX frames of a code 1
1087        // packet that libopus accepts.
1088        let (_, frame_payloads, _) = repacketizer::parse_packet(input, false)?;
1089        let frame_count = frame_payloads.len();
1090
1091        // libopus opus_decoder.c opus_decode_native:
1092        //   if (count*packet_frame_size > frame_size)
1093        //      return OPUS_BUFFER_TOO_SMALL;
1094        // The packet's own TOC duration must fit the caller's frame_size. We split
1095        // the caller's buffer as sub_frame_size = frame_size / frame_count, so a
1096        // malformed multi-frame packet (large frame count vs. a small caller
1097        // buffer) would otherwise make sub_frame_size smaller than the 2.5/5 ms
1098        // redundancy-fade region — the fuzzer-found out-of-bounds/underflow panics
1099        // in redundancy_fade_start/redundancy_fade_end. C rejects such packets
1100        // here; so do we.
1101        let packet_frame_samples =
1102            repacketizer::samples_per_frame(toc, self.sampling_rate) as usize;
1103        if frame_count * packet_frame_samples > frame_size {
1104            return Err(Error::buffer_too_small(
1105                frame_count * packet_frame_samples,
1106                frame_size,
1107            ));
1108        }
1109
1110        // From here on, work in the packet's own duration rather than the
1111        // caller's buffer size. libopus does the same: `frame_size` is the room
1112        // available in `output`, and `opus_decode` returns however many samples
1113        // the packet actually held. Treating it as the exact output length
1114        // instead stretched a 20 ms packet across whatever buffer it was given.
1115        let frame_size = frame_count * packet_frame_samples;
1116
1117        self.frame_size = frame_size;
1118        self.stream_channels = packet_channels;
1119        // libopus sets `st->end` from the packet's bandwidth (opus_decoder.c:546)
1120        // *after* the mode-switch concealment runs, so that concealment still
1121        // sees the band range the outgoing mode was decoded with.
1122        let prev_celt_end_band = self.celt_end_band;
1123        self.celt_end_band = celt_endband_for_bandwidth(bandwidth);
1124
1125        let sub_frame_size = frame_size / frame_count;
1126        let sub_output_len = sub_frame_size * self.channels;
1127
1128        // libopus opus_decoder.c:374 — a SILK<->CELT switch leaves the layer
1129        // taking over with no overlap-add history, so its first samples start
1130        // from silence. Unless the encoder bridged the seam with a redundant
1131        // frame, libopus conceals 5 ms of the outgoing mode and cross-fades it
1132        // over the head of this frame. Only the packet's first Opus frame can
1133        // be a transition: after it, the previous mode is this one.
1134        let transition = match self.prev_mode {
1135            Some(prev) => {
1136                (mode == OpusMode::CeltOnly && prev != OpusMode::CeltOnly && !self.prev_redundancy)
1137                    || (mode != OpusMode::CeltOnly && prev == OpusMode::CeltOnly)
1138            }
1139            None => false,
1140        };
1141
1142        match mode {
1143            OpusMode::SilkOnly => {
1144                let internal_sample_rate = match bandwidth {
1145                    Bandwidth::Narrowband => 8000,
1146                    Bandwidth::Mediumband => 12000,
1147                    Bandwidth::Wideband => 16000,
1148                    _ => 16000,
1149                };
1150                let internal_frame_size =
1151                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
1152
1153                // Initialised even where the rates already match: the copy
1154                // path still applies the resampler's input delay, and
1155                // `render_silk_frame` now routes every SILK frame through it.
1156                if internal_sample_rate != self.prev_internal_rate {
1157                    self.silk_resampler
1158                        .init(internal_sample_rate, self.sampling_rate);
1159                    self.silk_resampler_r
1160                        .init(internal_sample_rate, self.sampling_rate);
1161                    self.prev_internal_rate = internal_sample_rate;
1162                }
1163                self.silk_internal_rate = internal_sample_rate;
1164                self.reset_silk_after_celt_only();
1165
1166                // Pure-SILK stereo (both stream and output are 2ch): reconstruct
1167                // true L/R via SILK MS->LR instead of duplicating the mono mid.
1168                let silk_lr = self.setup_silk_channels(packet_channels);
1169
1170                // A 40/60 ms Opus frame carries 2/3 internal 20 ms SILK frames;
1171                // 10/20 ms carry one. libopus calls silk_Decode once per internal
1172                // frame (continuing the same range coder within the payload). We
1173                // must too — decoding only the first internal frame leaves the
1174                // rest of a 40/60 ms packet silent (the "collapse" bug).
1175                let n_silk = match frame_duration_ms {
1176                    40 => 2,
1177                    60 => 3,
1178                    _ => 1,
1179                };
1180                let internal_sub_frame_size = internal_frame_size / n_silk;
1181                // Per-FRAME previous mode (libopus updates prev_mode per frame; for
1182                // payloads after the first, the previous frame is this same packet).
1183                let mut prev_mode_frame = self.prev_mode;
1184
1185                for (fi, payload) in frame_payloads.iter().enumerate() {
1186                    let mut rc = RangeCoder::new_decoder(payload);
1187                    let pcm_i16_len = internal_sub_frame_size * self.channels;
1188                    // A malformed packet can imply a frame larger than our scratch
1189                    // buffer; reject it gracefully instead of slicing out of bounds
1190                    // (a decode-path DoS on attacker-controlled input).
1191                    if pcm_i16_len + 2 > self.w_pcm_i16.len() {
1192                        return Err(Error::InvalidPacket("opus: SILK frame size exceeds buffer"));
1193                    }
1194                    let out_start = fi * sub_output_len;
1195                    let mut silk_off = 0usize; // output samples/ch within this Opus frame
1196
1197                    for sf in 0..n_silk {
1198                        let s_mid = self.silk_s_mid;
1199                        let ret = {
1200                            let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1201                            // Prepend the previous frame's last two samples (sMid) at
1202                            // [0..2] and decode at offset 2, matching libopus's
1203                            // samplesOut1_tmp[n][2] layout.
1204                            pcm_i16[0] = s_mid[0];
1205                            pcm_i16[1] = s_mid[1];
1206                            silk_dec.decode(
1207                                &mut rc,
1208                                &mut pcm_i16[2..pcm_i16_len + 2],
1209                                silk::decode_frame::FLAG_DECODE_NORMAL,
1210                                sf == 0,
1211                                frame_duration_ms,
1212                                internal_sample_rate,
1213                            )
1214                        };
1215
1216                        if ret < 0 {
1217                            return Err(Error::Internal("SILK decoding failed"));
1218                        }
1219
1220                        let decoded_samples = ret as usize;
1221                        // Carry the last two decoded samples as next frame's sMid.
1222                        if decoded_samples >= 2 {
1223                            self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1224                            self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1225                        }
1226                        let base = out_start + silk_off * self.channels;
1227
1228                        // Stereo SILK: L in silk_dec.l_out, R in silk_dec.r_out,
1229                        // both already in the 1-sample-delay-line layout. Resample
1230                        // each channel through its own resampler.
1231                        let out_len = self.render_silk_frame(
1232                            output,
1233                            base,
1234                            decoded_samples,
1235                            silk_lr,
1236                            internal_sample_rate,
1237                        );
1238                        silk_off += out_len;
1239                    }
1240
1241                    // --- Opus redundancy layer (opus_decoder.c:420-580) ---
1242                    // A SILK-only frame carries IMPLICIT CELT redundancy: if >= 17
1243                    // bits remain after SILK, the trailing bytes ARE a 5 ms CELT
1244                    // frame (no flag) used to smooth mode/bandwidth transitions.
1245                    let mut redundant_rng = 0u32;
1246                    let mut redundancy = false;
1247                    let mut celt_to_silk = false;
1248                    let plen = payload.len();
1249                    let f5 = (self.sampling_rate / 200) as usize;
1250                    let f2_5 = f5 / 2;
1251                    let red_end_band = celt_endband_for_bandwidth(bandwidth);
1252                    let mut red_buf = [0.0f32; 480]; // F5 * <=2ch, planar
1253                    let mut red_bytes = 0usize;
1254                    if self.sampling_rate == 48000 && rc.tell() + 17 <= (plen as i32) * 8 {
1255                        redundancy = true;
1256                        celt_to_silk = rc.decode_bit_logp(1);
1257                        red_bytes = plen - (((rc.tell() + 7) >> 3) as usize);
1258                        if red_bytes < 2 || red_bytes >= plen {
1259                            redundancy = false;
1260                            red_bytes = 0;
1261                        }
1262                    }
1263                    // A redundant frame already bridges the seam, so it replaces
1264                    // the cross-fade rather than stacking with it
1265                    // (opus_decoder.c:532). Conceal before the redundant frame
1266                    // below advances the CELT state it reads.
1267                    let fade_transition = transition && fi == 0 && !redundancy;
1268                    if fade_transition {
1269                        self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1270                    }
1271                    // CELT->SILK: the redundant frame continues the prior CELT
1272                    // state (a fade-out of the previous CELT mode). Decode BEFORE
1273                    // the hybrid->SILK silence frame to keep libopus state order.
1274                    if redundancy && celt_to_silk {
1275                        redundant_rng = self.decode_redundant_celt(
1276                            &payload[plen - red_bytes..],
1277                            false,
1278                            packet_channels,
1279                            red_end_band,
1280                            &mut red_buf[..f5 * self.channels],
1281                        );
1282                    }
1283                    // Hybrid->SILK transition: let the CELT MDCT fade out by
1284                    // decoding a 2-byte silence frame; its 2.5 ms overlap tail is
1285                    // ADDED to the output (libopus decodes it into pcm before the
1286                    // SILK sum).
1287                    if self.sampling_rate == 48000
1288                        && prev_mode_frame == Some(OpusMode::Hybrid)
1289                        && !(redundancy && celt_to_silk && self.prev_redundancy)
1290                    {
1291                        let silence = [0xFFu8, 0xFF];
1292                        let mut sil_buf = [0.0f32; 240]; // F2_5 * <=2ch
1293                        self.celt_dec.set_stream_channels(packet_channels);
1294                        let mut src = RangeCoder::new_decoder(&silence);
1295                        self.celt_dec.decode_from_range_coder_with_band_range(
1296                            &mut src,
1297                            16,
1298                            f2_5,
1299                            &mut sil_buf[..f2_5 * self.channels],
1300                            0,
1301                            red_end_band,
1302                        );
1303                        let region = &mut output[out_start..out_start + sub_output_len];
1304                        for (o, s) in region.iter_mut().zip(&sil_buf[..f2_5 * self.channels]) {
1305                            *o += *s;
1306                        }
1307                    }
1308                    // SILK->CELT: reset, then decode — this PRIMES the CELT state
1309                    // for the upcoming CELT-mode frames (which is why the next mode
1310                    // change skips its reset when prev_redundancy is set).
1311                    if redundancy && !celt_to_silk {
1312                        redundant_rng = self.decode_redundant_celt(
1313                            &payload[plen - red_bytes..],
1314                            true,
1315                            packet_channels,
1316                            red_end_band,
1317                            &mut red_buf[..f5 * self.channels],
1318                        );
1319                    }
1320                    if redundancy {
1321                        let window = celt::modes::default_mode().window;
1322                        let region = &mut output[out_start..out_start + sub_output_len];
1323                        if celt_to_silk {
1324                            redundancy_fade_start(region, &red_buf, f2_5, self.channels, window);
1325                        } else {
1326                            redundancy_fade_end(
1327                                region,
1328                                sub_frame_size,
1329                                &red_buf,
1330                                f2_5,
1331                                self.channels,
1332                                window,
1333                            );
1334                        }
1335                    }
1336                    if fade_transition {
1337                        self.apply_transition(
1338                            &mut output[out_start..out_start + sub_output_len],
1339                            sub_frame_size,
1340                        );
1341                    }
1342                    self.prev_redundancy = redundancy && !celt_to_silk;
1343                    prev_mode_frame = Some(OpusMode::SilkOnly);
1344                    self.last_range = rc.rng ^ redundant_rng;
1345                }
1346                self.prev_mode = Some(OpusMode::SilkOnly);
1347                Ok(frame_size)
1348            }
1349
1350            OpusMode::CeltOnly => {
1351                let celt_end_band = self.celt_end_band_from_toc(toc);
1352                // Conceal the outgoing SILK/hybrid mode BEFORE the reset below
1353                // wipes the state it reads (opus_decoder.c:388).
1354                if transition {
1355                    self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1356                }
1357                // libopus opus_decoder.c:515 — discard CELT state on a mode change
1358                // unless the previous frame's SILK->CELT redundant frame already
1359                // primed it.
1360                if let Some(pm) = self.prev_mode
1361                    && pm != OpusMode::CeltOnly
1362                    && !self.prev_redundancy
1363                {
1364                    self.celt_dec.reset();
1365                }
1366                self.prev_redundancy = false;
1367                // Mono packet in a stereo stream => C=1, CC=2 (continuous state).
1368                self.celt_dec.set_stream_channels(packet_channels);
1369
1370                for (fi, payload) in frame_payloads.iter().enumerate() {
1371                    let mut rc = RangeCoder::new_decoder(payload);
1372                    let total_bits = (payload.len() * 8) as i32;
1373                    let needed = sub_frame_size * self.channels;
1374                    let out_start = fi * needed;
1375                    let out_end = (out_start + needed).min(output.len());
1376
1377                    if output.len() < out_end {
1378                        return Err(Error::buffer_too_small(out_end, output.len()));
1379                    }
1380
1381                    // No clamping: libopus's float API returns the
1382                    // reconstruction as-is, and codec ringing legitimately
1383                    // overshoots slightly. Clamping here also made this path
1384                    // disagree with the SILK path, which never did.
1385                    self.celt_dec.decode_from_range_coder_with_band_range(
1386                        &mut rc,
1387                        total_bits,
1388                        sub_frame_size,
1389                        &mut output[out_start..out_end],
1390                        0,
1391                        celt_end_band,
1392                    );
1393                    self.last_range = rc.rng;
1394                }
1395                if transition {
1396                    self.apply_transition(&mut output[..sub_output_len], sub_frame_size);
1397                }
1398                self.prev_mode = Some(OpusMode::CeltOnly);
1399                Ok(frame_size)
1400            }
1401
1402            OpusMode::Hybrid => {
1403                let internal_sample_rate = 16000;
1404                let internal_frame_size =
1405                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
1406                let celt_end_band = self.celt_end_band_from_toc(toc);
1407
1408                // Initialised even where the rates already match: the copy
1409                // path still applies the resampler's input delay, and
1410                // `render_silk_frame` now routes every SILK frame through it.
1411                if internal_sample_rate != self.prev_internal_rate {
1412                    self.silk_resampler
1413                        .init(internal_sample_rate, self.sampling_rate);
1414                    self.silk_resampler_r
1415                        .init(internal_sample_rate, self.sampling_rate);
1416                    self.prev_internal_rate = internal_sample_rate;
1417                }
1418                self.silk_internal_rate = internal_sample_rate;
1419                self.reset_silk_after_celt_only();
1420
1421                // Same SILK stereo/channel handling as the SilkOnly arm: true L/R
1422                // low band via MS->LR for stereo packets; per-packet internal
1423                // channel switch with side-channel/stereo-state resets.
1424                let silk_lr = self.setup_silk_channels(packet_channels);
1425
1426                for (fi, payload) in frame_payloads.iter().enumerate() {
1427                    let mut rc = RangeCoder::new_decoder(payload);
1428                    let pcm_silk_i16_len = internal_frame_size * self.channels;
1429                    if pcm_silk_i16_len + 2 > self.w_pcm_i16.len() {
1430                        return Err(Error::InvalidPacket("opus: SILK frame size exceeds buffer"));
1431                    }
1432
1433                    // Prepend the previous frame's last two samples (sMid) and
1434                    // decode at offset 2, matching libopus's samplesOut1_tmp[n][2]
1435                    // layout — the resampler is fed from offset 1 (the 1-sample
1436                    // delay line), keeping the SILK low band aligned with the CELT
1437                    // high band exactly as in the reference.
1438                    let s_mid = self.silk_s_mid;
1439                    let ret = {
1440                        let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1441                        pcm_i16[0] = s_mid[0];
1442                        pcm_i16[1] = s_mid[1];
1443                        silk_dec.decode(
1444                            &mut rc,
1445                            &mut pcm_i16[2..pcm_silk_i16_len + 2],
1446                            silk::decode_frame::FLAG_DECODE_NORMAL,
1447                            true,
1448                            frame_duration_ms,
1449                            internal_sample_rate,
1450                        )
1451                    };
1452
1453                    if ret < 0 {
1454                        return Err(Error::Internal("SILK decoding failed"));
1455                    }
1456
1457                    let silk_out_len = sub_frame_size * self.channels;
1458                    self.w_silk_out[..silk_out_len].fill(0.0);
1459                    if ret > 0 {
1460                        let decoded_samples = ret as usize;
1461                        if decoded_samples >= 2 {
1462                            self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1463                            self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1464                        }
1465                        let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1466                        let out_len =
1467                            ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
1468                        debug_assert!(out_len <= self.w_pcm_resampled.len());
1469                        if silk_lr {
1470                            // Stereo low band: L/R from dec_api (already in the
1471                            // 1-sample-delay layout), each through its own resampler.
1472                            self.silk_resampler.process(
1473                                &mut self.w_pcm_resampled[..out_len],
1474                                &self.silk_dec.l_out[..decoded_samples],
1475                                decoded_samples as i32,
1476                            );
1477                            for i in 0..out_len {
1478                                self.w_silk_out[i * 2] = self.w_pcm_resampled[i] as f32 / 32768.0;
1479                            }
1480                            self.silk_resampler_r.process(
1481                                &mut self.w_pcm_resampled[..out_len],
1482                                &self.silk_dec.r_out[..decoded_samples],
1483                                decoded_samples as i32,
1484                            );
1485                            for i in 0..out_len {
1486                                self.w_silk_out[i * 2 + 1] =
1487                                    self.w_pcm_resampled[i] as f32 / 32768.0;
1488                            }
1489                        } else {
1490                            self.silk_resampler.process(
1491                                &mut self.w_pcm_resampled[..out_len],
1492                                &self.w_pcm_i16[1..1 + decoded_samples],
1493                                decoded_samples as i32,
1494                            );
1495                            for i in 0..out_len {
1496                                let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1497                                for ch in 0..self.channels {
1498                                    self.w_silk_out[i * self.channels + ch] = v;
1499                                }
1500                            }
1501                            // Mono packet, stereo output: keep the right-channel
1502                            // resampler continuous (libopus dec_API.c:351-355).
1503                            if self.channels == 2 {
1504                                self.silk_resampler_r.process(
1505                                    &mut self.w_pcm_resampled[..out_len],
1506                                    &self.w_pcm_i16[1..1 + decoded_samples],
1507                                    decoded_samples as i32,
1508                                );
1509                                for i in 0..out_len {
1510                                    self.w_silk_out[i * 2 + 1] =
1511                                        self.w_pcm_resampled[i] as f32 / 32768.0;
1512                                }
1513                            }
1514                        }
1515                    }
1516
1517                    // --- Opus redundancy layer, hybrid form (opus_decoder.c) ---
1518                    // redundancy = bit(12); if set: celt_to_silk = bit(1),
1519                    // redundancy_bytes = uint(256)+2 taken from the END of the
1520                    // packet — the MAIN CELT layer still decodes, but with the
1521                    // range coder's storage shrunk by those bytes (this changes
1522                    // its raw-bit region and tell budget).
1523                    let plen = payload.len();
1524                    let mut redundancy = false;
1525                    let mut celt_to_silk = false;
1526                    let mut red_bytes = 0usize;
1527                    let mut effective_len = plen;
1528                    #[cfg(feature = "probe")]
1529                    {
1530                        self.probe_silk_bits = rc.tell();
1531                        self.probe_total_bits = (plen as i32) * 8;
1532                    }
1533                    if rc.tell() + 37 <= (plen as i32) * 8 {
1534                        redundancy = rc.decode_bit_logp(12);
1535                        if redundancy {
1536                            celt_to_silk = rc.decode_bit_logp(1);
1537                            red_bytes = rc.dec_uint(256) as usize + 2;
1538                            if red_bytes <= effective_len {
1539                                effective_len -= red_bytes;
1540                            } else {
1541                                red_bytes = 0;
1542                                redundancy = false;
1543                            }
1544                            if redundancy && (effective_len as i32) * 8 < rc.tell() {
1545                                effective_len = plen;
1546                                red_bytes = 0;
1547                                redundancy = false;
1548                            }
1549                            if redundancy {
1550                                rc.storage -= red_bytes as u32;
1551                            }
1552                        }
1553                    }
1554                    let f5 = (self.sampling_rate / 200) as usize;
1555                    let f2_5 = f5 / 2;
1556                    let red_end_band = celt_endband_for_bandwidth(bandwidth);
1557                    let mut red_buf = [0.0f32; 480];
1558                    let mut redundant_rng = 0u32;
1559                    let do_red = redundancy && self.sampling_rate == 48000;
1560                    // As in the SILK-only arm: a redundant frame replaces the
1561                    // mode-switch cross-fade (opus_decoder.c:532), and the
1562                    // concealment must run before the redundant frame or the
1563                    // CELT reset below disturbs the state it reads.
1564                    let fade_transition = transition && fi == 0 && !redundancy;
1565                    if fade_transition {
1566                        self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1567                    }
1568                    // CELT->SILK: redundant frame decodes BEFORE the main CELT,
1569                    // continuing the prior CELT state (fade-out of previous CELT).
1570                    if do_red && celt_to_silk {
1571                        redundant_rng = self.decode_redundant_celt(
1572                            &payload[plen - red_bytes..],
1573                            false,
1574                            packet_channels,
1575                            red_end_band,
1576                            &mut red_buf[..f5 * self.channels],
1577                        );
1578                    }
1579
1580                    // Main CELT high band. libopus opus_decoder.c:515 — reset CELT
1581                    // on a mode change unless primed by prior SILK->CELT redundancy.
1582                    if fi == 0
1583                        && let Some(pm) = self.prev_mode
1584                        && pm != OpusMode::Hybrid
1585                        && !self.prev_redundancy
1586                    {
1587                        self.celt_dec.reset();
1588                    }
1589                    self.celt_dec.set_stream_channels(packet_channels);
1590                    let total_bits = (effective_len * 8) as i32;
1591                    {
1592                        let (celt_dec, celt_out) = (&mut self.celt_dec, &mut self.w_celt_out);
1593                        celt_dec.decode_from_range_coder_with_band_range(
1594                            &mut rc,
1595                            total_bits,
1596                            sub_frame_size,
1597                            &mut celt_out[..silk_out_len],
1598                            17,
1599                            celt_end_band,
1600                        );
1601                    }
1602
1603                    let out_start = fi * silk_out_len;
1604                    let total = silk_out_len.min(output.len() - out_start);
1605                    for j in 0..total {
1606                        output[out_start + j] = self.w_silk_out[j] + self.w_celt_out[j];
1607                    }
1608
1609                    // SILK->CELT: reset + decode the redundant frame AFTER the main
1610                    // decode; it primes the CELT state for the upcoming CELT mode.
1611                    if do_red && !celt_to_silk {
1612                        redundant_rng = self.decode_redundant_celt(
1613                            &payload[plen - red_bytes..],
1614                            true,
1615                            packet_channels,
1616                            red_end_band,
1617                            &mut red_buf[..f5 * self.channels],
1618                        );
1619                    }
1620                    if do_red {
1621                        let window = celt::modes::default_mode().window;
1622                        let region = &mut output[out_start..out_start + silk_out_len];
1623                        if celt_to_silk {
1624                            redundancy_fade_start(region, &red_buf, f2_5, self.channels, window);
1625                        } else {
1626                            redundancy_fade_end(
1627                                region,
1628                                sub_frame_size,
1629                                &red_buf,
1630                                f2_5,
1631                                self.channels,
1632                                window,
1633                            );
1634                        }
1635                    }
1636                    if fade_transition {
1637                        self.apply_transition(
1638                            &mut output[out_start..out_start + silk_out_len],
1639                            sub_frame_size,
1640                        );
1641                    }
1642                    self.prev_redundancy = redundancy && !celt_to_silk;
1643                    self.last_range = rc.rng ^ redundant_rng;
1644                }
1645                self.prev_mode = Some(OpusMode::Hybrid);
1646                Ok(frame_size)
1647            }
1648        }
1649    }
1650}
1651
1652impl OpusDecoder {
1653    #[inline(always)]
1654    fn celt_end_band_from_toc(&self, toc: u8) -> usize {
1655        let mode = celt::modes::default_mode();
1656        let top = mode.eff_ebands;
1657        if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
1658            const FROM_OPUS_TABLE: [u8; 16] = [
1659                0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
1660                0x10, 0x18,
1661            ];
1662            let idx = ((toc >> 3) - 16) as usize;
1663            let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
1664            let trim = (data0 >> 5) as usize;
1665            return top.saturating_sub(2 * trim).max(1);
1666        }
1667        // Hybrid: libopus maps the packet bandwidth to a CELT end band
1668        // (opus_decoder.c: SWB -> 19, FB -> 21). Decoding SWB hybrid with 21
1669        // reads two bands the encoder never coded -> range desync every packet.
1670        if mode_from_toc(toc) == OpusMode::Hybrid
1671            && bandwidth_from_toc(toc) == Bandwidth::Superwideband
1672        {
1673            return 19.min(top);
1674        }
1675        top
1676    }
1677
1678    /// Decode a redundant CELT frame (opus_decoder.c "5 ms redundant frame"):
1679    /// start band 0, end band from the packet bandwidth, 5 ms, its own range
1680    /// decoder. Returns the redundant final range; PLANAR output in `buf`
1681    /// (F5 samples per state channel). Only valid at 48 kHz output.
1682    fn decode_redundant_celt(
1683        &mut self,
1684        red: &[u8],
1685        reset_first: bool,
1686        packet_channels: usize,
1687        end_band: usize,
1688        buf: &mut [f32],
1689    ) -> u32 {
1690        if reset_first {
1691            self.celt_dec.reset();
1692        }
1693        self.celt_dec.set_stream_channels(packet_channels);
1694        let f5 = (self.sampling_rate / 200) as usize;
1695        let mut rrc = RangeCoder::new_decoder(red);
1696        let total_bits = (red.len() * 8) as i32;
1697        self.celt_dec
1698            .decode_from_range_coder_with_band_range(&mut rrc, total_bits, f5, buf, 0, end_band);
1699        rrc.rng
1700    }
1701}
1702
1703/// First CELT band the hybrid layer codes; below it the SILK layer owns the
1704/// spectrum (libopus `start_band = 17`).
1705const HYBRID_START_BAND: usize = 17;
1706
1707/// libopus opus_decoder.c bandwidth -> CELT end band for the packet.
1708/// smooth_fade cross-fades (w = window[i]^2, 48 kHz inc=1) applied to the
1709/// interleaved output region of one frame. `red` is interleaved too.
1710/// celt_to_silk: redundant frame occupies the START of the frame — first 2.5 ms
1711/// copied verbatim, next 2.5 ms fades redundant -> main.
1712///
1713/// Indexing invariant: `out.len() >= f5 * channels` (writes reach sample
1714/// f5-1 = 2*f2_5-1). A malformed multi-frame packet used to violate this (a
1715/// hostile frame count made the per-frame region tinier than F5, fuzzer-found
1716/// OOB panics here); decode() now rejects such packets up front exactly as C
1717/// libopus does (opus_decode_native's count*packet_frame_size > frame_size ->
1718/// OPUS_BUFFER_TOO_SMALL, and the 120 ms cap of opus_packet_parse_impl), so a
1719/// redundant frame always has >= 10 ms of frame to fade into, as in C.
1720fn redundancy_fade_start(
1721    out: &mut [f32],
1722    red: &[f32],
1723    f2_5: usize,
1724    channels: usize,
1725    window: &[f32],
1726) {
1727    out[..f2_5 * channels].copy_from_slice(&red[..f2_5 * channels]);
1728    for i in 0..f2_5 {
1729        let w = window[i] * window[i];
1730        for c in 0..channels {
1731            let idx = (f2_5 + i) * channels + c;
1732            out[idx] = (1.0 - w) * red[idx] + w * out[idx];
1733        }
1734    }
1735}
1736
1737/// SILK->CELT: redundant frame occupies the END of the frame — the last 2.5 ms
1738/// fades main -> redundant (second half of the redundant frame).
1739///
1740/// Indexing invariant: `frame_samples >= f2_5` and `out.len() >=
1741/// frame_samples * channels` (the index `frame_samples - f2_5 + i` would
1742/// otherwise underflow). A malformed multi-frame packet used to violate this
1743/// (fuzzer-found subtract-with-overflow panic here); decode() now rejects such
1744/// packets up front exactly as C libopus does (opus_decode_native's
1745/// count*packet_frame_size > frame_size -> OPUS_BUFFER_TOO_SMALL, plus the
1746/// 120 ms cap of opus_packet_parse_impl), so redundancy only ever runs on
1747/// frames of >= 10 ms, as in C.
1748fn redundancy_fade_end(
1749    out: &mut [f32],
1750    frame_samples: usize,
1751    red: &[f32],
1752    f2_5: usize,
1753    channels: usize,
1754    window: &[f32],
1755) {
1756    for i in 0..f2_5 {
1757        let w = window[i] * window[i];
1758        for c in 0..channels {
1759            let idx = (frame_samples - f2_5 + i) * channels + c;
1760            out[idx] = (1.0 - w) * out[idx] + w * red[(f2_5 + i) * channels + c];
1761        }
1762    }
1763}