Skip to main content

rusty_opus/
lib.rs

1#![allow(unsafe_op_in_unsafe_fn)]
2#![allow(clippy::too_many_arguments)]
3#![allow(clippy::needless_range_loop)]
4
5pub mod analysis;
6pub mod analysis_data;
7pub mod bands;
8pub mod celt;
9pub mod celt_lpc;
10pub mod hp_cutoff;
11pub mod kiss_fft;
12pub mod mdct;
13pub mod modes;
14pub mod parallel;
15pub mod pitch;
16pub mod prof;
17pub mod pvq;
18pub mod quant_bands;
19pub mod range_coder;
20pub mod repacketizer;
21pub mod multistream;
22pub mod rate;
23pub mod silk;
24
25pub use silk::{SilkResampler, SilkResamplerDown1_3, SilkResamplerDown1_6};
26
27pub use celt::{CeltDecoder, CeltEncoder};
28use hp_cutoff::hp_cutoff;
29use range_coder::RangeCoder;
30use silk::control_codec::silk_control_encoder;
31use silk::enc_api::silk_encode;
32use silk::init_encoder::silk_init_encoder;
33use silk::lin2log::silk_lin2log;
34use silk::log2lin::silk_log2lin;
35use silk::macros::*;
36use silk::resampler::{silk_resampler_down2, silk_resampler_down2_3};
37use silk::structs::SilkEncoderState;
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum Application {
41    Voip = 2048,
42    Audio = 2049,
43    RestrictedLowDelay = 2051,
44}
45
46/// OPUS_SET_SIGNAL hint: bias mode selection toward speech or music. `None` =
47/// OPUS_AUTO (let the analysis decide).
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum SignalType {
50    Voice,
51    Music,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum Bandwidth {
56    Auto = -1000,
57    Narrowband = 1101,
58    Mediumband = 1102,
59    Wideband = 1103,
60    Superwideband = 1104,
61    Fullband = 1105,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65enum OpusMode {
66    SilkOnly,
67    Hybrid,
68    CeltOnly,
69}
70
71pub struct OpusEncoder {
72    celt_enc: CeltEncoder,
73    silk_enc: Box<SilkEncoderState>,
74    application: Application,
75    sampling_rate: i32,
76    channels: usize,
77    bandwidth: Bandwidth,
78    pub bitrate_bps: i32,
79    pub complexity: i32,
80    pub use_cbr: bool,
81
82    pub use_inband_fec: bool,
83
84    /// Discontinuous transmission: after enough consecutive inactive frames,
85    /// emit a 1-byte (TOC-only) packet so the decoder runs comfort-noise/PLC.
86    pub use_dtx: bool,
87    /// Consecutive inactive milliseconds, in Q1 (opus_encoder.c nb_no_activity).
88    nb_no_activity_ms_q1: i32,
89    /// Final range-coder state of the last packet (0 for DTX/PLC packets, which
90    /// carry no coded range — opus_encoder.c st->rangeFinal).
91    range_final: u32,
92
93    pub packet_loss_perc: i32,
94    silk_initialized: bool,
95    mode: OpusMode,
96    prev_enc_mode: Option<OpusMode>,
97
98    variable_hp_smth2_q15: i32,
99    /// Rate-dependent automatic bandwidth (libopus auto_bandwidth), stored as the
100    /// Bandwidth discriminant (1101 NB .. 1105 FB). Hysteresis state.
101    auto_bandwidth: i32,
102    first_frame: bool,
103    /// Overrides automatic bandwidth selection when set (OPUS_SET_BANDWIDTH).
104    pub force_bandwidth: Option<Bandwidth>,
105    /// OPUS_SET_SIGNAL: force the voice/music bias (None = auto from analysis).
106    pub signal_type: Option<SignalType>,
107    /// OPUS_SET_MAX_BANDWIDTH: cap the automatically-selected bandwidth.
108    pub max_bandwidth: Bandwidth,
109    /// Tonality/music/bandwidth analysis (libopus src/analysis.c); runs when
110    /// complexity >= 7 and the API rate is >= 16 kHz.
111    tonality: analysis::TonalityAnalysisState,
112    analysis_kfft: Option<kiss_fft::KissFftState>,
113    /// Input bit depth assumed by the analysis noise floors. The float API
114    /// default is 24; set 16 for s16-sourced content (opus_demo parity).
115    pub lsb_depth: i32,
116    /// 0..100 voice probability from the analysis (-1 = unknown), C voice_ratio.
117    voice_ratio: i32,
118    detected_bandwidth: i32,
119    hp_mem: Vec<i32>,
120
121    buf_filtered: Vec<i16>,
122    buf_silk_input: Vec<i16>,
123    buf_stereo_mid: Vec<i16>,
124    buf_stereo_side: Vec<i16>,
125    buf_celt_input: Vec<f32>,
126    down2_state_first: [i32; 2],
127    down2_state_second: [i32; 2],
128    down2_3_state: [i32; 6],
129    down_1_3_state: silk::resampler::SilkResamplerDown1_3,
130    down2_3_state_r: [i32; 6],
131    down_1_3_state_r: silk::resampler::SilkResamplerDown1_3,
132    down_fir_l: Option<silk::resampler::SilkDownFirResampler>,
133    down_fir_r: Option<silk::resampler::SilkDownFirResampler>,
134    /// Last 10 ms of API-rate mono input, for the SILK prefill after a
135    /// CELT-only -> SILK/hybrid transition (opus_encoder.c:1449 prefill=1).
136    silk_prefill_tail: Vec<i16>,
137    silk_prefill_pending: bool,
138    buf_left: Vec<i16>,
139    buf_right: Vec<i16>,
140    /// Last 2.5 ms of the previous frame's input (planar), for the CELT
141    /// prefill after a mode-transition reset (opus_encoder.c:2060).
142    celt_prefill_tail: Vec<f32>,
143
144    rc: RangeCoder,
145}
146
147// libopus opus_encoder.c bandwidth thresholds: (threshold, hysteresis) pairs for
148// NB<->MB, MB<->WB, WB<->SWB, SWB<->FB, interpolated voice<->music by voice_est^2.
149const MONO_VOICE_BANDWIDTH_THRESHOLDS: [i32; 8] = [9000, 700, 9000, 700, 13500, 1000, 14000, 2000];
150const MONO_MUSIC_BANDWIDTH_THRESHOLDS: [i32; 8] = [9000, 700, 9000, 700, 11000, 1000, 12000, 2000];
151const STEREO_VOICE_BANDWIDTH_THRESHOLDS: [i32; 8] = [9000, 700, 9000, 700, 13500, 1000, 14000, 2000];
152const STEREO_MUSIC_BANDWIDTH_THRESHOLDS: [i32; 8] = [9000, 700, 9000, 700, 11000, 1000, 12000, 2000];
153
154fn compute_equiv_rate(
155    bitrate: i32,
156    channels: usize,
157    frame_rate: i32,
158    vbr: bool,
159    complexity: i32,
160    loss: i32,
161) -> i32 {
162    let mut equiv = bitrate;
163    if frame_rate > 50 {
164        equiv -= (40 * channels as i32 + 20) * (frame_rate - 50);
165    }
166    if !vbr {
167        equiv -= equiv / 12;
168    }
169    equiv = equiv * (90 + complexity) / 100;
170    if loss > 0 {
171        equiv -= equiv * loss / (12 * loss + 20);
172    }
173    equiv
174}
175
176fn compute_mode_threshold(
177    application: Application,
178    channels: usize,
179    prev_was_celt: bool,
180    has_prev_mode: bool,
181    voice_est: i32,
182) -> i32 {
183    let mode_voice = if channels == 1 { 64000 } else { 44000 };
184    let mode_music = 10000;
185
186    let diff = mode_voice - mode_music;
187    let offset = (voice_est * voice_est * diff) >> 14;
188    let mut threshold = mode_music + offset;
189
190    if application == Application::Voip {
191        threshold += 8000;
192    }
193
194    if has_prev_mode {
195        if prev_was_celt {
196            threshold -= 4000;
197        } else {
198            threshold += 4000;
199        }
200    }
201
202    if application == Application::RestrictedLowDelay {
203        threshold = 0;
204    }
205
206    threshold
207}
208
209fn compute_silk_rate_for_hybrid(
210    rate_bps: i32,
211    bandwidth: Bandwidth,
212    frame20ms: bool,
213    vbr: bool,
214) -> i32 {
215    const RATE_TABLE: &[(i32, i32, i32)] = &[
216        (0, 0, 0),
217        (12000, 10000, 10000),
218        (16000, 13500, 13500),
219        (20000, 16000, 16000),
220        (24000, 18000, 18000),
221        (32000, 22000, 22000),
222        (64000, 38000, 38000),
223    ];
224    let n = RATE_TABLE.len();
225    let mut i = 1;
226    while i < n && RATE_TABLE[i].0 <= rate_bps {
227        i += 1;
228    }
229    let mut silk_rate = if i == n {
230        let (x_last, r10_last, r20_last) = RATE_TABLE[n - 1];
231        let base = if frame20ms { r20_last } else { r10_last };
232        base + (rate_bps - x_last) / 2
233    } else {
234        let (x0, lo10, lo20) = RATE_TABLE[i - 1];
235        let (x1, hi10, hi20) = RATE_TABLE[i];
236        let (lo, hi) = if frame20ms {
237            (lo20, hi20)
238        } else {
239            (lo10, hi10)
240        };
241        (lo * (x1 - rate_bps) + hi * (rate_bps - x0)) / (x1 - x0)
242    };
243    // C tail adjustments (opus_encoder.c:789): tiny SILK boost for CBR, and
244    // +300 for SWB hybrid (the CELT part starts at band 17 either way but
245    // covers less spectrum, so SILK earns a bigger share).
246    if !vbr {
247        silk_rate += 100;
248    }
249    if bandwidth == Bandwidth::Superwideband {
250        silk_rate += 300;
251    }
252    silk_rate
253}
254
255#[cfg(test)]
256mod silk_rate_tests {
257    use super::compute_silk_rate_for_hybrid;
258    use crate::Bandwidth;
259
260    #[test]
261    fn test_reference_table_exact_entries() {
262        assert_eq!(compute_silk_rate_for_hybrid(12000, Bandwidth::Fullband, true, true), 10000);
263        assert_eq!(compute_silk_rate_for_hybrid(16000, Bandwidth::Fullband, true, true), 13500);
264        assert_eq!(compute_silk_rate_for_hybrid(20000, Bandwidth::Fullband, true, true), 16000);
265        assert_eq!(compute_silk_rate_for_hybrid(24000, Bandwidth::Fullband, true, true), 18000);
266        assert_eq!(compute_silk_rate_for_hybrid(32000, Bandwidth::Fullband, true, true), 22000);
267        assert_eq!(compute_silk_rate_for_hybrid(64000, Bandwidth::Fullband, true, true), 38000);
268    }
269
270    #[test]
271    fn test_32kbps_gives_22kbps_silk() {
272        assert_eq!(compute_silk_rate_for_hybrid(32000, Bandwidth::Fullband, true, true), 22000);
273    }
274
275    #[test]
276    fn test_interpolation_between_table_entries() {
277        let r = compute_silk_rate_for_hybrid(18000, Bandwidth::Fullband, true, true);
278        assert_eq!(r, 14750);
279    }
280
281    #[test]
282    fn test_above_table_max_gives_half_extra() {
283        let r = compute_silk_rate_for_hybrid(72000, Bandwidth::Fullband, true, true);
284        assert_eq!(r, 38000 + (72000 - 64000) / 2);
285    }
286}
287
288impl OpusEncoder {
289    pub fn new(
290        sampling_rate: i32,
291        channels: usize,
292        application: Application,
293    ) -> Result<Self, &'static str> {
294        if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
295            return Err("Invalid sampling rate");
296        }
297        if ![1, 2].contains(&channels) {
298            return Err("Invalid number of channels");
299        }
300
301        let mode = modes::default_mode();
302        let celt_enc = CeltEncoder::new(mode, channels);
303
304        let mut silk_enc = Box::new(SilkEncoderState::default());
305        if silk_init_encoder(&mut silk_enc, 0) != 0 {
306            return Err("SILK encoder initialization failed");
307        }
308
309        let (opus_mode, bw) = match application {
310            Application::Voip => {
311                let bw = match sampling_rate {
312                    8000 => Bandwidth::Narrowband,
313                    12000 => Bandwidth::Mediumband,
314                    16000 => Bandwidth::Wideband,
315                    24000 => Bandwidth::Superwideband,
316                    48000 => Bandwidth::Fullband,
317                    _ => Bandwidth::Narrowband,
318                };
319
320                let mode = if sampling_rate > 16000 {
321                    OpusMode::Hybrid
322                } else {
323                    OpusMode::SilkOnly
324                };
325                (mode, bw)
326            }
327            Application::RestrictedLowDelay => {
328                let bw = match sampling_rate {
329                    8000 => Bandwidth::Narrowband,
330                    12000 => Bandwidth::Mediumband,
331                    16000 => Bandwidth::Wideband,
332                    24000 => Bandwidth::Superwideband,
333                    _ => Bandwidth::Fullband,
334                };
335                (OpusMode::CeltOnly, bw)
336            }
337            Application::Audio => {
338                if sampling_rate <= 16000 {
339                    let bw = match sampling_rate {
340                        8000 => Bandwidth::Narrowband,
341                        12000 => Bandwidth::Mediumband,
342                        _ => Bandwidth::Wideband,
343                    };
344                    (OpusMode::SilkOnly, bw)
345                } else {
346                    let bw = match sampling_rate {
347                        24000 => Bandwidth::Superwideband,
348                        _ => Bandwidth::Fullband,
349                    };
350                    (OpusMode::Hybrid, bw)
351                }
352            }
353        };
354
355        use silk::lin2log::silk_lin2log;
356        let variable_hp_smth2_q15 = silk_lin2log(60) << 8;
357
358        Ok(Self {
359            celt_enc,
360            silk_enc,
361            application,
362            sampling_rate,
363            channels,
364            bandwidth: bw,
365            bitrate_bps: 64000,
366            complexity: 9,
367            use_cbr: false,
368            use_inband_fec: false,
369            use_dtx: false,
370            nb_no_activity_ms_q1: 0,
371            range_final: 0,
372            packet_loss_perc: 0,
373            silk_initialized: false,
374            prev_enc_mode: None,
375            mode: opus_mode,
376            variable_hp_smth2_q15,
377            auto_bandwidth: 0,
378            first_frame: true,
379            force_bandwidth: None,
380            signal_type: None,
381            max_bandwidth: Bandwidth::Fullband,
382            tonality: analysis::TonalityAnalysisState::new(sampling_rate),
383            analysis_kfft: kiss_fft::KissFftState::new(480),
384            lsb_depth: 24,
385            voice_ratio: -1,
386            detected_bandwidth: 0,
387            hp_mem: vec![0; channels * 2],
388
389            buf_filtered: Vec::new(),
390            buf_silk_input: Vec::new(),
391            buf_stereo_mid: Vec::new(),
392            buf_stereo_side: Vec::new(),
393            buf_celt_input: Vec::new(),
394            down2_state_first: [0; 2],
395            down2_state_second: [0; 2],
396            down2_3_state: [0; 6],
397            down_1_3_state: silk::resampler::SilkResamplerDown1_3::default(),
398            down2_3_state_r: [0; 6],
399            down_1_3_state_r: silk::resampler::SilkResamplerDown1_3::default(),
400            down_fir_l: None,
401            down_fir_r: None,
402            silk_prefill_tail: Vec::new(),
403            silk_prefill_pending: false,
404            buf_left: Vec::new(),
405            buf_right: Vec::new(),
406            celt_prefill_tail: Vec::new(),
407            rc: RangeCoder::new_encoder(1),
408        })
409    }
410
411    pub fn enable_hybrid_mode(&mut self) -> Result<(), &'static str> {
412        if self.sampling_rate != 24000 && self.sampling_rate != 48000 {
413            return Err("Hybrid mode requires 24kHz or 48kHz sampling rate");
414        }
415        let bw = if self.sampling_rate == 48000 {
416            Bandwidth::Fullband
417        } else {
418            Bandwidth::Superwideband
419        };
420        self.mode = OpusMode::Hybrid;
421        self.bandwidth = bw;
422        self.silk_initialized = false;
423        Ok(())
424    }
425
426    /// Final range-coder state of the last encoded packet (libopus
427    /// OPUS_GET_FINAL_RANGE). Stored in opus_demo `.bit` framing so the reference
428    /// decoder can verify encoder/decoder range-coder agreement per packet.
429    pub fn final_range(&self) -> u32 {
430        self.range_final
431    }
432
433    /// opus_encoder.c:1296 voice_est ladder (signal_type is AUTO for us):
434    /// analysis-driven when voice_ratio is known, else application defaults.
435    fn compute_voice_est(&self) -> i32 {
436        match self.signal_type {
437            Some(SignalType::Voice) => return 127,
438            Some(SignalType::Music) => return 0,
439            None => {}
440        }
441        if self.voice_ratio >= 0 {
442            let mut v = self.voice_ratio * 327 >> 8;
443            // For AUDIO, never be more than 90% confident of having speech.
444            if self.application == Application::Audio {
445                v = v.min(115);
446            }
447            v
448        } else {
449            match self.application {
450                Application::Voip => 115,
451                Application::Audio => 48,
452                Application::RestrictedLowDelay => 0,
453            }
454        }
455    }
456
457    pub fn encode(
458        &mut self,
459        input: &[f32],
460        frame_size: usize,
461        output: &mut [u8],
462    ) -> Result<usize, &'static str> {
463        let _prof_total = crate::prof::scope(crate::prof::Stage::Total);
464        if output.len() < 2 {
465            return Err("Output buffer too small");
466        }
467
468        let frame_rate = frame_rate_from_params(self.sampling_rate, frame_size)
469            .ok_or("Invalid frame size for sampling rate")?;
470
471        // ---- Tonality analysis (opus_encoder.c:1123) ----
472        let mut analysis_info = analysis::AnalysisInfo::default();
473        if self.complexity >= 7 && self.sampling_rate >= 16000 {
474            if let Some(kfft) = &self.analysis_kfft {
475                analysis_info = analysis::run_analysis(
476                    &mut self.tonality,
477                    kfft,
478                    input,
479                    frame_size,
480                    frame_size,
481                    self.channels,
482                    self.sampling_rate,
483                    self.lsb_depth,
484                );
485            }
486        } else if self.tonality.initialized() {
487            self.tonality.reset();
488        }
489
490        // voice_ratio / detected_bandwidth from the analysis (opus_encoder.c:1154).
491        let silence_thresh = 1.0f32 / (1i64 << self.lsb_depth) as f32;
492        let is_silence = input[..(frame_size * self.channels).min(input.len())]
493            .iter()
494            .fold(0.0f32, |m, &v| m.max(v.abs()))
495            <= silence_thresh;
496        if !is_silence {
497            self.voice_ratio = -1;
498        }
499        // Voice-activity flag for DTX (opus_encoder.c:1160). Silence is always
500        // inactive; with analysis, use the VAD probability; without it, assume
501        // active (conservative — never DTX away real audio). We skip the
502        // peak-energy SNR fallback, which only ever ADDS activity.
503        let activity = if is_silence {
504            false
505        } else if analysis_info.valid {
506            analysis_info.activity_probability >= 0.1
507        } else {
508            true
509        };
510        self.detected_bandwidth = 0;
511        if analysis_info.valid {
512            // signal_type is AUTO: pick the hysteresis-correct probability.
513            let prob = if self.prev_enc_mode.is_none() {
514                analysis_info.music_prob
515            } else if self.prev_enc_mode == Some(OpusMode::CeltOnly) {
516                analysis_info.music_prob_max
517            } else {
518                analysis_info.music_prob_min
519            };
520            self.voice_ratio = (0.5 + 100.0 * (1.0 - prob)).floor() as i32;
521            let ab = analysis_info.bandwidth;
522            self.detected_bandwidth = if ab <= 12 {
523                Bandwidth::Narrowband as i32
524            } else if ab <= 14 {
525                Bandwidth::Mediumband as i32
526            } else if ab <= 16 {
527                Bandwidth::Wideband as i32
528            } else if ab <= 18 {
529                Bandwidth::Superwideband as i32
530            } else {
531                Bandwidth::Fullband as i32
532            };
533        }
534
535        // Mode selection: match C's opus_encode_native() behavior.
536        // C reference auto-selects between SILK_ONLY and CELT_ONLY; Hybrid is
537        // produced afterwards by bandwidth overrides (SILK-only + FB/SWB → Hybrid).
538        let mut mode = if self.application == Application::RestrictedLowDelay {
539            OpusMode::CeltOnly
540        } else {
541            let equiv = compute_equiv_rate(
542                self.bitrate_bps,
543                self.channels,
544                frame_rate,
545                !self.use_cbr,
546                self.complexity,
547                self.packet_loss_perc,
548            );
549            let prev_was_celt = self.prev_enc_mode == Some(OpusMode::CeltOnly);
550            let has_prev_mode = self.prev_enc_mode.is_some();
551            let voice_est = self.compute_voice_est();
552            let threshold = compute_mode_threshold(
553                self.application,
554                self.channels,
555                prev_was_celt,
556                has_prev_mode,
557                voice_est,
558            );
559            if equiv >= threshold && self.sampling_rate >= 24000 {
560                OpusMode::CeltOnly
561            } else {
562                OpusMode::SilkOnly
563            }
564        };
565
566        // ---- Automatic rate-dependent bandwidth selection (opus_encoder.c:1456) ----
567        // Walk down from FB; stop at the first bandwidth whose hysteresis-adjusted
568        // threshold the equivalent rate meets. Thresholds interpolate voice<->music
569        // by voice_est^2. Without the tonality analysis we cannot do
570        // detected-bandwidth reduction, so this reproduces libopus's
571        // complexity-0 choices (measured: WB @16k, SWB @20k, FB @24k+ voip mono).
572        {
573            let equiv = compute_equiv_rate(
574                self.bitrate_bps,
575                self.channels,
576                frame_rate,
577                !self.use_cbr,
578                self.complexity,
579                self.packet_loss_perc,
580            );
581            let voice_est: i32 = self.compute_voice_est();
582            let (vt, mt) = if self.channels == 2 {
583                (
584                    &STEREO_VOICE_BANDWIDTH_THRESHOLDS,
585                    &STEREO_MUSIC_BANDWIDTH_THRESHOLDS,
586                )
587            } else {
588                (
589                    &MONO_VOICE_BANDWIDTH_THRESHOLDS,
590                    &MONO_MUSIC_BANDWIDTH_THRESHOLDS,
591                )
592            };
593            let mut th = [0i32; 8];
594            for i in 0..8 {
595                th[i] = mt[i] + ((voice_est * voice_est * (vt[i] - mt[i])) >> 14);
596            }
597            const NB: i32 = Bandwidth::Narrowband as i32; // 1101
598            const MB: i32 = Bandwidth::Mediumband as i32; // 1102
599            const FB: i32 = Bandwidth::Fullband as i32; // 1105
600            let mut bw = FB;
601            while bw > NB {
602                let idx = (2 * (bw - MB)) as usize;
603                let mut threshold = th[idx];
604                let hysteresis = th[idx + 1];
605                if !self.first_frame {
606                    if self.auto_bandwidth >= bw {
607                        threshold -= hysteresis;
608                    } else {
609                        threshold += hysteresis;
610                    }
611                }
612                if equiv >= threshold {
613                    break;
614                }
615                bw -= 1;
616            }
617            // Mediumband is no longer used by libopus's selector.
618            if bw == MB {
619                bw = Bandwidth::Wideband as i32;
620            }
621            self.auto_bandwidth = bw;
622            // Hybrid at unsafe CBR rates starves SILK: cap at WB below 15 kb/s.
623            if mode != OpusMode::CeltOnly && self.use_cbr && self.bitrate_bps < 15000 {
624                bw = bw.min(Bandwidth::Wideband as i32);
625            }
626            // NB/MB SILK-internal rates (8/12 kHz) aren't wired for >16 kHz API
627            // input yet (no 48k->8k/12k encode resamplers); clamp to WB.
628            if mode != OpusMode::CeltOnly && self.sampling_rate > 16000 {
629                bw = bw.max(Bandwidth::Wideband as i32);
630            }
631            // Never code above the input's Nyquist (opus_encoder.c:1516).
632            if self.sampling_rate <= 24000 {
633                bw = bw.min(Bandwidth::Superwideband as i32);
634            }
635            if self.sampling_rate <= 16000 {
636                bw = bw.min(Bandwidth::Wideband as i32);
637            }
638            if self.sampling_rate <= 12000 {
639                bw = bw.min(Bandwidth::Mediumband as i32);
640            }
641            if self.sampling_rate <= 8000 {
642                bw = bw.min(Bandwidth::Narrowband as i32);
643            }
644            // (MB remap above may have been undone by the caps; keep WB floor
645            // only where the API rate allows it.)
646            if bw == Bandwidth::Mediumband as i32 && self.sampling_rate > 12000 {
647                bw = Bandwidth::Wideband as i32;
648            }
649            // Use the detected bandwidth to reduce the coded bandwidth
650            // (opus_encoder.c:1526), conservatively floored by rate. (For
651            // CELT-only this is currently undone below — no end-band support.)
652            // For CELT-only, hold the detected-bandwidth narrowing until the
653            // leak_boost dynalloc lands: decisions already match libopus
654            // frame-for-frame (64k st music: 27:704/31:680/23:90 both), but our
655            // dynalloc lacks C's leakage compensation at the spectral cut, so
656            // the same narrowing costs 0.25 ODG more than C pays (PEAQ-gated
657            // out). Hybrid/SILK caps (incl. hybrid SWB) stay live.
658            // CELT-only keeps FULL bandwidth by choice: C's detected-bandwidth
659            // narrowing costs PEAQ universally (libopus's own -2.11 at 64k st
660            // IS its narrowed score; our FB encode scores -1.65 on the same
661            // clip). leak_boost did NOT change this verdict (tested 2026-07-09
662            // with the full dynalloc live: narrowing still -2.37). Hybrid/SILK
663            // caps stay (they pick coding MODE, not spectral truncation).
664            if self.detected_bandwidth != 0
665                && self.force_bandwidth.is_none()
666                && mode != OpusMode::CeltOnly
667            {
668                let ch = self.channels as i32;
669                let equiv2 = equiv; // same 20-ms equivalent rate as the walk
670                let min_det = if equiv2 <= 18000 * ch && mode == OpusMode::CeltOnly {
671                    NB
672                } else if equiv2 <= 24000 * ch && mode == OpusMode::CeltOnly {
673                    MB
674                } else if equiv2 <= 30000 * ch {
675                    Bandwidth::Wideband as i32
676                } else if equiv2 <= 44000 * ch {
677                    Bandwidth::Superwideband as i32
678                } else {
679                    FB
680                };
681                bw = bw.min(self.detected_bandwidth.max(min_det));
682            }
683            // Cap by OPUS_SET_MAX_BANDWIDTH before the force override
684            // (opus_encoder.c: bandwidth = IMIN(bandwidth, max_bandwidth)), but
685            // keep the WB floor for non-CELT >16 kHz input — NB/MB SILK from
686            // 48 kHz needs the 48->8/12k encode resamplers we don't have, so a
687            // max_bandwidth of NB/MB there would emit an uncodeable config.
688            let mut max_bw = self.max_bandwidth as i32;
689            if mode != OpusMode::CeltOnly && self.sampling_rate > 16000 {
690                max_bw = max_bw.max(Bandwidth::Wideband as i32);
691            }
692            bw = bw.min(max_bw);
693            // The CELT TOC has no mediumband config; C maps MB down to NB.
694            if mode == OpusMode::CeltOnly && bw == MB {
695                bw = NB;
696            }
697            self.bandwidth = match self.force_bandwidth {
698                Some(f) => f,
699                None => match bw {
700                    x if x == NB => Bandwidth::Narrowband,
701                    x if x == MB => Bandwidth::Mediumband,
702                    x if x == Bandwidth::Wideband as i32 => Bandwidth::Wideband,
703                    x if x == Bandwidth::Superwideband as i32 => Bandwidth::Superwideband,
704                    x if x == FB => Bandwidth::Fullband,
705                    _ => Bandwidth::Wideband,
706                },
707            };
708            self.first_frame = false;
709        }
710
711        let curr_bw = self.bandwidth;
712        if mode == OpusMode::SilkOnly
713            && (curr_bw == Bandwidth::Superwideband || curr_bw == Bandwidth::Fullband)
714        {
715            mode = OpusMode::Hybrid;
716        }
717        if mode == OpusMode::Hybrid
718            && (curr_bw == Bandwidth::Narrowband
719                || curr_bw == Bandwidth::Mediumband
720                || curr_bw == Bandwidth::Wideband)
721        {
722            mode = OpusMode::SilkOnly;
723        }
724
725        // Stereo hybrid is now CONFORMANT (the CELT intensity-clamp fix), but
726        // our FIXED-point stereo SILK executes it worse than plain CELT-FB above
727        // ~28 kb/s: PEAQ on stereo speech (ODG) measured hybrid −2.196/−2.193 vs
728        // CELT-FB −2.136/−2.057 at 32k/48k (CELT-FB wins), while at 24k hybrid
729        // −2.198 beats CELT-FB −2.240. libopus's FLOAT stereo SILK hybrid beats
730        // both everywhere — the gap is fixed-vs-float, not a bug. So route
731        // stereo hybrid to CELT-FB except at the low rates where it wins. (Force
732        // via OPUS_SET_BANDWIDTH if the true hybrid path is wanted.) The clean
733        // fix is float stereo SILK — a large port, tracked in the roadmap.
734        if self.channels == 2 && mode == OpusMode::Hybrid && self.bitrate_bps > 28000 {
735            mode = OpusMode::CeltOnly;
736            self.bandwidth = Bandwidth::Fullband;
737        }
738
739        if mode == OpusMode::CeltOnly {
740            match frame_rate {
741                400 | 200 | 100 | 50 => {}
742                _ => return Err("Unsupported frame size for CELT-only mode"),
743            }
744        }
745
746        if mode == OpusMode::Hybrid {
747            match frame_rate {
748                100 | 50 => {}
749                _ => return Err("Unsupported frame size for Hybrid mode"),
750            }
751        }
752
753        if mode == OpusMode::SilkOnly {
754            match frame_rate {
755                400 | 200 | 100 | 50 | 25 => {}
756                _ => return Err("Unsupported frame size for SILK-only mode"),
757            }
758        }
759
760        let n400 = (self.sampling_rate / 400) as usize;
761
762        // ---- Mode-transition resets (opus_encoder.c:1449 + 2054) ----
763        // The decoder resets its CELT state on ANY mode change (when there is
764        // no redundancy) and its SILK state when leaving CELT-only; the
765        // encoder must mirror both or the streams desync from that frame on.
766        if let Some(prev) = self.prev_enc_mode {
767            if prev != mode {
768                if mode != OpusMode::SilkOnly {
769                    let ch = self.channels;
770                    self.celt_enc = CeltEncoder::new(modes::default_mode(), ch);
771                    // Prefill 2.5 ms so the fresh state has real preemph/overlap
772                    // history instead of a hard edge (opus_encoder.c:2060).
773                    let n400 = (self.sampling_rate / 400) as usize;
774                    if self.celt_prefill_tail.len() == n400 * ch {
775                        let mut dummy = RangeCoder::new_encoder(2);
776                        let tail = std::mem::take(&mut self.celt_prefill_tail);
777                        self.celt_enc.encode_with_budget(&tail, n400, &mut dummy, 0, 21, 16);
778                        self.celt_prefill_tail = tail;
779                    }
780                }
781                if mode != OpusMode::CeltOnly && prev == OpusMode::CeltOnly {
782                    self.silk_initialized = false;
783                    self.silk_prefill_pending = true;
784                }
785            }
786        }
787
788        // SILK prefill tail: last 10 ms of API-rate mono input.
789        if self.channels == 1 {
790            let n10 = (self.sampling_rate / 100) as usize;
791            if frame_size >= n10 {
792                self.silk_prefill_tail.resize(n10, 0);
793                for i in 0..n10 {
794                    self.silk_prefill_tail[i] = (input[frame_size - n10 + i] * 32768.0)
795                        .clamp(-32768.0, 32767.0) as i16;
796                }
797            }
798        }
799
800        // Save THIS frame's last 2.5 ms (planar) for a possible prefill at the
801        // next mode transition. (The transition block above consumed the
802        // PREVIOUS frame's tail.)
803        {
804            let ch = self.channels;
805            self.celt_prefill_tail.resize(n400 * ch, 0.0);
806            let base = frame_size - n400;
807            for c in 0..ch {
808                for i in 0..n400 {
809                    self.celt_prefill_tail[c * n400 + i] = input[(base + i) * ch + c];
810                }
811            }
812        }
813
814        let toc = gen_toc(mode, frame_rate, self.bandwidth, self.channels);
815        output[0] = toc;
816
817        // ---- DTX decision (opus_encoder.c:2137 decide_dtx_mode) ----
818        // After enough consecutive inactive frames, emit a TOC-only 1-byte
819        // packet: the decoder sees an empty payload and runs comfort-noise /
820        // PLC. We decide before the (skipped) SILK/CELT encode — SILK's own DTX
821        // likewise stops coding, so the encoder state simply doesn't advance;
822        // the codecs resync on the next active frame.
823        if self.use_dtx && (analysis_info.valid || is_silence) {
824            let frame_ms_q1 = 2 * 1000 * frame_size as i32 / self.sampling_rate;
825            let dtx = if !activity {
826                self.nb_no_activity_ms_q1 += frame_ms_q1;
827                const LO: i32 = silk::define::NB_SPEECH_FRAMES_BEFORE_DTX * 20 * 2; // 400
828                const HI: i32 = (silk::define::NB_SPEECH_FRAMES_BEFORE_DTX + silk::define::MAX_CONSECUTIVE_DTX) * 20 * 2; // 1200
829                if self.nb_no_activity_ms_q1 > LO {
830                    if self.nb_no_activity_ms_q1 <= HI {
831                        true
832                    } else {
833                        self.nb_no_activity_ms_q1 = LO;
834                        false
835                    }
836                } else {
837                    false
838                }
839            } else {
840                self.nb_no_activity_ms_q1 = 0;
841                false
842            };
843            if dtx {
844                self.prev_enc_mode = Some(mode);
845                self.range_final = 0;
846                return Ok(1);
847            }
848        } else {
849            self.nb_no_activity_ms_q1 = 0;
850        }
851
852        let target_bits =
853            (self.bitrate_bps as i64 * frame_size as i64 / self.sampling_rate as i64) as i32;
854        let cbr_bytes = ((target_bits + 4) / 8) as usize;
855        let max_data_bytes = output.len();
856
857        // CBR: the packet is exactly the target size. VBR: start the coder on a
858        // generous buffer — SILK-only packets end at whatever SILK produced, and
859        // the CELT layer picks its own frame size (compute_vbr) and shrinks the
860        // coder to it (libopus opus_encoder.c / celt_encoder.c VBR flow).
861        let n_bytes = if self.use_cbr {
862            cbr_bytes.min(max_data_bytes).max(1)
863        } else {
864            max_data_bytes.min(1276).max(cbr_bytes.min(max_data_bytes)).max(3)
865        };
866
867        let init_rc_size = n_bytes - 1;
868        self.rc.reset_for_encode(init_rc_size as u32);
869
870        if mode == OpusMode::SilkOnly || mode == OpusMode::Hybrid {
871            let silk_fs_khz = if mode == OpusMode::Hybrid {
872                16
873            } else {
874                self.sampling_rate.min(16000) / 1000
875            };
876
877            let frame_ms = (frame_size as i32 * 1000) / self.sampling_rate;
878            if !self.silk_initialized || self.silk_enc.s_cmn.fs_khz != silk_fs_khz {
879                let silk_init_bitrate = if self.use_cbr {
880                    (((n_bytes - 1) * 8) as i64 * self.sampling_rate as i64 / frame_size as i64)
881                        as i32
882                } else {
883                    self.bitrate_bps
884                };
885                silk_control_encoder(
886                    &mut self.silk_enc,
887                    silk_fs_khz,
888                    frame_ms,
889                    silk_init_bitrate,
890                    self.complexity,
891                );
892                self.silk_enc.s_cmn.use_cbr = if self.use_cbr { 1 } else { 0 };
893
894                self.silk_enc.s_cmn.n_channels = self.channels as i32;
895                self.silk_initialized = true;
896                self.down2_state_first = [0; 2];
897                self.down2_state_second = [0; 2];
898                self.down2_3_state = [0; 6];
899                self.down_1_3_state = silk::resampler::SilkResamplerDown1_3::default();
900                self.down2_3_state_r = [0; 6];
901                self.down_1_3_state_r = silk::resampler::SilkResamplerDown1_3::default();
902                self.down_fir_l =
903                    silk::resampler::SilkDownFirResampler::new(self.sampling_rate, 16000);
904                self.down_fir_r =
905                    silk::resampler::SilkDownFirResampler::new(self.sampling_rate, 16000);
906            }
907
908            // SILK prefill after CELT-only (opus_encoder.c prefill=1): run 10 ms
909            // of the previous audio through the fresh resampler + SILK warmup
910            // path so the first coded SILK frame has real LTP/shape history.
911            if self.silk_prefill_pending {
912                self.silk_prefill_pending = false;
913                let n10 = (self.sampling_rate / 100) as usize;
914                if self.channels == 1 && self.silk_prefill_tail.len() == n10 {
915                    let need = silk_fs_khz as usize * 10;
916                    let mut resampled = vec![0i16; need];
917                    if self.sampling_rate > 16000 {
918                        if let Some(r) = &mut self.down_fir_l {
919                            r.process(&mut resampled, &self.silk_prefill_tail);
920                        }
921                    } else {
922                        resampled.copy_from_slice(&self.silk_prefill_tail[..need]);
923                    }
924                    silk::enc_api::silk_encode_prefill(&mut self.silk_enc, &resampled, 0);
925                }
926            }
927
928            self.silk_enc.s_cmn.use_in_band_fec = if self.use_inband_fec { 1 } else { 0 };
929            self.silk_enc.s_cmn.packet_loss_perc = self.packet_loss_perc.clamp(0, 100);
930
931            self.silk_enc.s_cmn.lbrr_enabled = if self.use_inband_fec { 1 } else { 0 };
932
933            if self.silk_enc.s_cmn.lbrr_gain_increases == 0 {
934                self.silk_enc.s_cmn.lbrr_gain_increases = 2;
935            }
936
937            let hp_freq_smth1 = if mode == OpusMode::CeltOnly {
938                silk_lin2log(60) << 8
939            } else {
940                self.silk_enc.s_cmn.variable_hp_smth1_q15
941            };
942
943            const VARIABLE_HP_SMTH_COEF2_Q16: i32 = 984;
944            self.variable_hp_smth2_q15 = silk_smlawb(
945                self.variable_hp_smth2_q15,
946                hp_freq_smth1 - self.variable_hp_smth2_q15,
947                VARIABLE_HP_SMTH_COEF2_Q16,
948            );
949
950            let cutoff_hz = silk_log2lin(silk_rshift(self.variable_hp_smth2_q15, 8));
951
952            let _prof_rs = crate::prof::scope(crate::prof::Stage::Resample);
953            let required_size = frame_size * self.channels;
954            self.buf_filtered.resize(required_size, 0);
955            if self.application == Application::Voip {
956                hp_cutoff(
957                    input,
958                    cutoff_hz,
959                    &mut self.buf_filtered,
960                    &mut self.hp_mem,
961                    frame_size,
962                    self.channels,
963                    self.sampling_rate,
964                );
965            } else {
966                for (i, &x) in input.iter().enumerate() {
967                    self.buf_filtered[i] = (x * 32768.0).clamp(-32768.0, 32767.0) as i16;
968                }
969            }
970
971            let input_i16 = &self.buf_filtered;
972
973            let silk_input: &[i16] = if self.channels == 2 {
974                // Stereo SILK/hybrid: deinterleave, resample EACH channel to the
975                // SILK-internal rate (separate filter states), then split
976                // mid/side — C's order (per-channel resampling inside
977                // silk_Encode, then silk_stereo_LR_to_MS). The old code only
978                // handled stereo at <=16 kHz and fed resampled INTERLEAVED
979                // audio to a stereo-configured SILK above that (never
980                // exercised until the analysis started picking stereo hybrid).
981                let frame_length = input_i16.len() / 2;
982                self.buf_left.resize(frame_length, 0);
983                self.buf_right.resize(frame_length, 0);
984                for i in 0..frame_length {
985                    self.buf_left[i] = input_i16[2 * i];
986                    self.buf_right[i] = input_i16[2 * i + 1];
987                }
988                let need_resample = self.sampling_rate > 16000;
989                let ds_len = if !need_resample {
990                    frame_length
991                } else if self.sampling_rate == 48000 {
992                    frame_length / 3
993                } else {
994                    frame_length * 2 / 3
995                };
996                if need_resample {
997                    self.buf_stereo_mid.resize(ds_len, 0);
998                    self.buf_stereo_side.resize(ds_len, 0);
999                    if let (Some(rl), Some(rr)) = (&mut self.down_fir_l, &mut self.down_fir_r) {
1000                        rl.process(&mut self.buf_stereo_mid, &self.buf_left);
1001                        rr.process(&mut self.buf_stereo_side, &self.buf_right);
1002                    }
1003                    self.buf_left.resize(ds_len, 0);
1004                    self.buf_right.resize(ds_len, 0);
1005                    self.buf_left.copy_from_slice(&self.buf_stereo_mid[..ds_len]);
1006                    self.buf_right.copy_from_slice(&self.buf_stereo_side[..ds_len]);
1007                }
1008                self.buf_stereo_mid.resize(ds_len, 0);
1009                self.buf_stereo_side.resize(ds_len, 0);
1010                for i in 0..ds_len {
1011                    let l = self.buf_left[i] as i32;
1012                    let r = self.buf_right[i] as i32;
1013                    self.buf_stereo_mid[i] = ((l + r) / 2) as i16;
1014                    self.buf_stereo_side[i] = (l - r) as i16;
1015                }
1016                self.silk_enc.stereo.side.resize(ds_len, 0);
1017                self.silk_enc
1018                    .stereo
1019                    .side
1020                    .copy_from_slice(&self.buf_stereo_side[..ds_len]);
1021                &self.buf_stereo_mid
1022            } else if mode == OpusMode::SilkOnly && self.sampling_rate > 16000 {
1023                if self.sampling_rate == 48000 {
1024                    // 48k -> 16k via the same direct FIR the Hybrid path uses. The
1025                    // old down2 + down2_3 two-stage chain ALIASES: a 1 kHz sine
1026                    // came out with a 7 kHz mirror at ~1/3 amplitude (spectrum-
1027                    // verified), wrecking every SILK-only encode from 48 kHz input.
1028                    let silk_frame_size = frame_size / 3;
1029                    self.buf_silk_input.resize(silk_frame_size, 0);
1030                    if let Some(r) = &mut self.down_fir_l {
1031                        r.process(&mut self.buf_silk_input, input_i16);
1032                    }
1033                    &self.buf_silk_input
1034                } else if self.sampling_rate == 24000 {
1035                    let silk_frame_size = frame_size * 2 / 3;
1036                    self.buf_silk_input.resize(silk_frame_size, 0);
1037                    if let Some(r) = &mut self.down_fir_l {
1038                        r.process(&mut self.buf_silk_input, input_i16);
1039                    }
1040                    &self.buf_silk_input
1041                } else {
1042                    input_i16
1043                }
1044            } else if mode == OpusMode::Hybrid && self.sampling_rate > 16000 {
1045                let silk_frame_size = if self.sampling_rate == 48000 {
1046                    frame_size / 3
1047                } else {
1048                    frame_size * 2 / 3
1049                };
1050                self.buf_silk_input.resize(silk_frame_size, 0);
1051                if let Some(r) = &mut self.down_fir_l {
1052                    r.process(&mut self.buf_silk_input, input_i16);
1053                }
1054                &self.buf_silk_input
1055            } else {
1056                input_i16
1057            };
1058
1059            drop(_prof_rs);
1060
1061            let mut pn_bytes = 0;
1062
1063            // The frames-per-second math below divides by silk_input.len(), which is
1064            // at the SILK-INTERNAL rate — so the rate here must be internal too.
1065            // Using the API rate at 48 kHz told SILK to target 3x the real budget
1066            // with a hard max_bits cap -> the gain loop crushed every frame to fit
1067            // -> near-silent output (only worked at 16 kHz API where they coincide).
1068            let silk_rate_for_calc = if mode == OpusMode::Hybrid {
1069                16000
1070            } else {
1071                self.sampling_rate.min(16000)
1072            };
1073            let silk_frame_len = silk_input.len();
1074
1075            let silk_bitrate = if mode == OpusMode::Hybrid {
1076                let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
1077                let frame20ms = frame_duration_ms >= 20;
1078                compute_silk_rate_for_hybrid(self.bitrate_bps, curr_bw, frame20ms, !self.use_cbr)
1079            } else if self.use_cbr {
1080                (8i64 * (n_bytes - 1) as i64 * silk_rate_for_calc as i64 / silk_frame_len as i64)
1081                    as i32
1082            } else {
1083                // VBR: n_bytes is only the buffer cap; target the configured rate.
1084                self.bitrate_bps
1085            };
1086            let silk_max_bits = if mode == OpusMode::Hybrid {
1087                let total_max_bits = ((n_bytes - 1) * 8) as i32;
1088                if self.use_cbr {
1089                    let silk_bits = (silk_bitrate as i64 * silk_frame_len as i64
1090                        / silk_rate_for_calc as i64) as i32;
1091                    let other_bits = 0i32.max(total_max_bits - silk_bits);
1092                    0i32.max(total_max_bits - other_bits * 3 / 4)
1093                } else {
1094                    let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
1095                    let frame20ms = frame_duration_ms >= 20;
1096                    let max_bit_rate = compute_silk_rate_for_hybrid(
1097                        total_max_bits * self.sampling_rate / frame_size as i32,
1098                        curr_bw,
1099                        frame20ms,
1100                        !self.use_cbr,
1101                    );
1102                    max_bit_rate * frame_size as i32 / self.sampling_rate
1103                }
1104            } else {
1105                ((n_bytes - 1) * 8) as i32
1106            };
1107            let silk_use_cbr = if mode == OpusMode::Hybrid && self.use_cbr {
1108                0
1109            } else if self.use_cbr {
1110                1
1111            } else {
1112                0
1113            };
1114            let ret = silk_encode(
1115                &mut self.silk_enc,
1116                silk_input,
1117                silk_input.len(),
1118                &mut self.rc,
1119                &mut pn_bytes,
1120                silk_bitrate,
1121                silk_max_bits,
1122                silk_use_cbr,
1123                1,
1124            );
1125            if ret != 0 {
1126                return Err("SILK encoding failed");
1127            }
1128        }
1129
1130        // The hybrid redundancy flag is only present when >=37 bits remain
1131        // (opus_encoder.c: ec_tell+17+20 <= 8*(max_data_bytes-1)); the decoder
1132        // gates its read identically. Writing it unconditionally desynced every
1133        // frame where SILK left fewer than 37 bits (starved low-rate hybrid).
1134        if mode == OpusMode::Hybrid && self.rc.tell() + 37 <= ((n_bytes - 1) * 8) as i32 {
1135            self.rc.encode_bit_logp(false, 12); // redundancy = 0
1136        }
1137
1138        if mode == OpusMode::Hybrid {
1139            let nb_compr_bytes = (n_bytes - 1) as u32;
1140            self.rc.shrink(nb_compr_bytes);
1141        }
1142
1143        let silk_ret_bytes = if mode == OpusMode::SilkOnly {
1144            ((self.rc.tell() + 7) >> 3) as usize
1145        } else {
1146            0
1147        };
1148
1149        if mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid {
1150            self.celt_enc.analysis = celt::AnalysisInfo {
1151                valid: analysis_info.valid,
1152                tonality: analysis_info.tonality,
1153                tonality_slope: analysis_info.tonality_slope,
1154                noisiness: analysis_info.noisiness,
1155                activity: analysis_info.activity,
1156                music_prob: analysis_info.music_prob,
1157                music_prob_min: analysis_info.music_prob_min,
1158                music_prob_max: analysis_info.music_prob_max,
1159                bandwidth: analysis_info.bandwidth,
1160                activity_probability: analysis_info.activity_probability,
1161                max_pitch_ratio: analysis_info.max_pitch_ratio,
1162                leak_boost: analysis_info.leak_boost,
1163            };
1164            self.celt_enc.complexity = self.complexity;
1165            self.celt_enc.lsb_depth = self.lsb_depth;
1166            let start_band = if mode == OpusMode::Hybrid { 17 } else { 0 };
1167            // CELT end band from the coded bandwidth (mirrors the decoder's
1168            // celt_endband_for_bandwidth): NB->13, MB/WB->17, SWB->19, FB->21.
1169            let end_band = match self.bandwidth {
1170                Bandwidth::Narrowband => 13,
1171                Bandwidth::Mediumband | Bandwidth::Wideband => 17,
1172                Bandwidth::Superwideband => 19,
1173                _ => 21,
1174            };
1175            let total_packet_bits = ((n_bytes - 1) * 8) as i32;
1176            // VBR: hand CELT the target in eighth-bits per frame; it picks the
1177            // frame's size (compute_vbr) and shrinks the range coder to it. The
1178            // hybrid target covers the whole packet (CELT adds back the SILK
1179            // bits via `target += tell`).
1180            self.celt_enc.vbr_rate = if self.use_cbr {
1181                0
1182            } else {
1183                let den = self.sampling_rate >> 3; // Fs >> BITRES
1184                ((self.bitrate_bps as i64 * frame_size as i64 + (den >> 1) as i64)
1185                    / den as i64) as i32
1186            };
1187
1188            let celt_input: &[f32] = if self.channels == 1 {
1189                input
1190            } else {
1191                let n = frame_size * self.channels;
1192                self.buf_celt_input.resize(n, 0.0);
1193                for i in 0..frame_size {
1194                    for ch in 0..self.channels {
1195                        self.buf_celt_input[ch * frame_size + i] = input[i * self.channels + ch];
1196                    }
1197                }
1198                &self.buf_celt_input
1199            };
1200
1201            if self.rc.tell() <= total_packet_bits {
1202                self.celt_enc.encode_with_budget(
1203                    celt_input,
1204                    frame_size,
1205                    &mut self.rc,
1206                    start_band,
1207                    end_band,
1208                    total_packet_bits,
1209                );
1210            }
1211        }
1212
1213        self.rc.done();
1214        self.range_final = self.rc.rng;
1215
1216        if mode == OpusMode::SilkOnly {
1217            let mut ret = silk_ret_bytes.min(self.rc.storage as usize);
1218            while ret > 2 && self.rc.buf[ret - 1] == 0 {
1219                ret -= 1;
1220            }
1221
1222            let target_total = if self.use_cbr {
1223                n_bytes.min(output.len())
1224            } else {
1225                (ret + 1).min(output.len())
1226            };
1227
1228            let silk_len = ret;
1229
1230            if !self.use_cbr || silk_len + 1 >= target_total {
1231                // VBR or payload fills the target: simple code 0 packet
1232                output[0] = toc;
1233                let copy_len = silk_len.min(target_total - 1);
1234                output[1..1 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
1235                return Ok((copy_len + 1).min(output.len()));
1236            }
1237
1238            output[0] = toc | 0x03;
1239
1240            if silk_len + 2 >= target_total {
1241                output[1] = 0x01;
1242                let copy_len = (target_total - 2).min(silk_len);
1243                output[2..2 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
1244                self.prev_enc_mode = Some(mode);
1245                return Ok(target_total.min(output.len()));
1246            }
1247
1248            let pad_amount = target_total - silk_len - 2;
1249            output[1] = 0x41;
1250
1251            let nb_255s = (pad_amount - 1) / 255;
1252            let mut ptr = 2;
1253            for _ in 0..nb_255s {
1254                output[ptr] = 255;
1255                ptr += 1;
1256            }
1257            output[ptr] = (pad_amount - 255 * nb_255s - 1) as u8;
1258            ptr += 1;
1259
1260            output[ptr..ptr + silk_len].copy_from_slice(&self.rc.buf[..silk_len]);
1261            ptr += silk_len;
1262
1263            let fill_end = target_total.min(output.len());
1264            for byte in output[ptr..fill_end].iter_mut() {
1265                *byte = 0;
1266            }
1267
1268            self.prev_enc_mode = Some(mode);
1269            return Ok(target_total.min(output.len()));
1270        }
1271
1272        // CBR: fixed payload. VBR (CELT/hybrid): the CELT layer shrank the coder
1273        // to this frame's chosen size — emit exactly that many payload bytes.
1274        let payload_len = if self.use_cbr {
1275            n_bytes - 1
1276        } else {
1277            (self.rc.storage as usize).min(n_bytes - 1)
1278        };
1279        output[1..1 + payload_len].copy_from_slice(&self.rc.buf[..payload_len]);
1280        self.prev_enc_mode = Some(mode);
1281        Ok(1 + payload_len)
1282    }
1283}
1284
1285pub struct OpusDecoder {
1286    celt_dec: CeltDecoder,
1287    silk_dec: silk::dec_api::SilkDecoder,
1288    sampling_rate: i32,
1289    channels: usize,
1290
1291    prev_mode: Option<OpusMode>,
1292    frame_size: usize,
1293
1294    bandwidth: Bandwidth,
1295
1296    stream_channels: usize,
1297
1298    silk_resampler: silk::resampler::SilkResampler,
1299    // Second resampler for the SILK stereo right channel (L uses silk_resampler).
1300    silk_resampler_r: silk::resampler::SilkResampler,
1301
1302    prev_internal_rate: i32,
1303
1304    pub hybrid_skip_celt: bool,
1305
1306    w_pcm_i16: Vec<i16>,
1307    w_silk_out: Vec<f32>,
1308    w_pcm_resampled: Vec<i16>,
1309    w_celt_planar: Vec<f32>,
1310    w_celt_out: Vec<f32>,
1311
1312    // SILK per-frame history: libopus prepends the previous frame's last two
1313    // decoded samples (`sStereo.sMid`) and feeds the resampler from offset 1, a
1314    // 1-internal-sample delay line. Replicated here so our SILK output aligns
1315    // with the reference across every bandwidth (was leading by 1 internal
1316    // sample = 3/4/6 output samples at WB/MB/NB).
1317    silk_s_mid: [i16; 2],
1318
1319    // Range decoder final `rng` from the last decoded frame (conformance/desync
1320    // diagnostic: compare against the encoder's stored final range).
1321    pub last_range: u32,
1322
1323    // Auxiliary decoder for packets whose channel count differs from ours
1324    // (a stream may switch between mono and stereo). It decodes at the packet's
1325    // native channel count; we then up/downmix to our output count. Persistent
1326    // so the "other" channel mode keeps its own inter-frame state.
1327    aux: Option<Box<OpusDecoder>>,
1328    // Set when a packet was just decoded by the aux (a mono packet in a stereo
1329    // stream); triggers seeding the primary CELT decoder's overlap/energy state
1330    // from the aux at the next primary (stereo) CELT/Hybrid packet, so the MDCT
1331    // overlap-add is continuous across the mono->stereo switch.
1332    prev_used_aux: bool,
1333    // libopus st->prev_redundancy: the previous frame carried a SILK->CELT
1334    // redundant frame (redundancy && !celt_to_silk). Suppresses the CELT reset on
1335    // the following mode change (the redundant frame already primed CELT state).
1336    prev_redundancy: bool,
1337}
1338
1339impl OpusDecoder {
1340    pub fn new(sampling_rate: i32, channels: usize) -> Result<Self, &'static str> {
1341        if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
1342            return Err("Invalid sampling rate");
1343        }
1344        if ![1, 2].contains(&channels) {
1345            return Err("Invalid number of channels");
1346        }
1347
1348        let mode = modes::default_mode();
1349        let celt_dec = CeltDecoder::new(mode, channels);
1350
1351        let mut silk_dec = silk::dec_api::SilkDecoder::new();
1352        silk_dec.init(sampling_rate.min(16000), channels as i32);
1353        silk_dec.channel_state[0].fs_api_hz = sampling_rate;
1354
1355        Ok(Self {
1356            celt_dec,
1357            silk_dec,
1358            sampling_rate,
1359            channels,
1360            prev_mode: None,
1361            frame_size: 0,
1362            bandwidth: Bandwidth::Auto,
1363            stream_channels: channels,
1364            silk_resampler: silk::resampler::SilkResampler::default(),
1365            silk_resampler_r: silk::resampler::SilkResampler::default(),
1366            prev_internal_rate: 0,
1367            hybrid_skip_celt: false,
1368
1369            // SILK internal scratch: max frame is 60 ms at the 16 kHz WB internal
1370            // rate (960 samples/ch), i.e. 1920 stereo. Sized like the sibling
1371            // buffers below for headroom — the old fixed 640 overflowed on any
1372            // 60 ms SILK frame (panic decoding valid streams).
1373            w_pcm_i16: vec![0i16; 5760 * channels],
1374
1375            w_silk_out: vec![0.0f32; 5760 * channels],
1376            w_pcm_resampled: vec![0i16; 5760 * channels],
1377            w_celt_planar: vec![0.0f32; 5760 * channels],
1378            w_celt_out: vec![0.0f32; 5760 * channels],
1379            silk_s_mid: [0; 2],
1380            last_range: 0,
1381            aux: None,
1382            prev_used_aux: false,
1383            prev_redundancy: false,
1384        })
1385    }
1386
1387    /// Packet-loss concealment for a lost frame (empty/None packet). Runs the
1388    /// SILK PLC (LTP+LPC extrapolation) for the last-known SILK/hybrid mode and
1389    /// resamples to the output rate. CELT-only loss has no CELT PLC yet, so it
1390    /// yields silence (a documented Tier-1 follow-up); the SILK path covers the
1391    /// dominant VoIP case. Mono conceal is duplicated to both channels on a
1392    /// stereo output.
1393    fn decode_plc(
1394        &mut self,
1395        frame_size: usize,
1396        output: &mut [f32],
1397    ) -> Result<usize, &'static str> {
1398        let out_samples = frame_size * self.channels;
1399        for v in output.iter_mut().take(out_samples) {
1400            *v = 0.0;
1401        }
1402        let mode = self.prev_mode.unwrap_or(OpusMode::SilkOnly);
1403        if mode == OpusMode::CeltOnly {
1404            // CELT packet-loss concealment (noise-based celt_decode_lost): real
1405            // attenuating audio instead of silence.
1406            self.celt_dec.conceal_lost(frame_size, output);
1407            self.prev_mode = Some(mode);
1408            return Ok(frame_size);
1409        }
1410
1411        let frame_ms = (frame_size as i32 * 1000 / self.sampling_rate).max(1);
1412        let internal_rate = if mode == OpusMode::Hybrid {
1413            16000
1414        } else {
1415            match self.bandwidth {
1416                Bandwidth::Narrowband => 8000,
1417                Bandwidth::Mediumband => 12000,
1418                _ => 16000,
1419            }
1420        };
1421        if self.sampling_rate != internal_rate && internal_rate != self.prev_internal_rate {
1422            self.silk_resampler.init(internal_rate, self.sampling_rate);
1423            self.prev_internal_rate = internal_rate;
1424        }
1425        let n_silk = match frame_ms {
1426            40 => 2,
1427            60 => 3,
1428            _ => 1,
1429        };
1430        let internal_frame = (frame_ms * internal_rate / 1000) as usize;
1431        let internal_sub = internal_frame / n_silk.max(1);
1432        let ratio = self.sampling_rate as f64 / internal_rate as f64;
1433        // Conceal mono only (the SILK low band); stereo output duplicates it.
1434        self.silk_dec.produce_lr = false;
1435        self.silk_dec.n_channels_internal = 1;
1436
1437        let mut off = 0usize; // output samples/ch written so far
1438        for sf in 0..n_silk {
1439            let mut rc = RangeCoder::new_decoder(&[]);
1440            let n16 = internal_sub;
1441            if n16 + 2 > self.w_pcm_i16.len() {
1442                return Err("opus PLC: frame exceeds buffer");
1443            }
1444            self.w_pcm_i16[0] = self.silk_s_mid[0];
1445            self.w_pcm_i16[1] = self.silk_s_mid[1];
1446            let ret = self.silk_dec.decode(
1447                &mut rc,
1448                &mut self.w_pcm_i16[2..n16 + 2],
1449                silk::decode_frame::FLAG_PACKET_LOST,
1450                sf == 0,
1451                frame_ms,
1452                internal_rate,
1453            );
1454            if ret < 0 {
1455                return Err("SILK PLC failed");
1456            }
1457            let dec = ret as usize;
1458            if dec >= 2 {
1459                self.silk_s_mid[0] = self.w_pcm_i16[dec];
1460                self.silk_s_mid[1] = self.w_pcm_i16[dec + 1];
1461            }
1462            let base = off * self.channels;
1463            let out_len = if self.sampling_rate == internal_rate {
1464                for i in 0..dec {
1465                    let v = self.w_pcm_i16[1 + i] as f32 / 32768.0;
1466                    for ch in 0..self.channels {
1467                        let idx = base + i * self.channels + ch;
1468                        if idx < output.len() {
1469                            output[idx] = v;
1470                        }
1471                    }
1472                }
1473                dec
1474            } else {
1475                let out_len = (dec as f64 * ratio) as usize;
1476                let src: Vec<i16> = self.w_pcm_i16[1..1 + dec].to_vec();
1477                self.silk_resampler
1478                    .process(&mut self.w_pcm_resampled[..out_len], &src, dec as i32);
1479                for i in 0..out_len {
1480                    let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1481                    for ch in 0..self.channels {
1482                        let idx = base + i * self.channels + ch;
1483                        if idx < output.len() {
1484                            output[idx] = v;
1485                        }
1486                    }
1487                }
1488                out_len
1489            };
1490            off += out_len;
1491        }
1492        self.prev_mode = Some(mode);
1493        Ok(frame_size)
1494    }
1495
1496    /// Forward-error-correction decode: reconstruct a LOST frame from the LBRR
1497    /// (low-bitrate redundancy) embedded in the NEXT received `packet`. Drives
1498    /// the SILK decoder in FLAG_DECODE_LBRR mode, which self-selects: it decodes
1499    /// the redundant frame when the packet carries LBRR for it, and falls back
1500    /// to PLC extrapolation when it doesn't. CELT-only or multi-frame packets
1501    /// fall back to plain PLC (no SILK LBRR to recover). After this call the
1502    /// caller decodes `packet` normally for the following frame.
1503    pub fn decode_fec(
1504        &mut self,
1505        packet: &[u8],
1506        frame_size: usize,
1507        output: &mut [f32],
1508    ) -> Result<usize, &'static str> {
1509        if packet.is_empty() {
1510            return self.decode_plc(frame_size, output);
1511        }
1512        let toc = packet[0];
1513        let mode = mode_from_toc(toc);
1514        // FEC only lives in SILK/hybrid low band; code-0 (single frame) only.
1515        if mode == OpusMode::CeltOnly || (toc & 0x03) != 0 {
1516            return self.decode_plc(frame_size, output);
1517        }
1518        let bandwidth = bandwidth_from_toc(toc);
1519        let payload = &packet[1..];
1520
1521        let out_samples = frame_size * self.channels;
1522        for v in output.iter_mut().take(out_samples) {
1523            *v = 0.0;
1524        }
1525        let frame_ms = (frame_size as i32 * 1000 / self.sampling_rate).max(1);
1526        let internal_rate = if mode == OpusMode::Hybrid {
1527            16000
1528        } else {
1529            match bandwidth {
1530                Bandwidth::Narrowband => 8000,
1531                Bandwidth::Mediumband => 12000,
1532                _ => 16000,
1533            }
1534        };
1535        if self.sampling_rate != internal_rate && internal_rate != self.prev_internal_rate {
1536            self.silk_resampler.init(internal_rate, self.sampling_rate);
1537            self.prev_internal_rate = internal_rate;
1538        }
1539        let internal_frame = (frame_ms * internal_rate / 1000) as usize;
1540        let ratio = self.sampling_rate as f64 / internal_rate as f64;
1541        self.silk_dec.produce_lr = false;
1542        self.silk_dec.n_channels_internal = 1;
1543
1544        let mut rc = RangeCoder::new_decoder(payload);
1545        let n16 = internal_frame;
1546        if n16 + 2 > self.w_pcm_i16.len() {
1547            return Err("opus FEC: frame exceeds buffer");
1548        }
1549        self.w_pcm_i16[0] = self.silk_s_mid[0];
1550        self.w_pcm_i16[1] = self.silk_s_mid[1];
1551        let ret = self.silk_dec.decode(
1552            &mut rc,
1553            &mut self.w_pcm_i16[2..n16 + 2],
1554            silk::decode_frame::FLAG_DECODE_LBRR,
1555            true,
1556            frame_ms,
1557            internal_rate,
1558        );
1559        if ret < 0 {
1560            return Err("SILK FEC failed");
1561        }
1562        let dec = ret as usize;
1563        if dec >= 2 {
1564            self.silk_s_mid[0] = self.w_pcm_i16[dec];
1565            self.silk_s_mid[1] = self.w_pcm_i16[dec + 1];
1566        }
1567        if self.sampling_rate == internal_rate {
1568            for i in 0..dec {
1569                let v = self.w_pcm_i16[1 + i] as f32 / 32768.0;
1570                for ch in 0..self.channels {
1571                    let idx = i * self.channels + ch;
1572                    if idx < output.len() {
1573                        output[idx] = v;
1574                    }
1575                }
1576            }
1577        } else {
1578            let out_len = (dec as f64 * ratio) as usize;
1579            let src: Vec<i16> = self.w_pcm_i16[1..1 + dec].to_vec();
1580            self.silk_resampler
1581                .process(&mut self.w_pcm_resampled[..out_len], &src, dec as i32);
1582            for i in 0..out_len {
1583                let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1584                for ch in 0..self.channels {
1585                    let idx = i * self.channels + ch;
1586                    if idx < output.len() {
1587                        output[idx] = v;
1588                    }
1589                }
1590            }
1591        }
1592        self.prev_mode = Some(mode);
1593        Ok(frame_size)
1594    }
1595
1596    pub fn decode(
1597        &mut self,
1598        input: &[u8],
1599        frame_size: usize,
1600        output: &mut [f32],
1601    ) -> Result<usize, &'static str> {
1602        // Lost packet (data==NULL / empty) -> packet-loss concealment.
1603        if input.is_empty() {
1604            return self.decode_plc(frame_size, output);
1605        }
1606
1607        let toc = input[0];
1608        let mode = mode_from_toc(toc);
1609        let packet_channels = channels_from_toc(toc);
1610        let bandwidth = bandwidth_from_toc(toc);
1611        let frame_duration_ms = frame_duration_ms_from_toc(toc);
1612
1613        // A mono SILK packet inside a stereo stream is decoded through the PRIMARY
1614        // decoder (unified path), not a separate aux — the aux's SILK/resampler
1615        // state is blind to the interleaved stereo packets, so its state is stale
1616        // at every mono<->stereo switch. libopus keeps ONE decoder whose channel-0
1617        // resampler and stereo state run continuously across the switches.
1618        // A mono packet of ANY mode in a stereo stream decodes through the PRIMARY
1619        // (unified path) so inter-frame state stays one continuous chain across
1620        // mono<->stereo switches — SILK resampler/stereo state; CELT (and the
1621        // redundant/silence transition frames) via stream_channels=1 (C=1/CC=2) —
1622        // matching libopus's single decoder.
1623        let mono_in_stereo = packet_channels == 1 && self.channels == 2;
1624
1625        if packet_channels != self.channels && !mono_in_stereo {
1626            // The packet's channel count differs from ours (a stream can switch
1627            // between mono and stereo). Decode it at its native channel count in
1628            // a persistent auxiliary decoder, then render to our output count:
1629            // mono->stereo duplicates, stereo->mono averages the two channels.
1630            if self
1631                .aux
1632                .as_ref()
1633                .map(|a| a.channels != packet_channels)
1634                .unwrap_or(true)
1635            {
1636                self.aux = Some(Box::new(OpusDecoder::new(
1637                    self.sampling_rate,
1638                    packet_channels,
1639                )?));
1640            }
1641            // Reverse of the mono->stereo seed: on a stereo->mono switch, seed the
1642            // aux (mono) CELT decoder from the primary (stereo channel 0) so its
1643            // MDCT-overlap/energy state is continuous with the preceding stereo
1644            // packets (the primary was the continuous decoder during them).
1645            if !self.prev_used_aux
1646                && packet_channels == 1
1647                && self.channels == 2
1648                && (mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid)
1649            {
1650                let (aux_opt, primary) = (&mut self.aux, &self.celt_dec);
1651                if let Some(aux) = aux_opt.as_mut() {
1652                    aux.celt_dec.seed_from(primary);
1653                }
1654            }
1655            let aux = self.aux.as_mut().unwrap();
1656            let mut buf = vec![0.0f32; frame_size * packet_channels];
1657            let n = aux.decode(input, frame_size, &mut buf)?;
1658            self.last_range = aux.last_range;
1659            if packet_channels == 1 && self.channels == 2 {
1660                for i in 0..n {
1661                    let v = buf[i];
1662                    output[2 * i] = v;
1663                    output[2 * i + 1] = v;
1664                }
1665            } else if packet_channels == 2 && self.channels == 1 {
1666                for i in 0..n {
1667                    output[i] = 0.5 * (buf[2 * i] + buf[2 * i + 1]);
1668                }
1669            } else {
1670                let m = (n * self.channels).min(output.len()).min(buf.len());
1671                output[..m].copy_from_slice(&buf[..m]);
1672            }
1673            self.prev_mode = Some(mode);
1674            self.prev_used_aux = true;
1675            return Ok(n);
1676        }
1677
1678        // First primary (native-channel) packet after a run of aux (mono-in-stereo)
1679        // packets: seed the primary CELT decoder's inter-frame state from the aux
1680        // so the mono->stereo MDCT overlap-add is continuous (matches libopus's
1681        // single continuous decoder). SILK carries its own state through the
1682        // primary already; this is for the CELT/Hybrid high band.
1683        if self.prev_used_aux {
1684            self.prev_used_aux = false;
1685            if (mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid) && self.channels == 2 {
1686                if let Some(aux) = self.aux.as_ref() {
1687                    self.celt_dec.seed_from(&aux.celt_dec);
1688                }
1689            }
1690        }
1691
1692        let code = toc & 0x03;
1693        let frame_count: usize;
1694        let frame_payloads: Vec<&[u8]>;
1695
1696        match code {
1697            0 => {
1698                frame_count = 1;
1699                frame_payloads = vec![&input[1..]];
1700            }
1701            1 => {
1702                frame_count = 2;
1703                let half = (input.len() - 1) / 2;
1704                if half == 0 {
1705                    return Err("Code 1: empty frame");
1706                }
1707                frame_payloads = vec![&input[1..1 + half], &input[1 + half..]];
1708            }
1709            2 => {
1710                frame_count = 2;
1711                let data = &input[1..];
1712                if data.is_empty() {
1713                    return Err("Code 2 packet has no data");
1714                }
1715                let (first_len, header_size) = read_opus_frame_len(data, 0)?;
1716                if header_size + first_len > data.len() {
1717                    return Err("Code 2: first frame size exceeds packet");
1718                }
1719                frame_payloads = vec![
1720                    &data[header_size..header_size + first_len],
1721                    &data[header_size + first_len..],
1722                ];
1723            }
1724            3 => {
1725                // RFC 6716 §3.2.5. Frame-count byte: bit 7 = VBR flag, bit 6 =
1726                // padding flag, bits 5..0 = frame count M. VBR and padding are
1727                // independent; the earlier code conflated them (and used a
1728                // non-standard length coding), which mis-parsed CBR and padded
1729                // packets — exactly what the RFC test vectors exercise.
1730                if input.len() < 2 {
1731                    return Err("Code 3 packet too short");
1732                }
1733                let count_byte = input[1];
1734                let m = (count_byte & 0x3F) as usize;
1735                if m < 1 || m > 48 {
1736                    return Err("Code 3: invalid frame count");
1737                }
1738                frame_count = m;
1739                let vbr = (count_byte & 0x80) != 0;
1740                let padding = (count_byte & 0x40) != 0;
1741
1742                // Padding length indicator bytes follow the count byte; the
1743                // padding data itself sits at the end of the packet.
1744                let mut ptr = 2usize;
1745                let mut pad_len = 0usize;
1746                if padding {
1747                    loop {
1748                        let p = *input.get(ptr).ok_or("Code 3: padding overflow")? as usize;
1749                        ptr += 1;
1750                        if p == 255 {
1751                            pad_len += 254;
1752                        } else {
1753                            pad_len += p;
1754                            break;
1755                        }
1756                    }
1757                }
1758                let end = input
1759                    .len()
1760                    .checked_sub(pad_len)
1761                    .ok_or("Code 3: padding exceeds packet")?;
1762                if ptr > end {
1763                    return Err("Code 3: padding exceeds packet");
1764                }
1765                // Frame-data region, with the length headers (VBR) at its front
1766                // and the trailing padding already excluded.
1767                let region = &input[ptr..end];
1768
1769                if vbr {
1770                    // M-1 explicit frame lengths, contiguous, then the frame
1771                    // data; the last frame is the remainder.
1772                    let mut lens = Vec::with_capacity(m.saturating_sub(1));
1773                    let mut hp = 0usize;
1774                    for _ in 0..m - 1 {
1775                        let (l, nb) = read_opus_frame_len(region, hp)?;
1776                        hp += nb;
1777                        lens.push(l);
1778                    }
1779                    let mut payloads = Vec::with_capacity(m);
1780                    let mut fp = hp;
1781                    for &l in &lens {
1782                        if fp + l > region.len() {
1783                            return Err("Code 3 VBR: frame length exceeds packet");
1784                        }
1785                        payloads.push(&region[fp..fp + l]);
1786                        fp += l;
1787                    }
1788                    if fp > region.len() {
1789                        return Err("Code 3 VBR: no data for last frame");
1790                    }
1791                    payloads.push(&region[fp..]);
1792                    frame_payloads = payloads;
1793                } else {
1794                    // CBR: the region splits into M equal frames (possibly all
1795                    // empty, e.g. DTX).
1796                    if region.len() % m != 0 {
1797                        return Err("Code 3 CBR: frame data not divisible by frame count");
1798                    }
1799                    let frame_len = region.len() / m;
1800                    frame_payloads = (0..m)
1801                        .map(|i| &region[i * frame_len..(i + 1) * frame_len])
1802                        .collect();
1803                }
1804            }
1805            _ => unreachable!(),
1806        }
1807
1808        self.frame_size = frame_size;
1809        self.bandwidth = bandwidth;
1810        self.stream_channels = packet_channels;
1811
1812        let sub_frame_size = frame_size / frame_count;
1813        let sub_output_len = sub_frame_size * self.channels;
1814
1815        match mode {
1816            OpusMode::SilkOnly => {
1817                let internal_sample_rate = match bandwidth {
1818                    Bandwidth::Narrowband => 8000,
1819                    Bandwidth::Mediumband => 12000,
1820                    Bandwidth::Wideband => 16000,
1821                    _ => 16000,
1822                };
1823                let internal_frame_size =
1824                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
1825
1826                if self.sampling_rate != internal_sample_rate
1827                    && internal_sample_rate != self.prev_internal_rate
1828                {
1829                    self.silk_resampler
1830                        .init(internal_sample_rate, self.sampling_rate);
1831                    self.silk_resampler_r
1832                        .init(internal_sample_rate, self.sampling_rate);
1833                    self.prev_internal_rate = internal_sample_rate;
1834                }
1835
1836                // Pure-SILK stereo (both stream and output are 2ch): reconstruct
1837                // true L/R via SILK MS->LR instead of duplicating the mono mid.
1838                let silk_lr = self.channels == 2 && packet_channels == 2;
1839                self.silk_dec.produce_lr = silk_lr;
1840
1841                // Per-packet internal channel switch (libopus dec_API.c:119-166).
1842                let prev_internal_ch = self.silk_dec.n_channels_internal;
1843                if packet_channels as i32 > prev_internal_ch {
1844                    // mono -> stereo: reset the side channel decoder.
1845                    silk::init_decoder::silk_init_decoder(
1846                        &mut self.silk_dec.channel_state[1],
1847                    );
1848                }
1849                if self.channels == 2 && packet_channels == 2 && prev_internal_ch == 1 {
1850                    // Switching to stereo: clear stereo prediction/side history and
1851                    // seed the right-channel resampler from the (continuous) left.
1852                    self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
1853                    self.silk_dec.s_stereo_side = [0; 2];
1854                    self.silk_resampler_r = self.silk_resampler.clone();
1855                }
1856                self.silk_dec.n_channels_internal = packet_channels as i32;
1857
1858                // A 40/60 ms Opus frame carries 2/3 internal 20 ms SILK frames;
1859                // 10/20 ms carry one. libopus calls silk_Decode once per internal
1860                // frame (continuing the same range coder within the payload). We
1861                // must too — decoding only the first internal frame leaves the
1862                // rest of a 40/60 ms packet silent (the "collapse" bug).
1863                let n_silk = match frame_duration_ms {
1864                    40 => 2,
1865                    60 => 3,
1866                    _ => 1,
1867                };
1868                let internal_sub_frame_size = internal_frame_size / n_silk;
1869                let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1870                // Per-FRAME previous mode (libopus updates prev_mode per frame; for
1871                // payloads after the first, the previous frame is this same packet).
1872                let mut prev_mode_frame = self.prev_mode;
1873
1874                for (fi, payload) in frame_payloads.iter().enumerate() {
1875                    let mut rc = RangeCoder::new_decoder(payload);
1876                    let pcm_i16_len = internal_sub_frame_size * self.channels;
1877                    // A malformed packet can imply a frame larger than our scratch
1878                    // buffer; reject it gracefully instead of slicing out of bounds
1879                    // (a decode-path DoS on attacker-controlled input).
1880                    if pcm_i16_len + 2 > self.w_pcm_i16.len() {
1881                        return Err("opus: SILK frame size exceeds buffer");
1882                    }
1883                    let out_start = fi * sub_output_len;
1884                    let mut silk_off = 0usize; // output samples/ch within this Opus frame
1885
1886                    for sf in 0..n_silk {
1887                        let s_mid = self.silk_s_mid;
1888                        let ret = {
1889                            let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1890                            // Prepend the previous frame's last two samples (sMid) at
1891                            // [0..2] and decode at offset 2, matching libopus's
1892                            // samplesOut1_tmp[n][2] layout.
1893                            pcm_i16[0] = s_mid[0];
1894                            pcm_i16[1] = s_mid[1];
1895                            silk_dec.decode(
1896                                &mut rc,
1897                                &mut pcm_i16[2..pcm_i16_len + 2],
1898                                silk::decode_frame::FLAG_DECODE_NORMAL,
1899                                sf == 0,
1900                                frame_duration_ms,
1901                                internal_sample_rate,
1902                            )
1903                        };
1904
1905                        if ret < 0 {
1906                            return Err("SILK decoding failed");
1907                        }
1908
1909                        let decoded_samples = ret as usize;
1910                        // Carry the last two decoded samples as next frame's sMid.
1911                        if decoded_samples >= 2 {
1912                            self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1913                            self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1914                        }
1915                        let base = out_start + silk_off * self.channels;
1916
1917                        // Stereo SILK: L in silk_dec.l_out, R in silk_dec.r_out,
1918                        // both already in the 1-sample-delay-line layout. Resample
1919                        // each channel through its own resampler.
1920                        let out_len = if silk_lr {
1921                            if self.sampling_rate == internal_sample_rate {
1922                                for i in 0..decoded_samples {
1923                                    let l = self.silk_dec.l_out[i] as f32 / 32768.0;
1924                                    let r = self.silk_dec.r_out[i] as f32 / 32768.0;
1925                                    let idx = base + i * 2;
1926                                    if idx + 1 < output.len() {
1927                                        output[idx] = l;
1928                                        output[idx + 1] = r;
1929                                    }
1930                                }
1931                                decoded_samples
1932                            } else {
1933                                let out_len = (decoded_samples as f64 * ratio) as usize;
1934                                // Left
1935                                self.silk_resampler.process(
1936                                    &mut self.w_pcm_resampled[..out_len],
1937                                    &self.silk_dec.l_out[..decoded_samples],
1938                                    decoded_samples as i32,
1939                                );
1940                                for i in 0..out_len {
1941                                    let idx = base + i * 2;
1942                                    if idx < output.len() {
1943                                        output[idx] = self.w_pcm_resampled[i] as f32 / 32768.0;
1944                                    }
1945                                }
1946                                // Right (reuse the scratch)
1947                                self.silk_resampler_r.process(
1948                                    &mut self.w_pcm_resampled[..out_len],
1949                                    &self.silk_dec.r_out[..decoded_samples],
1950                                    decoded_samples as i32,
1951                                );
1952                                for i in 0..out_len {
1953                                    let idx = base + i * 2 + 1;
1954                                    if idx < output.len() {
1955                                        output[idx] = self.w_pcm_resampled[i] as f32 / 32768.0;
1956                                    }
1957                                }
1958                                out_len
1959                            }
1960                        } else if self.sampling_rate == internal_sample_rate {
1961                            let frames = decoded_samples;
1962                            for i in 0..frames {
1963                                let v = self.w_pcm_i16[1 + i] as f32 / 32768.0;
1964                                for ch in 0..self.channels {
1965                                    let idx = base + i * self.channels + ch;
1966                                    if idx < output.len() {
1967                                        output[idx] = v;
1968                                    }
1969                                }
1970                            }
1971                            frames
1972                        } else {
1973                            let out_len = (decoded_samples as f64 * ratio) as usize;
1974                            debug_assert!(out_len <= self.w_pcm_resampled.len());
1975                            {
1976                                let (silk_res, pcm_i16, pcm_out) = (
1977                                    &mut self.silk_resampler,
1978                                    &self.w_pcm_i16,
1979                                    &mut self.w_pcm_resampled,
1980                                );
1981                                silk_res.process(
1982                                    &mut pcm_out[..out_len],
1983                                    &pcm_i16[1..1 + decoded_samples],
1984                                    decoded_samples as i32,
1985                                );
1986                            }
1987                            for i in 0..out_len {
1988                                let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1989                                for ch in 0..self.channels {
1990                                    let idx = base + i * self.channels + ch;
1991                                    if idx < output.len() {
1992                                        output[idx] = v;
1993                                    }
1994                                }
1995                            }
1996                            // Stereo output, mono packet: also run the mono signal
1997                            // through the RIGHT-channel resampler so its state stays
1998                            // continuous for the next stereo packet (libopus
1999                            // dec_API.c:351-355). Its output overwrites channel 1,
2000                            // which is numerically ~identical to the left here.
2001                            if self.channels == 2 {
2002                                self.silk_resampler_r.process(
2003                                    &mut self.w_pcm_resampled[..out_len],
2004                                    &self.w_pcm_i16[1..1 + decoded_samples],
2005                                    decoded_samples as i32,
2006                                );
2007                                for i in 0..out_len {
2008                                    let idx = base + i * 2 + 1;
2009                                    if idx < output.len() {
2010                                        output[idx] = self.w_pcm_resampled[i] as f32 / 32768.0;
2011                                    }
2012                                }
2013                            }
2014                            out_len
2015                        };
2016                        silk_off += out_len;
2017                    }
2018
2019                    // --- Opus redundancy layer (opus_decoder.c:420-580) ---
2020                    // A SILK-only frame carries IMPLICIT CELT redundancy: if >= 17
2021                    // bits remain after SILK, the trailing bytes ARE a 5 ms CELT
2022                    // frame (no flag) used to smooth mode/bandwidth transitions.
2023                    let mut redundant_rng = 0u32;
2024                    let mut redundancy = false;
2025                    let mut celt_to_silk = false;
2026                    let plen = payload.len();
2027                    let f5 = (self.sampling_rate / 200) as usize;
2028                    let f2_5 = f5 / 2;
2029                    let red_end_band = celt_endband_for_bandwidth(bandwidth);
2030                    let mut red_buf = [0.0f32; 480]; // F5 * <=2ch, planar
2031                    let mut red_bytes = 0usize;
2032                    if self.sampling_rate == 48000 && rc.tell() + 17 <= (plen as i32) * 8 {
2033                        redundancy = true;
2034                        celt_to_silk = rc.decode_bit_logp(1);
2035                        red_bytes = plen - (((rc.tell() + 7) >> 3) as usize);
2036                        if red_bytes < 2 || red_bytes >= plen {
2037                            redundancy = false;
2038                            red_bytes = 0;
2039                        }
2040                    }
2041                    // CELT->SILK: the redundant frame continues the prior CELT
2042                    // state (a fade-out of the previous CELT mode). Decode BEFORE
2043                    // the hybrid->SILK silence frame to keep libopus state order.
2044                    if redundancy && celt_to_silk {
2045                        redundant_rng = self.decode_redundant_celt(
2046                            &payload[plen - red_bytes..],
2047                            false,
2048                            packet_channels,
2049                            red_end_band,
2050                            &mut red_buf[..f5 * self.channels],
2051                        );
2052                    }
2053                    // Hybrid->SILK transition: let the CELT MDCT fade out by
2054                    // decoding a 2-byte silence frame; its 2.5 ms overlap tail is
2055                    // ADDED to the output (libopus decodes it into pcm before the
2056                    // SILK sum).
2057                    if self.sampling_rate == 48000
2058                        && prev_mode_frame == Some(OpusMode::Hybrid)
2059                        && !(redundancy && celt_to_silk && self.prev_redundancy)
2060                    {
2061                        let silence = [0xFFu8, 0xFF];
2062                        let mut sil_buf = [0.0f32; 240]; // F2_5 * <=2ch, planar
2063                        self.celt_dec.set_stream_channels(packet_channels);
2064                        let mut src = RangeCoder::new_decoder(&silence);
2065                        self.celt_dec.decode_from_range_coder_with_band_range(
2066                            &mut src,
2067                            16,
2068                            f2_5,
2069                            &mut sil_buf[..f2_5 * self.channels],
2070                            0,
2071                            red_end_band,
2072                        );
2073                        let region = &mut output[out_start..out_start + sub_output_len];
2074                        for i in 0..f2_5 {
2075                            for c in 0..self.channels {
2076                                region[i * self.channels + c] += sil_buf[c * f2_5 + i];
2077                            }
2078                        }
2079                    }
2080                    // SILK->CELT: reset, then decode — this PRIMES the CELT state
2081                    // for the upcoming CELT-mode frames (which is why the next mode
2082                    // change skips its reset when prev_redundancy is set).
2083                    if redundancy && !celt_to_silk {
2084                        redundant_rng = self.decode_redundant_celt(
2085                            &payload[plen - red_bytes..],
2086                            true,
2087                            packet_channels,
2088                            red_end_band,
2089                            &mut red_buf[..f5 * self.channels],
2090                        );
2091                    }
2092                    if redundancy {
2093                        let window = modes::default_mode().window;
2094                        let region = &mut output[out_start..out_start + sub_output_len];
2095                        if celt_to_silk {
2096                            redundancy_fade_start(
2097                                region,
2098                                &red_buf,
2099                                f5,
2100                                f2_5,
2101                                self.channels,
2102                                window,
2103                            );
2104                        } else {
2105                            redundancy_fade_end(
2106                                region,
2107                                sub_frame_size,
2108                                &red_buf,
2109                                f5,
2110                                f2_5,
2111                                self.channels,
2112                                window,
2113                            );
2114                        }
2115                    }
2116                    self.prev_redundancy = redundancy && !celt_to_silk;
2117                    prev_mode_frame = Some(OpusMode::SilkOnly);
2118                    self.last_range = rc.rng ^ redundant_rng;
2119                }
2120                self.prev_mode = Some(OpusMode::SilkOnly);
2121                Ok(frame_size)
2122            }
2123
2124            OpusMode::CeltOnly => {
2125                let celt_end_band = self.celt_end_band_from_toc(toc);
2126                // libopus opus_decoder.c:515 — discard CELT state on a mode change
2127                // unless the previous frame's SILK->CELT redundant frame already
2128                // primed it.
2129                if let Some(pm) = self.prev_mode {
2130                    if pm != OpusMode::CeltOnly && !self.prev_redundancy {
2131                        self.celt_dec.reset();
2132                    }
2133                }
2134                self.prev_redundancy = false;
2135                // Mono packet in a stereo stream => C=1, CC=2 (continuous state).
2136                self.celt_dec.set_stream_channels(packet_channels);
2137
2138                for (fi, payload) in frame_payloads.iter().enumerate() {
2139                    let mut rc = RangeCoder::new_decoder(payload);
2140                    let total_bits = (payload.len() * 8) as i32;
2141                    let needed = sub_frame_size * self.channels;
2142                    let out_start = fi * needed;
2143                    let out_end = (out_start + needed).min(output.len());
2144
2145                    if output.len() < out_end {
2146                        return Err("Output buffer too small");
2147                    }
2148
2149                    if self.channels == 1 {
2150                        self.celt_dec.decode_from_range_coder_with_band_range(
2151                            &mut rc,
2152                            total_bits,
2153                            sub_frame_size,
2154                            &mut output[out_start..out_end],
2155                            0,
2156                            celt_end_band,
2157                        );
2158                        for sample in &mut output[out_start..out_end] {
2159                            *sample = sample.clamp(-1.0, 1.0);
2160                        }
2161                    } else {
2162                        self.celt_dec.decode_from_range_coder_with_band_range(
2163                            &mut rc,
2164                            total_bits,
2165                            sub_frame_size,
2166                            &mut self.w_celt_planar[..needed],
2167                            0,
2168                            celt_end_band,
2169                        );
2170                        for i in 0..sub_frame_size {
2171                            for ch in 0..self.channels {
2172                                let idx = out_start + i * self.channels + ch;
2173                                output[idx] =
2174                                    self.w_celt_planar[ch * sub_frame_size + i].clamp(-1.0, 1.0);
2175                            }
2176                        }
2177                    }
2178                    self.last_range = rc.rng;
2179                }
2180                self.prev_mode = Some(OpusMode::CeltOnly);
2181                Ok(frame_size)
2182            }
2183
2184            OpusMode::Hybrid => {
2185                let internal_sample_rate = 16000;
2186                let internal_frame_size =
2187                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
2188                let celt_end_band = self.celt_end_band_from_toc(toc);
2189
2190                if self.sampling_rate != internal_sample_rate
2191                    && internal_sample_rate != self.prev_internal_rate
2192                {
2193                    self.silk_resampler
2194                        .init(internal_sample_rate, self.sampling_rate);
2195                    self.silk_resampler_r
2196                        .init(internal_sample_rate, self.sampling_rate);
2197                    self.prev_internal_rate = internal_sample_rate;
2198                }
2199
2200                // Same SILK stereo/channel handling as the SilkOnly arm: true L/R
2201                // low band via MS->LR for stereo packets; per-packet internal
2202                // channel switch with side-channel/stereo-state resets.
2203                let silk_lr = self.channels == 2 && packet_channels == 2;
2204                self.silk_dec.produce_lr = silk_lr;
2205                let prev_internal_ch = self.silk_dec.n_channels_internal;
2206                if packet_channels as i32 > prev_internal_ch {
2207                    silk::init_decoder::silk_init_decoder(&mut self.silk_dec.channel_state[1]);
2208                }
2209                if self.channels == 2 && packet_channels == 2 && prev_internal_ch == 1 {
2210                    self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
2211                    self.silk_dec.s_stereo_side = [0; 2];
2212                    self.silk_resampler_r = self.silk_resampler.clone();
2213                }
2214                self.silk_dec.n_channels_internal = packet_channels as i32;
2215
2216                for (fi, payload) in frame_payloads.iter().enumerate() {
2217                    let mut rc = RangeCoder::new_decoder(payload);
2218                    let pcm_silk_i16_len = internal_frame_size * self.channels;
2219                    if pcm_silk_i16_len + 2 > self.w_pcm_i16.len() {
2220                        return Err("opus: SILK frame size exceeds buffer");
2221                    }
2222
2223                    // Prepend the previous frame's last two samples (sMid) and
2224                    // decode at offset 2, matching libopus's samplesOut1_tmp[n][2]
2225                    // layout — the resampler is fed from offset 1 (the 1-sample
2226                    // delay line), keeping the SILK low band aligned with the CELT
2227                    // high band exactly as in the reference.
2228                    let s_mid = self.silk_s_mid;
2229                    let ret = {
2230                        let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
2231                        pcm_i16[0] = s_mid[0];
2232                        pcm_i16[1] = s_mid[1];
2233                        silk_dec.decode(
2234                            &mut rc,
2235                            &mut pcm_i16[2..pcm_silk_i16_len + 2],
2236                            silk::decode_frame::FLAG_DECODE_NORMAL,
2237                            true,
2238                            frame_duration_ms,
2239                            internal_sample_rate,
2240                        )
2241                    };
2242
2243                    if ret < 0 {
2244                        return Err("SILK decoding failed");
2245                    }
2246
2247                    let silk_out_len = sub_frame_size * self.channels;
2248                    self.w_silk_out[..silk_out_len].fill(0.0);
2249                    if ret > 0 {
2250                        let decoded_samples = ret as usize;
2251                        if decoded_samples >= 2 {
2252                            self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
2253                            self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
2254                        }
2255                        let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
2256                        let out_len =
2257                            ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
2258                        debug_assert!(out_len <= self.w_pcm_resampled.len());
2259                        if silk_lr {
2260                            // Stereo low band: L/R from dec_api (already in the
2261                            // 1-sample-delay layout), each through its own resampler.
2262                            self.silk_resampler.process(
2263                                &mut self.w_pcm_resampled[..out_len],
2264                                &self.silk_dec.l_out[..decoded_samples],
2265                                decoded_samples as i32,
2266                            );
2267                            for i in 0..out_len {
2268                                self.w_silk_out[i * 2] = self.w_pcm_resampled[i] as f32 / 32768.0;
2269                            }
2270                            self.silk_resampler_r.process(
2271                                &mut self.w_pcm_resampled[..out_len],
2272                                &self.silk_dec.r_out[..decoded_samples],
2273                                decoded_samples as i32,
2274                            );
2275                            for i in 0..out_len {
2276                                self.w_silk_out[i * 2 + 1] =
2277                                    self.w_pcm_resampled[i] as f32 / 32768.0;
2278                            }
2279                        } else {
2280                            self.silk_resampler.process(
2281                                &mut self.w_pcm_resampled[..out_len],
2282                                &self.w_pcm_i16[1..1 + decoded_samples],
2283                                decoded_samples as i32,
2284                            );
2285                            for i in 0..out_len {
2286                                let v = self.w_pcm_resampled[i] as f32 / 32768.0;
2287                                for ch in 0..self.channels {
2288                                    self.w_silk_out[i * self.channels + ch] = v;
2289                                }
2290                            }
2291                            // Mono packet, stereo output: keep the right-channel
2292                            // resampler continuous (libopus dec_API.c:351-355).
2293                            if self.channels == 2 {
2294                                self.silk_resampler_r.process(
2295                                    &mut self.w_pcm_resampled[..out_len],
2296                                    &self.w_pcm_i16[1..1 + decoded_samples],
2297                                    decoded_samples as i32,
2298                                );
2299                                for i in 0..out_len {
2300                                    self.w_silk_out[i * 2 + 1] =
2301                                        self.w_pcm_resampled[i] as f32 / 32768.0;
2302                                }
2303                            }
2304                        }
2305                    }
2306
2307                    // --- Opus redundancy layer, hybrid form (opus_decoder.c) ---
2308                    // redundancy = bit(12); if set: celt_to_silk = bit(1),
2309                    // redundancy_bytes = uint(256)+2 taken from the END of the
2310                    // packet — the MAIN CELT layer still decodes, but with the
2311                    // range coder's storage shrunk by those bytes (this changes
2312                    // its raw-bit region and tell budget).
2313                    let plen = payload.len();
2314                    let mut redundancy = false;
2315                    let mut celt_to_silk = false;
2316                    let mut red_bytes = 0usize;
2317                    let mut effective_len = plen;
2318                    if rc.tell() + 37 <= (plen as i32) * 8 {
2319                        redundancy = rc.decode_bit_logp(12);
2320                        if redundancy {
2321                            celt_to_silk = rc.decode_bit_logp(1);
2322                            red_bytes = rc.dec_uint(256) as usize + 2;
2323                            if red_bytes <= effective_len {
2324                                effective_len -= red_bytes;
2325                            } else {
2326                                red_bytes = 0;
2327                                redundancy = false;
2328                            }
2329                            if redundancy && (effective_len as i32) * 8 < rc.tell() {
2330                                effective_len = plen;
2331                                red_bytes = 0;
2332                                redundancy = false;
2333                            }
2334                            if redundancy {
2335                                rc.storage -= red_bytes as u32;
2336                            }
2337                        }
2338                    }
2339                    let f5 = (self.sampling_rate / 200) as usize;
2340                    let f2_5 = f5 / 2;
2341                    let red_end_band = celt_endband_for_bandwidth(bandwidth);
2342                    let mut red_buf = [0.0f32; 480];
2343                    let mut redundant_rng = 0u32;
2344                    let do_red = redundancy && self.sampling_rate == 48000;
2345                    // CELT->SILK: redundant frame decodes BEFORE the main CELT,
2346                    // continuing the prior CELT state (fade-out of previous CELT).
2347                    if do_red && celt_to_silk {
2348                        redundant_rng = self.decode_redundant_celt(
2349                            &payload[plen - red_bytes..],
2350                            false,
2351                            packet_channels,
2352                            red_end_band,
2353                            &mut red_buf[..f5 * self.channels],
2354                        );
2355                    }
2356
2357                    // Main CELT high band. libopus opus_decoder.c:515 — reset CELT
2358                    // on a mode change unless primed by prior SILK->CELT redundancy.
2359                    if fi == 0 {
2360                        if let Some(pm) = self.prev_mode {
2361                            if pm != OpusMode::Hybrid && !self.prev_redundancy {
2362                                self.celt_dec.reset();
2363                            }
2364                        }
2365                    }
2366                    self.celt_dec.set_stream_channels(packet_channels);
2367                    let total_bits = (effective_len * 8) as i32;
2368                    {
2369                        let (celt_dec, celt_planar) = (&mut self.celt_dec, &mut self.w_celt_planar);
2370                        celt_dec.decode_from_range_coder_with_band_range(
2371                            &mut rc,
2372                            total_bits,
2373                            sub_frame_size,
2374                            &mut celt_planar[..silk_out_len],
2375                            17,
2376                            celt_end_band,
2377                        );
2378
2379                        if self.channels == 1 {
2380                            self.w_celt_out[..silk_out_len]
2381                                .copy_from_slice(&self.w_celt_planar[..silk_out_len]);
2382                        } else {
2383                            for i in 0..sub_frame_size {
2384                                for ch in 0..self.channels {
2385                                    self.w_celt_out[i * self.channels + ch] =
2386                                        self.w_celt_planar[ch * sub_frame_size + i];
2387                                }
2388                            }
2389                        }
2390                    }
2391
2392                    let out_start = fi * silk_out_len;
2393                    let total = silk_out_len.min(output.len() - out_start);
2394                    for j in 0..total {
2395                        output[out_start + j] =
2396                            (self.w_silk_out[j] + self.w_celt_out[j]).clamp(-1.0, 1.0);
2397                    }
2398
2399                    // SILK->CELT: reset + decode the redundant frame AFTER the main
2400                    // decode; it primes the CELT state for the upcoming CELT mode.
2401                    if do_red && !celt_to_silk {
2402                        redundant_rng = self.decode_redundant_celt(
2403                            &payload[plen - red_bytes..],
2404                            true,
2405                            packet_channels,
2406                            red_end_band,
2407                            &mut red_buf[..f5 * self.channels],
2408                        );
2409                    }
2410                    if do_red {
2411                        let window = modes::default_mode().window;
2412                        let region = &mut output[out_start..out_start + silk_out_len];
2413                        if celt_to_silk {
2414                            redundancy_fade_start(
2415                                region,
2416                                &red_buf,
2417                                f5,
2418                                f2_5,
2419                                self.channels,
2420                                window,
2421                            );
2422                        } else {
2423                            redundancy_fade_end(
2424                                region,
2425                                sub_frame_size,
2426                                &red_buf,
2427                                f5,
2428                                f2_5,
2429                                self.channels,
2430                                window,
2431                            );
2432                        }
2433                    }
2434                    self.prev_redundancy = redundancy && !celt_to_silk;
2435                    self.last_range = rc.rng ^ redundant_rng;
2436                }
2437                self.prev_mode = Some(OpusMode::Hybrid);
2438                Ok(frame_size)
2439            }
2440        }
2441    }
2442}
2443
2444impl OpusDecoder {
2445    #[inline(always)]
2446    fn celt_end_band_from_toc(&self, toc: u8) -> usize {
2447        let mode = modes::default_mode();
2448        let top = mode.eff_ebands;
2449        if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
2450            const FROM_OPUS_TABLE: [u8; 16] = [
2451                0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
2452                0x10, 0x18,
2453            ];
2454            let idx = ((toc >> 3) - 16) as usize;
2455            let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
2456            let trim = (data0 >> 5) as usize;
2457            return top.saturating_sub(2 * trim).max(1);
2458        }
2459        // Hybrid: libopus maps the packet bandwidth to a CELT end band
2460        // (opus_decoder.c: SWB -> 19, FB -> 21). Decoding SWB hybrid with 21
2461        // reads two bands the encoder never coded -> range desync every packet.
2462        if mode_from_toc(toc) == OpusMode::Hybrid
2463            && bandwidth_from_toc(toc) == Bandwidth::Superwideband
2464        {
2465            return 19.min(top);
2466        }
2467        top
2468    }
2469
2470    /// Decode a redundant CELT frame (opus_decoder.c "5 ms redundant frame"):
2471    /// start band 0, end band from the packet bandwidth, 5 ms, its own range
2472    /// decoder. Returns the redundant final range; PLANAR output in `buf`
2473    /// (F5 samples per state channel). Only valid at 48 kHz output.
2474    fn decode_redundant_celt(
2475        &mut self,
2476        red: &[u8],
2477        reset_first: bool,
2478        packet_channels: usize,
2479        end_band: usize,
2480        buf: &mut [f32],
2481    ) -> u32 {
2482        if reset_first {
2483            self.celt_dec.reset();
2484        }
2485        self.celt_dec.set_stream_channels(packet_channels);
2486        let f5 = (self.sampling_rate / 200) as usize;
2487        let mut rrc = RangeCoder::new_decoder(red);
2488        let total_bits = (red.len() * 8) as i32;
2489        self.celt_dec.decode_from_range_coder_with_band_range(
2490            &mut rrc, total_bits, f5, buf, 0, end_band,
2491        );
2492        rrc.rng
2493    }
2494}
2495
2496/// libopus opus_decoder.c bandwidth -> CELT end band for the packet.
2497fn celt_endband_for_bandwidth(bw: Bandwidth) -> usize {
2498    match bw {
2499        Bandwidth::Narrowband => 13,
2500        Bandwidth::Mediumband | Bandwidth::Wideband => 17,
2501        Bandwidth::Superwideband => 19,
2502        _ => 21,
2503    }
2504}
2505
2506/// smooth_fade cross-fades (w = window[i]^2, 48 kHz inc=1) applied to the
2507/// interleaved output region of one frame. `red` is PLANAR (F5 per channel).
2508/// celt_to_silk: redundant frame occupies the START of the frame — first 2.5 ms
2509/// copied verbatim, next 2.5 ms fades redundant -> main.
2510fn redundancy_fade_start(
2511    out: &mut [f32],
2512    red: &[f32],
2513    f5: usize,
2514    f2_5: usize,
2515    channels: usize,
2516    window: &[f32],
2517) {
2518    for i in 0..f2_5 {
2519        for c in 0..channels {
2520            out[i * channels + c] = red[c * f5 + i];
2521        }
2522    }
2523    for i in 0..f2_5 {
2524        let w = window[i] * window[i];
2525        for c in 0..channels {
2526            let idx = (f2_5 + i) * channels + c;
2527            out[idx] = (1.0 - w) * red[c * f5 + f2_5 + i] + w * out[idx];
2528        }
2529    }
2530}
2531
2532/// SILK->CELT: redundant frame occupies the END of the frame — the last 2.5 ms
2533/// fades main -> redundant (second half of the redundant frame).
2534fn redundancy_fade_end(
2535    out: &mut [f32],
2536    frame_samples: usize,
2537    red: &[f32],
2538    f5: usize,
2539    f2_5: usize,
2540    channels: usize,
2541    window: &[f32],
2542) {
2543    for i in 0..f2_5 {
2544        let w = window[i] * window[i];
2545        for c in 0..channels {
2546            let idx = (frame_samples - f2_5 + i) * channels + c;
2547            out[idx] = (1.0 - w) * out[idx] + w * red[c * f5 + f2_5 + i];
2548        }
2549    }
2550}
2551
2552fn frame_rate_from_params(sampling_rate: i32, frame_size: usize) -> Option<i32> {
2553    let frame_size = frame_size as i32;
2554    if frame_size == 0 || sampling_rate % frame_size != 0 {
2555        return None;
2556    }
2557    Some(sampling_rate / frame_size)
2558}
2559
2560fn gen_toc(mode: OpusMode, frame_rate: i32, bandwidth: Bandwidth, channels: usize) -> u8 {
2561    let mut rate = frame_rate;
2562    let mut period = 0;
2563    while rate < 400 {
2564        rate <<= 1;
2565        period += 1;
2566    }
2567
2568    let mut toc = match mode {
2569        OpusMode::SilkOnly => {
2570            let bw = (bandwidth as i32 - Bandwidth::Narrowband as i32) << 5;
2571            let per = (period - 2) << 3;
2572            (bw | per) as u8
2573        }
2574        OpusMode::CeltOnly => {
2575            let mut tmp = bandwidth as i32 - Bandwidth::Mediumband as i32;
2576            if tmp < 0 {
2577                tmp = 0;
2578            }
2579            let per = period << 3;
2580            (0x80 | (tmp << 5) | per) as u8
2581        }
2582        OpusMode::Hybrid => {
2583            let base_config = if bandwidth == Bandwidth::Superwideband {
2584                12
2585            } else {
2586                14
2587            };
2588            let period_offset = if frame_rate >= 100 { 0 } else { 1 };
2589            ((base_config + period_offset) << 3) as u8
2590        }
2591    };
2592
2593    if channels == 2 {
2594        toc |= 0x04;
2595    }
2596    toc
2597}
2598
2599fn mode_from_toc(toc: u8) -> OpusMode {
2600    if toc & 0x80 != 0 {
2601        OpusMode::CeltOnly
2602    } else if toc & 0x60 == 0x60 {
2603        OpusMode::Hybrid
2604    } else {
2605        OpusMode::SilkOnly
2606    }
2607}
2608
2609fn bandwidth_from_toc(toc: u8) -> Bandwidth {
2610    let mode = mode_from_toc(toc);
2611    match mode {
2612        OpusMode::SilkOnly => {
2613            let bw_bits = (toc >> 5) & 0x03;
2614            match bw_bits {
2615                0 => Bandwidth::Narrowband,
2616                1 => Bandwidth::Mediumband,
2617                2 => Bandwidth::Wideband,
2618                _ => Bandwidth::Wideband,
2619            }
2620        }
2621        OpusMode::Hybrid => {
2622            let bw_bit = (toc >> 4) & 0x01;
2623            if bw_bit == 0 {
2624                Bandwidth::Superwideband
2625            } else {
2626                Bandwidth::Fullband
2627            }
2628        }
2629        OpusMode::CeltOnly => {
2630            let bw_bits = (toc >> 5) & 0x03;
2631            match bw_bits {
2632                0 => Bandwidth::Mediumband,
2633                1 => Bandwidth::Wideband,
2634                2 => Bandwidth::Superwideband,
2635                3 => Bandwidth::Fullband,
2636                _ => Bandwidth::Fullband,
2637            }
2638        }
2639    }
2640}
2641
2642fn frame_duration_ms_from_toc(toc: u8) -> i32 {
2643    let mode = mode_from_toc(toc);
2644    match mode {
2645        OpusMode::SilkOnly => {
2646            let config = (toc >> 3) & 0x03;
2647            match config {
2648                0 => 10,
2649                1 => 20,
2650                2 => 40,
2651                3 => 60,
2652                _ => 20,
2653            }
2654        }
2655        OpusMode::Hybrid => {
2656            let config = (toc >> 3) & 0x01;
2657            if config == 0 { 10 } else { 20 }
2658        }
2659        OpusMode::CeltOnly => {
2660            let config = (toc >> 3) & 0x03;
2661            match config {
2662                0 => 2,
2663                1 => 5,
2664                2 => 10,
2665                3 => 20,
2666                _ => 20,
2667            }
2668        }
2669    }
2670}
2671
2672fn channels_from_toc(toc: u8) -> usize {
2673    if toc & 0x04 != 0 { 2 } else { 1 }
2674}
2675
2676/// RFC 6716 §3.1 frame-length coding (used by code 2 and VBR code 3): a length
2677/// of 0..=251 is one byte with that value; 252..=1275 is two bytes `b0` (252..255)
2678/// then `b1`, giving `b1*4 + b0`. Returns `(length, bytes_consumed)`.
2679fn read_opus_frame_len(data: &[u8], ptr: usize) -> Result<(usize, usize), &'static str> {
2680    let b0 = *data.get(ptr).ok_or("Opus frame length: truncated")? as usize;
2681    if b0 < 252 {
2682        Ok((b0, 1))
2683    } else {
2684        let b1 = *data.get(ptr + 1).ok_or("Opus frame length: truncated 2-byte")? as usize;
2685        Ok((b1 * 4 + b0, 2))
2686    }
2687}
2688
2689#[cfg(test)]
2690mod tests {
2691    use super::*;
2692
2693    fn frame_size_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
2694        let mode = mode_from_toc(toc);
2695        match mode {
2696            OpusMode::CeltOnly => {
2697                let period = ((toc >> 3) & 0x03) as i32;
2698                let frame_rate = 400 >> period;
2699                if frame_rate == 0 || sampling_rate % frame_rate != 0 {
2700                    return None;
2701                }
2702                Some((sampling_rate / frame_rate) as usize)
2703            }
2704            OpusMode::SilkOnly => {
2705                let duration_ms = frame_duration_ms_from_toc(toc);
2706                Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
2707            }
2708            OpusMode::Hybrid => {
2709                let duration_ms = frame_duration_ms_from_toc(toc);
2710                Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
2711            }
2712        }
2713    }
2714
2715    #[test]
2716    fn gen_toc_matches_celt_reference_values() {
2717        let sampling_rate = 48_000;
2718        let cases = [
2719            (120usize, 0xE0u8),
2720            (240usize, 0xE8u8),
2721            (480usize, 0xF0u8),
2722            (960usize, 0xF8u8),
2723        ];
2724
2725        for (frame_size, expected_toc) in cases {
2726            let frame_rate = frame_rate_from_params(sampling_rate, frame_size).unwrap();
2727            let toc = gen_toc(OpusMode::CeltOnly, frame_rate, Bandwidth::Fullband, 1);
2728            assert_eq!(
2729                toc, expected_toc,
2730                "frame_size {} expected TOC {:02X} got {:02X}",
2731                frame_size, expected_toc, toc
2732            );
2733            let decoded_size = frame_size_from_toc(toc, sampling_rate).unwrap();
2734            assert_eq!(decoded_size, frame_size);
2735        }
2736
2737        let stereo_toc = gen_toc(
2738            OpusMode::CeltOnly,
2739            frame_rate_from_params(sampling_rate, 960).unwrap(),
2740            Bandwidth::Fullband,
2741            2,
2742        );
2743        assert_eq!(channels_from_toc(stereo_toc), 2);
2744    }
2745
2746    #[test]
2747    fn test_celt_decoder_large_frame_sizes() {
2748        let sampling_rate = 48000;
2749        let channels = 1;
2750
2751        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2752
2753        let frame_sizes = [120, 240, 480, 960];
2754
2755        for frame_size in frame_sizes {
2756            let toc = gen_toc(
2757                OpusMode::CeltOnly,
2758                frame_rate_from_params(sampling_rate, frame_size).unwrap(),
2759                Bandwidth::Fullband,
2760                channels,
2761            );
2762            let packet = [toc, 0, 0, 0, 0];
2763
2764            let mut output = vec![0.0f32; frame_size * channels];
2765
2766            let _ = decoder.decode(&packet, frame_size, &mut output);
2767        }
2768
2769        let channels = 2;
2770        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2771
2772        for frame_size in frame_sizes {
2773            let toc = gen_toc(
2774                OpusMode::CeltOnly,
2775                frame_rate_from_params(sampling_rate, frame_size).unwrap(),
2776                Bandwidth::Fullband,
2777                channels,
2778            );
2779            let packet = [toc, 0, 0, 0, 0];
2780
2781            let mut output = vec![0.0f32; frame_size * channels];
2782            let _ = decoder.decode(&packet, frame_size, &mut output);
2783        }
2784    }
2785
2786    #[test]
2787    fn test_celt_decoder_edge_case_frame_sizes() {
2788        let sampling_rate = 48000;
2789        let channels = 1;
2790        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2791
2792        let edge_sizes = [2048, 2167, 2168, 2169, 2880, 3072];
2793
2794        for frame_size in edge_sizes {
2795            let mut output = vec![0.0f32; frame_size * channels];
2796
2797            let _ = decoder.decode(&[0x80, 0, 0, 0], frame_size, &mut output);
2798        }
2799    }
2800
2801    // Regression test for: "index out of bounds: the len is 48 but the index is 119"
2802    // Root cause: frame_size=48 at 48kHz gives frame_rate=1000, which is not a valid
2803    // Hybrid-mode frame rate but was not validated.  CELT's lm-search then silently
2804    // fell back to lm=0, computed n2=120, and wrote output[119] into a 48-element
2805    // slice.  Triggered via G.729-decoded PCM (8kHz) passed to a 48kHz Opus encoder
2806    // without proper resampling, so the encoder received 48 samples instead of 480.
2807    #[test]
2808    fn test_invalid_small_frame_size_returns_error_not_panic() {
2809        let mut enc = OpusEncoder::new(48000, 2, Application::Voip).unwrap();
2810        enc.bitrate_bps = 64000;
2811        enc.complexity = 5;
2812        enc.use_cbr = true;
2813
2814        // 48 samples at 48kHz = 1ms → frame_rate=1000, invalid for Hybrid mode.
2815        let input = vec![0.0f32; 48 * 2]; // stereo interleaved
2816        let mut output = vec![0u8; 256];
2817
2818        let result = enc.encode(&input, 48, &mut output);
2819        assert!(
2820            result.is_err(),
2821            "encode with invalid frame_size=48 should return Err, not panic"
2822        );
2823    }
2824
2825    // Also verify that the Audio application path (always Hybrid at 48 kHz) rejects
2826    // the same bad frame size.
2827    #[test]
2828    fn test_invalid_small_frame_size_audio_application_returns_error() {
2829        let mut enc = OpusEncoder::new(48000, 1, Application::Audio).unwrap();
2830        let input = vec![0.0f32; 48];
2831        let mut output = vec![0u8; 256];
2832
2833        let result = enc.encode(&input, 48, &mut output);
2834        assert!(
2835            result.is_err(),
2836            "Audio/48kHz encoder with frame_size=48 should return Err"
2837        );
2838    }
2839}