Skip to main content

opus_rs/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(unsafe_op_in_unsafe_fn)]
3#![allow(clippy::too_many_arguments)]
4#![allow(clippy::needless_range_loop)]
5
6mod compat;
7mod fixedvec;
8
9pub mod bands;
10pub mod celt;
11pub mod celt_lpc;
12pub mod hp_cutoff;
13pub mod kiss_fft;
14pub mod mdct;
15pub mod modes;
16pub mod pitch;
17pub mod pvq;
18pub mod quant_bands;
19pub mod range_coder;
20pub mod rate;
21pub mod silk;
22
23pub use silk::{SilkResampler, SilkResamplerDown1_3, SilkResamplerDown1_6};
24
25pub use celt::{CeltDecoder, CeltEncoder};
26use hp_cutoff::hp_cutoff;
27use range_coder::RangeCoder;
28use silk::control_codec::silk_control_encoder;
29use silk::enc_api::silk_encode;
30use silk::init_encoder::silk_init_encoder;
31use silk::lin2log::silk_lin2log;
32use silk::log2lin::silk_log2lin;
33use silk::macros::*;
34use silk::resampler::{silk_resampler_down2, silk_resampler_down2_3};
35use silk::structs::SilkEncoderState;
36use crate::fixedvec::FixedVec;
37
38// --- Heap-free buffer capacity constants (worst case: 2 channels). ---
39const OPUS_MAX_CHANNELS: usize = 2;
40/// Largest API frame in samples/channel (120 ms @ 48 kHz = 5760). Used by the
41/// encoder's per-frame input buffers (sized `frame_size * channels`).
42const OPUS_MAX_FRAME: usize = 5760;
43/// Largest *single-frame* samples/channel (60 ms @ 48 kHz = 2880). The decoder's
44/// staging buffers hold one sub-frame at a time, so they're sized to this — not
45/// the full packet. (Halves the decoder footprint vs. a naive 5760/channel.)
46const OPUS_MAX_SUBFRAME: usize = 2880;
47/// Decoder per-sub-frame staging cap: `OPUS_MAX_SUBFRAME * max_channels`.
48const OPUS_SUBFRAME_SCRATCH: usize = OPUS_MAX_SUBFRAME * OPUS_MAX_CHANNELS;
49/// High-pass filter state memory (`channels * 2`).
50const OPUS_HP_MEM: usize = OPUS_MAX_CHANNELS * 2;
51/// Decoder `w_pcm_i16` cap (`960 * max_channels`).
52const OPUS_PCM_I16: usize = 960 * OPUS_MAX_CHANNELS;
53/// Decoder `prev_pcm_tail` cap (`240 * max_channels`).
54const OPUS_PCM_TAIL: usize = 240 * OPUS_MAX_CHANNELS;
55/// Max number of frames encoded in one Opus packet (RFC 6716 caps at 48 for
56/// 2.5 ms codes in a 120 ms packet).
57const OPUS_MAX_PACKET_FRAMES: usize = 48;
58/// RFC 6716 §3.1: a single Opus packet carries at most 1276 bytes of data.
59const OPUS_MAX_PACKET_BYTES: usize = 1276;
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum Application {
63    Voip = 2048,
64    Audio = 2049,
65    RestrictedLowDelay = 2051,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum Bandwidth {
70    Auto = -1000,
71    Narrowband = 1101,
72    Mediumband = 1102,
73    Wideband = 1103,
74    Superwideband = 1104,
75    Fullband = 1105,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79enum OpusMode {
80    SilkOnly,
81    Hybrid,
82    CeltOnly,
83}
84
85pub struct OpusEncoder {
86    celt_enc: CeltEncoder,
87    silk_enc: SilkEncoderState,
88    application: Application,
89    sampling_rate: i32,
90    channels: usize,
91    bandwidth: Bandwidth,
92    pub bitrate_bps: i32,
93    pub complexity: i32,
94    pub use_cbr: bool,
95
96    pub use_inband_fec: bool,
97
98    pub packet_loss_perc: i32,
99    silk_initialized: bool,
100    mode: OpusMode,
101    prev_enc_mode: Option<OpusMode>,
102
103    variable_hp_smth2_q15: i32,
104    hp_mem: FixedVec<i32, OPUS_HP_MEM>,
105
106    buf_filtered: FixedVec<i16, OPUS_MAX_FRAME>,
107    buf_silk_input: FixedVec<i16, OPUS_MAX_FRAME>,
108    buf_stereo_mid: FixedVec<i16, OPUS_MAX_FRAME>,
109    buf_stereo_side: FixedVec<i16, OPUS_MAX_FRAME>,
110    buf_celt_input: FixedVec<f32, OPUS_MAX_FRAME>,
111    down2_state_first: [i32; 2],
112    down2_state_second: [i32; 2],
113    down2_3_state: [i32; 6],
114    down_1_3_state: silk::resampler::SilkResamplerDown1_3,
115
116    rc: RangeCoder,
117}
118
119fn compute_equiv_rate(
120    bitrate: i32,
121    channels: usize,
122    frame_rate: i32,
123    vbr: bool,
124    complexity: i32,
125    loss: i32,
126) -> i32 {
127    let mut equiv = bitrate;
128    if frame_rate > 50 {
129        equiv -= (40 * channels as i32 + 20) * (frame_rate - 50);
130    }
131    if !vbr {
132        equiv -= equiv / 12;
133    }
134    equiv = equiv * (90 + complexity) / 100;
135    if loss > 0 {
136        equiv -= equiv * loss / (12 * loss + 20);
137    }
138    equiv
139}
140
141fn compute_mode_threshold(
142    application: Application,
143    channels: usize,
144    prev_was_celt: bool,
145    has_prev_mode: bool,
146    voice_est: i32,
147) -> i32 {
148    let mode_voice = if channels == 1 { 64000 } else { 44000 };
149    let mode_music = 10000;
150
151    let diff = mode_voice - mode_music;
152    let offset = (voice_est * voice_est * diff) >> 14;
153    let mut threshold = mode_music + offset;
154
155    if application == Application::Voip {
156        threshold += 8000;
157    }
158
159    if has_prev_mode {
160        if prev_was_celt {
161            threshold -= 4000;
162        } else {
163            threshold += 4000;
164        }
165    }
166
167    if application == Application::RestrictedLowDelay {
168        threshold = 0;
169    }
170
171    threshold
172}
173
174fn compute_silk_rate_for_hybrid(rate_bps: i32, frame20ms: bool) -> i32 {
175    const RATE_TABLE: &[(i32, i32, i32)] = &[
176        (0, 0, 0),
177        (12000, 10000, 10000),
178        (16000, 13500, 13500),
179        (20000, 16000, 16000),
180        (24000, 18000, 18000),
181        (32000, 22000, 22000),
182        (64000, 38000, 38000),
183    ];
184    let n = RATE_TABLE.len();
185    let mut i = 1;
186    while i < n && RATE_TABLE[i].0 <= rate_bps {
187        i += 1;
188    }
189    if i == n {
190        let (x_last, r10_last, r20_last) = RATE_TABLE[n - 1];
191        let base = if frame20ms { r20_last } else { r10_last };
192        base + (rate_bps - x_last) / 2
193    } else {
194        let (x0, lo10, lo20) = RATE_TABLE[i - 1];
195        let (x1, hi10, hi20) = RATE_TABLE[i];
196        let (lo, hi) = if frame20ms {
197            (lo20, hi20)
198        } else {
199            (lo10, hi10)
200        };
201        (lo * (x1 - rate_bps) + hi * (rate_bps - x0)) / (x1 - x0)
202    }
203}
204
205#[cfg(all(test, feature = "std"))]
206mod silk_rate_tests {
207    use super::compute_silk_rate_for_hybrid;
208
209    #[test]
210    fn test_reference_table_exact_entries() {
211        assert_eq!(compute_silk_rate_for_hybrid(12000, true), 10000);
212        assert_eq!(compute_silk_rate_for_hybrid(16000, true), 13500);
213        assert_eq!(compute_silk_rate_for_hybrid(20000, true), 16000);
214        assert_eq!(compute_silk_rate_for_hybrid(24000, true), 18000);
215        assert_eq!(compute_silk_rate_for_hybrid(32000, true), 22000);
216        assert_eq!(compute_silk_rate_for_hybrid(64000, true), 38000);
217    }
218
219    #[test]
220    fn test_32kbps_gives_22kbps_silk() {
221        assert_eq!(compute_silk_rate_for_hybrid(32000, true), 22000);
222    }
223
224    #[test]
225    fn test_interpolation_between_table_entries() {
226        let r = compute_silk_rate_for_hybrid(18000, true);
227        assert_eq!(r, 14750);
228    }
229
230    #[test]
231    fn test_above_table_max_gives_half_extra() {
232        let r = compute_silk_rate_for_hybrid(72000, true);
233        assert_eq!(r, 38000 + (72000 - 64000) / 2);
234    }
235}
236
237impl OpusEncoder {
238    pub fn new(
239        sampling_rate: i32,
240        channels: usize,
241        application: Application,
242    ) -> Result<Self, &'static str> {
243        if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
244            return Err("Invalid sampling rate");
245        }
246        if ![1, 2].contains(&channels) {
247            return Err("Invalid number of channels");
248        }
249
250        let mode = modes::default_mode();
251        let celt_enc = CeltEncoder::new(mode, channels);
252
253        let mut silk_enc = SilkEncoderState::default();
254        if silk_init_encoder(&mut silk_enc, 0) != 0 {
255            return Err("SILK encoder initialization failed");
256        }
257
258        let (opus_mode, bw) = match application {
259            Application::Voip => {
260                let bw = match sampling_rate {
261                    8000 => Bandwidth::Narrowband,
262                    12000 => Bandwidth::Mediumband,
263                    16000 => Bandwidth::Wideband,
264                    24000 => Bandwidth::Superwideband,
265                    48000 => Bandwidth::Fullband,
266                    _ => Bandwidth::Narrowband,
267                };
268
269                let mode = if sampling_rate > 16000 {
270                    OpusMode::Hybrid
271                } else {
272                    OpusMode::SilkOnly
273                };
274                (mode, bw)
275            }
276            Application::RestrictedLowDelay => {
277                let bw = match sampling_rate {
278                    8000 => Bandwidth::Narrowband,
279                    12000 => Bandwidth::Mediumband,
280                    16000 => Bandwidth::Wideband,
281                    24000 => Bandwidth::Superwideband,
282                    _ => Bandwidth::Fullband,
283                };
284                (OpusMode::CeltOnly, bw)
285            }
286            Application::Audio => {
287                if sampling_rate <= 16000 {
288                    let bw = match sampling_rate {
289                        8000 => Bandwidth::Narrowband,
290                        12000 => Bandwidth::Mediumband,
291                        _ => Bandwidth::Wideband,
292                    };
293                    (OpusMode::SilkOnly, bw)
294                } else {
295                    let bw = match sampling_rate {
296                        24000 => Bandwidth::Superwideband,
297                        _ => Bandwidth::Fullband,
298                    };
299                    (OpusMode::Hybrid, bw)
300                }
301            }
302        };
303
304        use silk::lin2log::silk_lin2log;
305        let variable_hp_smth2_q15 = silk_lin2log(60) << 8;
306
307        Ok(Self {
308            celt_enc,
309            silk_enc,
310            application,
311            sampling_rate,
312            channels,
313            bandwidth: bw,
314            bitrate_bps: 64000,
315            complexity: 9,
316            use_cbr: false,
317            use_inband_fec: false,
318            packet_loss_perc: 0,
319            silk_initialized: false,
320            prev_enc_mode: None,
321            mode: opus_mode,
322            variable_hp_smth2_q15,
323            hp_mem: FixedVec::from_value(0, channels * 2),
324
325            buf_filtered: FixedVec::new(),
326            buf_silk_input: FixedVec::new(),
327            buf_stereo_mid: FixedVec::new(),
328            buf_stereo_side: FixedVec::new(),
329            buf_celt_input: FixedVec::new(),
330            down2_state_first: [0; 2],
331            down2_state_second: [0; 2],
332            down2_3_state: [0; 6],
333            down_1_3_state: silk::resampler::SilkResamplerDown1_3::default(),
334            rc: RangeCoder::new_encoder(1),
335        })
336    }
337
338    pub fn enable_hybrid_mode(&mut self) -> Result<(), &'static str> {
339        if self.sampling_rate != 24000 && self.sampling_rate != 48000 {
340            return Err("Hybrid mode requires 24kHz or 48kHz sampling rate");
341        }
342        let bw = if self.sampling_rate == 48000 {
343            Bandwidth::Fullband
344        } else {
345            Bandwidth::Superwideband
346        };
347        self.mode = OpusMode::Hybrid;
348        self.bandwidth = bw;
349        self.silk_initialized = false;
350        Ok(())
351    }
352
353    pub fn encode(
354        &mut self,
355        input: &[f32],
356        frame_size: usize,
357        output: &mut [u8],
358    ) -> Result<usize, &'static str> {
359        if output.len() < 2 {
360            return Err("Output buffer too small");
361        }
362
363        let frame_rate = frame_rate_from_params(self.sampling_rate, frame_size)
364            .ok_or("Invalid frame size for sampling rate")?;
365
366        // Mode selection: match C's opus_encode_native() behavior.
367        // C reference auto-selects between SILK_ONLY and CELT_ONLY; Hybrid is
368        // produced afterwards by bandwidth overrides (SILK-only + FB/SWB → Hybrid).
369        let mut mode = if self.application == Application::RestrictedLowDelay {
370            OpusMode::CeltOnly
371        } else {
372            let equiv = compute_equiv_rate(
373                self.bitrate_bps,
374                self.channels,
375                frame_rate,
376                !self.use_cbr,
377                self.complexity,
378                self.packet_loss_perc,
379            );
380            let prev_was_celt = self.prev_enc_mode == Some(OpusMode::CeltOnly);
381            let has_prev_mode = self.prev_enc_mode.is_some();
382            let voice_est = match self.application {
383                Application::Voip => 115,
384                Application::Audio => 48,
385                Application::RestrictedLowDelay => 0,
386            };
387            let threshold = compute_mode_threshold(
388                self.application,
389                self.channels,
390                prev_was_celt,
391                has_prev_mode,
392                voice_est,
393            );
394            if equiv >= threshold && self.sampling_rate >= 24000 {
395                OpusMode::CeltOnly
396            } else {
397                OpusMode::SilkOnly
398            }
399        };
400
401        let curr_bw = self.bandwidth;
402        if mode == OpusMode::SilkOnly
403            && (curr_bw == Bandwidth::Superwideband || curr_bw == Bandwidth::Fullband)
404        {
405            mode = OpusMode::Hybrid;
406        }
407        if mode == OpusMode::Hybrid
408            && (curr_bw == Bandwidth::Narrowband
409                || curr_bw == Bandwidth::Mediumband
410                || curr_bw == Bandwidth::Wideband)
411        {
412            mode = OpusMode::SilkOnly;
413        }
414
415        if mode == OpusMode::CeltOnly {
416            match frame_rate {
417                400 | 200 | 100 | 50 => {}
418                _ => return Err("Unsupported frame size for CELT-only mode"),
419            }
420        }
421
422        if mode == OpusMode::Hybrid {
423            match frame_rate {
424                100 | 50 => {}
425                _ => return Err("Unsupported frame size for Hybrid mode"),
426            }
427        }
428
429        if mode == OpusMode::SilkOnly {
430            match frame_rate {
431                400 | 200 | 100 | 50 | 25 => {}
432                _ => return Err("Unsupported frame size for SILK-only mode"),
433            }
434        }
435
436        let toc = gen_toc(mode, frame_rate, self.bandwidth, self.channels);
437        output[0] = toc;
438
439        let target_bits =
440            (self.bitrate_bps as i64 * frame_size as i64 / self.sampling_rate as i64) as i32;
441        let cbr_bytes = ((target_bits + 4) / 8) as usize;
442        let max_data_bytes = output.len();
443
444        // Cap at the Opus per-packet maximum (RFC 6716); the range coder's buffer
445        // is heap-free and sized to this constant.
446        let n_bytes = cbr_bytes
447            .min(max_data_bytes)
448            .max(1)
449            .min(OPUS_MAX_PACKET_BYTES);
450
451        let init_rc_size = n_bytes - 1;
452        self.rc.reset_for_encode(init_rc_size as u32);
453
454        if mode == OpusMode::SilkOnly || mode == OpusMode::Hybrid {
455            let silk_fs_khz = if mode == OpusMode::Hybrid {
456                16
457            } else {
458                self.sampling_rate.min(16000) / 1000
459            };
460
461            let frame_ms = (frame_size as i32 * 1000) / self.sampling_rate;
462            if !self.silk_initialized || self.silk_enc.s_cmn.fs_khz != silk_fs_khz {
463                let silk_init_bitrate = (((n_bytes - 1) * 8) as i64 * self.sampling_rate as i64
464                    / frame_size as i64) as i32;
465                silk_control_encoder(
466                    &mut self.silk_enc,
467                    silk_fs_khz,
468                    frame_ms,
469                    silk_init_bitrate,
470                    self.complexity,
471                );
472                self.silk_enc.s_cmn.use_cbr = if self.use_cbr { 1 } else { 0 };
473
474                self.silk_enc.s_cmn.n_channels = self.channels as i32;
475                self.silk_initialized = true;
476                self.down2_state_first = [0; 2];
477                self.down2_state_second = [0; 2];
478                self.down2_3_state = [0; 6];
479                self.down_1_3_state = silk::resampler::SilkResamplerDown1_3::default();
480            }
481
482            self.silk_enc.s_cmn.use_in_band_fec = if self.use_inband_fec { 1 } else { 0 };
483            self.silk_enc.s_cmn.packet_loss_perc = self.packet_loss_perc.clamp(0, 100);
484
485            self.silk_enc.s_cmn.lbrr_enabled = if self.use_inband_fec { 1 } else { 0 };
486
487            if self.silk_enc.s_cmn.lbrr_gain_increases == 0 {
488                self.silk_enc.s_cmn.lbrr_gain_increases = 2;
489            }
490
491            let hp_freq_smth1 = if mode == OpusMode::CeltOnly {
492                silk_lin2log(60) << 8
493            } else {
494                self.silk_enc.s_cmn.variable_hp_smth1_q15
495            };
496
497            const VARIABLE_HP_SMTH_COEF2_Q16: i32 = 984;
498            self.variable_hp_smth2_q15 = silk_smlawb(
499                self.variable_hp_smth2_q15,
500                hp_freq_smth1 - self.variable_hp_smth2_q15,
501                VARIABLE_HP_SMTH_COEF2_Q16,
502            );
503
504            let cutoff_hz = silk_log2lin(silk_rshift(self.variable_hp_smth2_q15, 8));
505
506            let required_size = frame_size * self.channels;
507            self.buf_filtered.resize(required_size, 0);
508            if self.application == Application::Voip {
509                hp_cutoff(
510                    input,
511                    cutoff_hz,
512                    &mut self.buf_filtered,
513                    &mut self.hp_mem,
514                    frame_size,
515                    self.channels,
516                    self.sampling_rate,
517                );
518            } else {
519                for (i, &x) in input.iter().enumerate() {
520                    self.buf_filtered[i] = (x * 32768.0).clamp(-32768.0, 32767.0) as i16;
521                }
522            }
523
524            let input_i16 = &self.buf_filtered;
525
526            let silk_input: &[i16] = if mode == OpusMode::SilkOnly && self.sampling_rate > 16000 {
527                if self.sampling_rate == 48000 {
528                    let stage1_size = frame_size / 2;
529                    let mut stage1_buf = [0i16; 480];
530                    silk_resampler_down2(
531                        &mut self.down2_state_first,
532                        &mut stage1_buf[..stage1_size],
533                        input_i16,
534                        frame_size as i32,
535                    );
536                    let silk_frame_size = stage1_size * 2 / 3;
537                    self.buf_silk_input.resize(silk_frame_size, 0);
538                    silk_resampler_down2_3(
539                        &mut self.down2_3_state,
540                        &mut self.buf_silk_input,
541                        &stage1_buf[..stage1_size],
542                        stage1_size as i32,
543                    );
544                    &self.buf_silk_input
545                } else if self.sampling_rate == 24000 {
546                    let silk_frame_size = frame_size * 2 / 3;
547                    self.buf_silk_input.resize(silk_frame_size, 0);
548                    silk_resampler_down2_3(
549                        &mut self.down2_3_state,
550                        &mut self.buf_silk_input,
551                        input_i16,
552                        frame_size as i32,
553                    );
554                    &self.buf_silk_input
555                } else {
556                    input_i16
557                }
558            } else if mode == OpusMode::SilkOnly && self.channels == 2 {
559                let frame_length = input_i16.len() / 2;
560                self.buf_stereo_mid.resize(frame_length, 0);
561                self.buf_stereo_side.resize(frame_length, 0);
562                for i in 0..frame_length {
563                    let l = input_i16[2 * i] as i32;
564                    let r = input_i16[2 * i + 1] as i32;
565                    self.buf_stereo_mid[i] = ((l + r) / 2) as i16;
566                    self.buf_stereo_side[i] = (l - r) as i16;
567                }
568
569                self.silk_enc.stereo.side.resize(frame_length, 0);
570                self.silk_enc
571                    .stereo
572                    .side
573                    .copy_from_slice(&self.buf_stereo_side[..frame_length]);
574                &self.buf_stereo_mid
575            } else if mode == OpusMode::Hybrid && self.sampling_rate > 16000 {
576                if self.sampling_rate == 48000 {
577                    let silk_frame_size = frame_size / 3;
578                    self.buf_silk_input.resize(silk_frame_size, 0);
579                    silk::resampler::silk_resampler_down_1_3(
580                        &mut self.down_1_3_state,
581                        &mut self.buf_silk_input,
582                        input_i16,
583                    );
584                } else {
585                    let silk_frame_size = frame_size * 2 / 3;
586                    self.buf_silk_input.resize(silk_frame_size, 0);
587                    silk_resampler_down2_3(
588                        &mut self.down2_3_state,
589                        &mut self.buf_silk_input,
590                        input_i16,
591                        frame_size as i32,
592                    );
593                }
594                &self.buf_silk_input
595            } else {
596                input_i16
597            };
598
599            let mut pn_bytes = 0;
600
601            let silk_rate_for_calc = if mode == OpusMode::Hybrid {
602                16000
603            } else {
604                self.sampling_rate
605            };
606            let silk_frame_len = silk_input.len();
607
608            let silk_bitrate = if mode == OpusMode::Hybrid {
609                let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
610                let frame20ms = frame_duration_ms >= 20;
611                compute_silk_rate_for_hybrid(self.bitrate_bps, frame20ms)
612            } else {
613                (8i64 * (n_bytes - 1) as i64 * silk_rate_for_calc as i64 / silk_frame_len as i64)
614                    as i32
615            };
616            let silk_max_bits = if mode == OpusMode::Hybrid {
617                let total_max_bits = ((n_bytes - 1) * 8) as i32;
618                if self.use_cbr {
619                    let silk_bits = (silk_bitrate as i64 * silk_frame_len as i64
620                        / silk_rate_for_calc as i64) as i32;
621                    let other_bits = 0i32.max(total_max_bits - silk_bits);
622                    0i32.max(total_max_bits - other_bits * 3 / 4)
623                } else {
624                    let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
625                    let frame20ms = frame_duration_ms >= 20;
626                    let max_bit_rate = compute_silk_rate_for_hybrid(
627                        total_max_bits * self.sampling_rate / frame_size as i32,
628                        frame20ms,
629                    );
630                    max_bit_rate * frame_size as i32 / self.sampling_rate
631                }
632            } else {
633                ((n_bytes - 1) * 8) as i32
634            };
635            let silk_use_cbr = if mode == OpusMode::Hybrid && self.use_cbr {
636                0
637            } else if self.use_cbr {
638                1
639            } else {
640                0
641            };
642            let ret = silk_encode(
643                &mut self.silk_enc,
644                silk_input,
645                silk_input.len(),
646                &mut self.rc,
647                &mut pn_bytes,
648                silk_bitrate,
649                silk_max_bits,
650                silk_use_cbr,
651                1,
652            );
653            if ret != 0 {
654                return Err("SILK encoding failed");
655            }
656        }
657
658        if mode == OpusMode::Hybrid {
659            self.rc.encode_bit_logp(false, 12); // redundancy = 0
660        }
661
662        if mode == OpusMode::Hybrid {
663            let nb_compr_bytes = (n_bytes - 1) as u32;
664            self.rc.shrink(nb_compr_bytes);
665        }
666
667        let silk_ret_bytes = if mode == OpusMode::SilkOnly {
668            ((self.rc.tell() + 7) >> 3) as usize
669        } else {
670            0
671        };
672
673        if mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid {
674            self.celt_enc.complexity = self.complexity;
675            let start_band = if mode == OpusMode::Hybrid { 17 } else { 0 };
676            let total_packet_bits = ((n_bytes - 1) * 8) as i32;
677
678            let celt_input: &[f32] = if self.channels == 1 {
679                input
680            } else {
681                let n = frame_size * self.channels;
682                self.buf_celt_input.resize(n, 0.0);
683                for i in 0..frame_size {
684                    for ch in 0..self.channels {
685                        self.buf_celt_input[ch * frame_size + i] = input[i * self.channels + ch];
686                    }
687                }
688                &self.buf_celt_input
689            };
690
691            if self.rc.tell() <= total_packet_bits {
692                self.celt_enc.encode_with_budget(
693                    celt_input,
694                    frame_size,
695                    &mut self.rc,
696                    start_band,
697                    total_packet_bits,
698                );
699            }
700        }
701
702        self.rc.done();
703
704        if self.rc.error != 0 {
705            return Err("Range coder buffer overflow: encoded data exceeds packet budget");
706        }
707
708        if mode == OpusMode::SilkOnly {
709            let mut ret = silk_ret_bytes.min(self.rc.storage as usize);
710            while ret > 2 && self.rc.buf[ret - 1] == 0 {
711                ret -= 1;
712            }
713
714            let target_total = if self.use_cbr {
715                n_bytes.min(output.len())
716            } else {
717                (ret + 1).min(output.len())
718            };
719
720            let silk_len = ret;
721
722            if !self.use_cbr || silk_len + 1 >= target_total {
723                // VBR or payload fills the target: simple code 0 packet
724                output[0] = toc;
725                let copy_len = silk_len.min(target_total - 1);
726                output[1..1 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
727                return Ok((copy_len + 1).min(output.len()));
728            }
729
730            output[0] = toc | 0x03;
731
732            if silk_len + 2 >= target_total {
733                output[1] = 0x01;
734                let copy_len = (target_total - 2).min(silk_len);
735                output[2..2 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
736                self.prev_enc_mode = Some(mode);
737                return Ok(target_total.min(output.len()));
738            }
739
740            let pad_amount = target_total - silk_len - 2;
741            output[1] = 0x41;
742
743            let nb_255s = (pad_amount - 1) / 255;
744            let mut ptr = 2;
745            for _ in 0..nb_255s {
746                output[ptr] = 255;
747                ptr += 1;
748            }
749            output[ptr] = (pad_amount - 255 * nb_255s - 1) as u8;
750            ptr += 1;
751
752            output[ptr..ptr + silk_len].copy_from_slice(&self.rc.buf[..silk_len]);
753            ptr += silk_len;
754
755            let fill_end = target_total.min(output.len());
756            for byte in output[ptr..fill_end].iter_mut() {
757                *byte = 0;
758            }
759
760            self.prev_enc_mode = Some(mode);
761            return Ok(target_total.min(output.len()));
762        }
763
764        let payload_len = n_bytes - 1;
765        output[1..1 + payload_len].copy_from_slice(&self.rc.buf[..payload_len]);
766        self.prev_enc_mode = Some(mode);
767        Ok(n_bytes)
768    }
769}
770
771pub struct OpusDecoder {
772    celt_dec: CeltDecoder,
773    silk_dec: silk::dec_api::SilkDecoder,
774    sampling_rate: i32,
775    channels: usize,
776
777    prev_mode: Option<OpusMode>,
778
779    /// Whether the previous frame had redundancy (mode transition marker).
780    prev_redundancy: bool,
781    frame_size: usize,
782
783    bandwidth: Bandwidth,
784
785    stream_channels: usize,
786
787    silk_resampler: silk::resampler::SilkResampler,
788
789    /// Second resampler instance for stereo channel 1.
790    silk_resampler_2: silk::resampler::SilkResampler,
791
792    prev_internal_rate: i32,
793
794    pub hybrid_skip_celt: bool,
795
796    w_pcm_i16: FixedVec<i16, OPUS_PCM_I16>,
797    w_silk_out: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
798    w_pcm_resampled: FixedVec<i16, OPUS_SUBFRAME_SCRATCH>,
799    w_celt_planar: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
800    w_celt_out: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
801
802    /// Tail of the previous frame's output, used for smooth_fade at mode
803    /// transitions (libopus pcm_transition + smooth_fade).
804    prev_pcm_tail: FixedVec<f32, OPUS_PCM_TAIL>,
805}
806
807impl OpusDecoder {
808    pub fn new(sampling_rate: i32, channels: usize) -> Result<Self, &'static str> {
809        if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
810            return Err("Invalid sampling rate");
811        }
812        if ![1, 2].contains(&channels) {
813            return Err("Invalid number of channels");
814        }
815
816        let mode = modes::default_mode();
817        let celt_dec = CeltDecoder::new(mode, channels, sampling_rate);
818
819        let mut silk_dec = silk::dec_api::SilkDecoder::new();
820        silk_dec.init(sampling_rate.min(16000), channels as i32);
821        silk_dec.channel_state[0].fs_api_hz = sampling_rate;
822
823        Ok(Self {
824            celt_dec,
825            silk_dec,
826            sampling_rate,
827            channels,
828            prev_mode: None,
829            prev_redundancy: false,
830            frame_size: 0,
831            bandwidth: Bandwidth::Auto,
832            stream_channels: channels,
833            silk_resampler: silk::resampler::SilkResampler::default(),
834            silk_resampler_2: silk::resampler::SilkResampler::default(),
835            prev_internal_rate: 0,
836            hybrid_skip_celt: false,
837
838            w_pcm_i16: FixedVec::from_value(0i16, 960 * channels),
839
840            w_silk_out: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
841            w_pcm_resampled: FixedVec::from_value(0i16, OPUS_MAX_SUBFRAME * channels),
842            w_celt_planar: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
843            w_celt_out: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
844
845            prev_pcm_tail: FixedVec::from_value(0.0f32, 240 * channels),
846        })
847    }
848
849    pub fn decode(
850        &mut self,
851        input: &[u8],
852        frame_size: usize,
853        output: &mut [f32],
854    ) -> Result<usize, &'static str> {
855        if input.is_empty() {
856            return Err("Input packet empty");
857        }
858
859        let toc = input[0];
860        let mode = mode_from_toc(toc);
861        let packet_channels = channels_from_toc(toc);
862        let bandwidth = bandwidth_from_toc(toc);
863        let frame_duration_ms = frame_duration_ms_from_toc(toc);
864
865        // A packet of 0 or 1 bytes (ToC only) is a lost/DTX frame. libopus
866        // triggers PLC in this case (opus_decoder.c:315-321). We decode the
867        // frame using the previous mode's concealment.
868        let lost_frame = input.len() <= 1;
869
870        if packet_channels != self.channels {
871            return Err("Channel count mismatch between packet and decoder");
872        }
873
874        let code = toc & 0x03;
875        let frame_count: usize;
876        let frame_payloads: FixedVec<&[u8], OPUS_MAX_PACKET_FRAMES>;
877
878        match code {
879            0 => {
880                frame_count = 1;
881                frame_payloads = FixedVec::from_slice(&[&input[1..]]);
882            }
883            1 => {
884                frame_count = 2;
885                let data_len = input.len() - 1;
886                // RFC 6716 §3.2.1: code 1 carries two equal-size (CBR) frames,
887                // so the payload length must be even. libopus rejects odd lengths.
888                if data_len % 2 != 0 {
889                    return Err("Code 1: payload length must be even");
890                }
891                let half = data_len / 2;
892                if half == 0 {
893                    return Err("Code 1: empty frame");
894                }
895                frame_payloads = FixedVec::from_slice(&[&input[1..1 + half], &input[1 + half..]]);
896            }
897            2 => {
898                frame_count = 2;
899                let data = &input[1..];
900                if data.is_empty() {
901                    return Err("Code 2 packet has no data");
902                }
903                let (first_len, header_size) = parse_frame_size(data)?;
904                if header_size + first_len > data.len() {
905                    return Err("Code 2: first frame size exceeds packet");
906                }
907                frame_payloads = FixedVec::from_slice(&[
908                    &data[header_size..header_size + first_len],
909                    &data[header_size + first_len..],
910                ]);
911            }
912            3 => {
913                if input.len() < 2 {
914                    return Err("Code 3 packet too short");
915                }
916                let count_byte = input[1];
917                let n_frames = (count_byte & 0x3F) as usize;
918                if n_frames < 1 || n_frames > 48 {
919                    return Err("Code 3: invalid frame count");
920                }
921                frame_count = n_frames;
922                // Bit 6 = padding flag, bit 7 = VBR flag (RFC 6716 §3.2.1).
923                let padding_flag = (count_byte & 0x40) != 0;
924                let vbr = (count_byte & 0x80) != 0;
925
926                // Parse the optional padding length bytes that follow the count
927                // byte. The padding *content* (pad_len bytes) lives at the end of
928                // the packet and is not part of any frame.
929                let mut ptr = 2usize;
930                let mut pad_len = 0usize;
931                if padding_flag {
932                    loop {
933                        if ptr >= input.len() {
934                            return Err("Code 3: padding overflow");
935                        }
936                        let p = input[ptr] as usize;
937                        ptr += 1;
938                        if p == 255 {
939                            pad_len += 254;
940                        } else {
941                            pad_len += p;
942                            break;
943                        }
944                    }
945                }
946                if ptr + pad_len > input.len() {
947                    return Err("Code 3: padding exceeds packet");
948                }
949                let payload_end = input.len() - pad_len;
950                let payload = &input[ptr..payload_end];
951
952                let mut payloads: FixedVec<&[u8], OPUS_MAX_PACKET_FRAMES> = FixedVec::new();
953                if frame_count == 1 {
954                    // Single frame: the entire payload region is the frame, both
955                    // for VBR and CBR (no length prefix is present).
956                    payloads.push(payload);
957                } else if vbr {
958                    // VBR (V=1): per-frame lengths for all frames except the last,
959                    // which takes the remaining bytes (RFC 6716 §3.2.1).
960                    let mut cursor = 0usize;
961                    for i in 0..frame_count {
962                        if i + 1 < frame_count {
963                            if cursor >= payload.len() {
964                                return Err("Code 3: unexpected end in VBR header");
965                            }
966                            let (frame_len, header_bytes) =
967                                parse_frame_size(&payload[cursor..])?;
968                            cursor += header_bytes;
969                            if cursor + frame_len > payload.len() {
970                                return Err("Code 3: frame length exceeds packet");
971                            }
972                            payloads.push(&payload[cursor..cursor + frame_len]);
973                            cursor += frame_len;
974                        } else {
975                            // Last frame: remaining bytes, no length prefix.
976                            if cursor > payload.len() {
977                                return Err("Code 3: no data for last frame");
978                            }
979                            payloads.push(&payload[cursor..]);
980                        }
981                    }
982                } else {
983                    // CBR (V=0): remaining bytes are split equally into M frames
984                    // (RFC 6716 §3.2.1: "the remaining bytes are split into M
985                    // equal chunks").
986                    if payload.len() % frame_count != 0 {
987                        return Err("Code 3 CBR: payload not divisible by frame count");
988                    }
989                    let frame_len = payload.len() / frame_count;
990                    for i in 0..frame_count {
991                        payloads.push(&payload[i * frame_len..(i + 1) * frame_len]);
992                    }
993                }
994                frame_payloads = payloads;
995            }
996            _ => unreachable!(),
997        }
998
999        self.frame_size = frame_size;
1000        self.bandwidth = bandwidth;
1001        self.stream_channels = packet_channels;
1002
1003        // Derive the actual per-frame sample count from the TOC, not from the
1004        // caller's frame_size. This prevents panics in bands.rs/celt.rs when
1005        // the caller passes a mismatched frame_size (issue #7 sub-item 1):
1006        // the internal decoders always get the correct geometry.
1007        let toc_frame_size = frame_samples_from_toc(toc, self.sampling_rate)
1008            .ok_or("Invalid TOC for sampling rate")?;
1009        let decoded_total = toc_frame_size * frame_count;
1010        if frame_size < decoded_total {
1011            return Err("frame_size too small for packet");
1012        }
1013        if output.len() < decoded_total * self.channels {
1014            return Err("Output buffer too small for packet");
1015        }
1016        // Zero-fill any extra space the caller provided beyond what the packet
1017        // actually produces, so stale data is never left in the buffer.
1018        if output.len() > decoded_total * self.channels {
1019            for v in &mut output[decoded_total * self.channels..] {
1020                *v = 0.0;
1021            }
1022        }
1023        let sub_frame_size = toc_frame_size;
1024        let sub_output_len = sub_frame_size * self.channels;
1025
1026        // Detect mode transition and reset CELT decoder state to prevent
1027        // cross-mode artifacts (libopus opus_decoder.c:602-604).
1028        // This is the primary fix for issue #8/#9 alignment divergence:
1029        // stale CELT MDCT/prefilter state at SILK↔CELT boundaries causes
1030        // discontinuities that accumulate across transitions.
1031        let mode_transition = match self.prev_mode {
1032            Some(prev) if prev != mode && !self.prev_redundancy => true,
1033            _ => false,
1034        };
1035        if mode_transition {
1036            self.celt_dec.reset_state();
1037        }
1038
1039        // Generate SILK PLC audio for the mode-transition bridge. libopus
1040        // synthesizes 5ms (F5) of pitch-extrapolated audio in the OLD mode
1041        // (opus_decoder.c:387-391) and crossfades it with the new frame. We
1042        // reuse the F5-sized prev_pcm_tail buffer for this bridge.
1043        let f5_bridge = self.sampling_rate as usize / 200; // F5 = Fs/200
1044        if mode_transition
1045            && f5_bridge > 0
1046            && matches!(
1047                self.prev_mode,
1048                Some(OpusMode::SilkOnly) | Some(OpusMode::Hybrid)
1049            )
1050            && self.prev_internal_rate > 0
1051        {
1052            let internal_rate = self.prev_internal_rate;
1053            let plc_internal_len = (10 * internal_rate / 1000) as usize;
1054            let mut plc_rc = RangeCoder::new_decoder(&[]);
1055            let mut plc_i16: FixedVec<i16, OPUS_PCM_I16> =
1056                FixedVec::from_value(0i16, plc_internal_len * self.channels);
1057            let n = self.silk_dec.decode(
1058                &mut plc_rc,
1059                &mut plc_i16,
1060                silk::decode_frame::FLAG_PACKET_LOST,
1061                true,
1062                10,
1063                internal_rate,
1064            );
1065            if n > 0 {
1066                let bridge_ch = f5_bridge * self.channels;
1067                let bridge_len = bridge_ch.min(self.prev_pcm_tail.len());
1068                if internal_rate == self.sampling_rate {
1069                    // No resampling: copy PLC samples directly (ch0 planar).
1070                    let n_us = n as usize;
1071                    for ch in 0..self.channels {
1072                        let src_base = ch * n_us;
1073                        for i in 0..(bridge_len / self.channels).min(n_us) {
1074                            let dst = i * self.channels + ch;
1075                            if dst < bridge_len {
1076                                self.prev_pcm_tail[dst] = plc_i16[src_base + i] as f32 / 32768.0;
1077                            }
1078                        }
1079                    }
1080                } else if self.silk_resampler.is_initialized() {
1081                    // Resample channel 0 to the API rate for the bridge.
1082                    let ratio = self.sampling_rate as f64 / internal_rate as f64;
1083                    let out_len = ((n as f64 * ratio) as usize).min(f5_bridge);
1084                    let n_us = n as usize;
1085                    let mut resampled: FixedVec<i16, OPUS_MAX_FRAME> = FixedVec::from_value(0i16, out_len);
1086                    self.silk_resampler.process(
1087                        &mut resampled,
1088                        &plc_i16[..n_us],
1089                        n,
1090                    );
1091                    for i in 0..out_len {
1092                        if i < bridge_len / self.channels {
1093                            for ch in 0..self.channels {
1094                                self.prev_pcm_tail[i * self.channels + ch] =
1095                                    resampled[i] as f32 / 32768.0;
1096                            }
1097                        }
1098                    }
1099                }
1100            }
1101        }
1102
1103        // Track whether this packet uses Hybrid redundancy.
1104        let mut has_redundancy = false;
1105
1106        match mode {
1107            OpusMode::SilkOnly => {
1108                let internal_sample_rate = match bandwidth {
1109                    Bandwidth::Narrowband => 8000,
1110                    Bandwidth::Mediumband => 12000,
1111                    Bandwidth::Wideband => 16000,
1112                    _ => 16000,
1113                };
1114                let internal_frame_size =
1115                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
1116
1117                if self.sampling_rate != internal_sample_rate
1118                    && internal_sample_rate != self.prev_internal_rate
1119                {
1120                    self.silk_resampler
1121                        .init(internal_sample_rate, self.sampling_rate);
1122                    self.silk_resampler_2
1123                        .init(internal_sample_rate, self.sampling_rate);
1124                }
1125                // Always track the SILK internal rate so the mode-transition
1126                // PLC bridge can be generated (even when no resampling is
1127                // needed, e.g. 16kHz decoder + SILK WB).
1128                self.prev_internal_rate = internal_sample_rate;
1129
1130                for (fi, payload) in frame_payloads.iter().enumerate() {
1131                    let mut rc = RangeCoder::new_decoder(payload);
1132                    let pcm_i16_len = internal_frame_size * self.channels;
1133                    debug_assert!(pcm_i16_len <= self.w_pcm_i16.len());
1134
1135                    let ret = {
1136                        let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1137                        let lost_flag = if lost_frame {
1138                            silk::decode_frame::FLAG_PACKET_LOST
1139                        } else {
1140                            silk::decode_frame::FLAG_DECODE_NORMAL
1141                        };
1142                        silk_dec.decode(
1143                            &mut rc,
1144                            &mut pcm_i16[..pcm_i16_len],
1145                            lost_flag,
1146                            true,
1147                            frame_duration_ms,
1148                            internal_sample_rate,
1149                        )
1150                    };
1151
1152                    if ret < 0 {
1153                        return Err("SILK decoding failed");
1154                    }
1155
1156                    let decoded_samples = ret as usize;
1157                    let out_start = fi * sub_output_len;
1158
1159                    // SILK decoder outputs planar: ch0 at [0..fl], ch1 at [fl..2*fl].
1160                    if self.sampling_rate == internal_sample_rate {
1161                        let frames = decoded_samples.min(sub_frame_size);
1162                        for i in 0..frames {
1163                            for ch in 0..self.channels {
1164                                let src = if ch == 0 { i } else { internal_frame_size + i };
1165                                let v = self.w_pcm_i16[src] as f32 / 32768.0;
1166                                let idx = out_start + i * self.channels + ch;
1167                                if idx < output.len() {
1168                                    output[idx] = v;
1169                                }
1170                            }
1171                        }
1172                    } else {
1173                        let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1174                        let out_len =
1175                            ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
1176                        debug_assert!(out_len * self.channels <= self.w_pcm_resampled.len());
1177                        // Resample channel 0.
1178                        {
1179                            let (res, inp, out) = (
1180                                &mut self.silk_resampler,
1181                                &self.w_pcm_i16,
1182                                &mut self.w_pcm_resampled,
1183                            );
1184                            res.process(
1185                                &mut out[..out_len],
1186                                &inp[..decoded_samples],
1187                                decoded_samples as i32,
1188                            );
1189                        }
1190                        // Resample channel 1 (stereo only).
1191                        if self.channels == 2 {
1192                            let (res, inp, out) = (
1193                                &mut self.silk_resampler_2,
1194                                &self.w_pcm_i16,
1195                                &mut self.w_pcm_resampled,
1196                            );
1197                            res.process(
1198                                &mut out[out_len..2 * out_len],
1199                                &inp[internal_frame_size..internal_frame_size + decoded_samples],
1200                                decoded_samples as i32,
1201                            );
1202                        }
1203                        let frames = out_len.min(sub_frame_size);
1204                        for i in 0..frames {
1205                            for ch in 0..self.channels {
1206                                let v = self.w_pcm_resampled[ch * out_len + i] as f32 / 32768.0;
1207                                let idx = out_start + i * self.channels + ch;
1208                                if idx < output.len() {
1209                                    output[idx] = v;
1210                                }
1211                            }
1212                        }
1213                    }
1214                }
1215                decoded_total
1216            }
1217
1218            OpusMode::CeltOnly => {
1219                let celt_end_band = self.celt_end_band_from_toc(toc);
1220
1221                for (fi, payload) in frame_payloads.iter().enumerate() {
1222                    let mut rc = RangeCoder::new_decoder(payload);
1223                    let total_bits = (payload.len() * 8) as i32;
1224                    let needed = sub_frame_size * self.channels;
1225                    let out_start = fi * needed;
1226                    let out_end = (out_start + needed).min(output.len());
1227
1228                    if output.len() < out_end {
1229                        return Err("Output buffer too small");
1230                    }
1231
1232                    if self.channels == 1 {
1233                        self.celt_dec.decode_from_range_coder_with_band_range(
1234                            &mut rc,
1235                            total_bits,
1236                            sub_frame_size,
1237                            &mut output[out_start..out_end],
1238                            0,
1239                            celt_end_band,
1240                        );
1241                        for sample in &mut output[out_start..out_end] {
1242                            *sample = sample.clamp(-1.0, 1.0);
1243                        }
1244                    } else {
1245                        self.celt_dec.decode_from_range_coder_with_band_range(
1246                            &mut rc,
1247                            total_bits,
1248                            sub_frame_size,
1249                            &mut self.w_celt_planar[..needed],
1250                            0,
1251                            celt_end_band,
1252                        );
1253                        for i in 0..sub_frame_size {
1254                            for ch in 0..self.channels {
1255                                let idx = out_start + i * self.channels + ch;
1256                                output[idx] =
1257                                    self.w_celt_planar[ch * sub_frame_size + i].clamp(-1.0, 1.0);
1258                            }
1259                        }
1260                    }
1261                }
1262                decoded_total
1263            }
1264
1265            OpusMode::Hybrid => {
1266                let internal_sample_rate = 16000;
1267                let internal_frame_size =
1268                    (frame_duration_ms * internal_sample_rate / 1000) as usize;
1269                let celt_end_band = self.celt_end_band_from_toc(toc);
1270
1271                if self.sampling_rate != internal_sample_rate
1272                    && internal_sample_rate != self.prev_internal_rate
1273                {
1274                    self.silk_resampler
1275                        .init(internal_sample_rate, self.sampling_rate);
1276                    self.silk_resampler_2
1277                        .init(internal_sample_rate, self.sampling_rate);
1278                }
1279                self.prev_internal_rate = internal_sample_rate;
1280
1281                for (fi, payload) in frame_payloads.iter().enumerate() {
1282                    let mut rc = RangeCoder::new_decoder(payload);
1283                    let pcm_silk_i16_len = internal_frame_size * self.channels;
1284                    debug_assert!(pcm_silk_i16_len <= self.w_pcm_i16.len());
1285
1286                    let ret = {
1287                        let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1288                        let lost_flag = if lost_frame {
1289                            silk::decode_frame::FLAG_PACKET_LOST
1290                        } else {
1291                            silk::decode_frame::FLAG_DECODE_NORMAL
1292                        };
1293                        silk_dec.decode(
1294                            &mut rc,
1295                            &mut pcm_i16[..pcm_silk_i16_len],
1296                            lost_flag,
1297                            true,
1298                            frame_duration_ms,
1299                            internal_sample_rate,
1300                        )
1301                    };
1302
1303                    if ret < 0 {
1304                        return Err("SILK decoding failed");
1305                    }
1306
1307                    let silk_out_len = sub_frame_size * self.channels;
1308                    self.w_silk_out[..silk_out_len].fill(0.0);
1309                    if ret > 0 {
1310                        let decoded_samples = ret as usize;
1311                        // SILK decoder outputs planar: ch0 at [0..fl], ch1 at [fl..2*fl].
1312                        if self.sampling_rate == internal_sample_rate {
1313                            let frames = decoded_samples.min(sub_frame_size);
1314                            for i in 0..frames {
1315                                for ch in 0..self.channels {
1316                                    let src = if ch == 0 { i } else { internal_frame_size + i };
1317                                    let v = self.w_pcm_i16[src] as f32 / 32768.0;
1318                                    let idx = i * self.channels + ch;
1319                                    if idx < silk_out_len {
1320                                        self.w_silk_out[idx] = v;
1321                                    }
1322                                }
1323                            }
1324                        } else {
1325                            let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1326                            let out_len =
1327                                ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
1328                            debug_assert!(out_len * self.channels <= self.w_pcm_resampled.len());
1329                            // Resample channel 0.
1330                            {
1331                                let (res, inp, out) = (
1332                                    &mut self.silk_resampler,
1333                                    &self.w_pcm_i16,
1334                                    &mut self.w_pcm_resampled,
1335                                );
1336                                res.process(
1337                                    &mut out[..out_len],
1338                                    &inp[..decoded_samples],
1339                                    decoded_samples as i32,
1340                                );
1341                            }
1342                            // Resample channel 1 (stereo only).
1343                            if self.channels == 2 {
1344                                let (res, inp, out) = (
1345                                    &mut self.silk_resampler_2,
1346                                    &self.w_pcm_i16,
1347                                    &mut self.w_pcm_resampled,
1348                                );
1349                                res.process(
1350                                    &mut out[out_len..2 * out_len],
1351                                    &inp[internal_frame_size..internal_frame_size + decoded_samples],
1352                                    decoded_samples as i32,
1353                                );
1354                            }
1355                            let frames = out_len.min(sub_frame_size);
1356                            for i in 0..frames {
1357                                for ch in 0..self.channels {
1358                                    let v = self.w_pcm_resampled[ch * out_len + i] as f32 / 32768.0;
1359                                    let idx = i * self.channels + ch;
1360                                    if idx < silk_out_len {
1361                                        self.w_silk_out[idx] = v;
1362                                    }
1363                                }
1364                            }
1365                        }
1366                    }
1367
1368                    let total_bits = (payload.len() * 8) as i32;
1369                    let redundancy = rc.decode_bit_logp(12);
1370                    let skip_celt = if redundancy {
1371                        let _celt_to_silk = rc.decode_bit_logp(1);
1372                        has_redundancy = true;
1373                        // When redundancy is present, the redundant CELT frame
1374                        // provides the transition audio. We skip the main CELT
1375                        // decode for this sub-frame (the SILK output stands alone)
1376                        // — a simplified version of libopus's behaviour where the
1377                        // redundant frame is decoded separately and crossfaded.
1378                        true
1379                    } else {
1380                        false
1381                    };
1382
1383                    if skip_celt {
1384                        self.w_celt_out[..silk_out_len].fill(0.0);
1385                    } else {
1386                        let (celt_dec, celt_planar) = (&mut self.celt_dec, &mut self.w_celt_planar);
1387                        celt_dec.decode_from_range_coder_with_band_range(
1388                            &mut rc,
1389                            total_bits,
1390                            sub_frame_size,
1391                            &mut celt_planar[..silk_out_len],
1392                            17,
1393                            celt_end_band,
1394                        );
1395
1396                        if self.channels == 1 {
1397                            self.w_celt_out[..silk_out_len]
1398                                .copy_from_slice(&self.w_celt_planar[..silk_out_len]);
1399                        } else {
1400                            for i in 0..sub_frame_size {
1401                                for ch in 0..self.channels {
1402                                    self.w_celt_out[i * self.channels + ch] =
1403                                        self.w_celt_planar[ch * sub_frame_size + i];
1404                                }
1405                            }
1406                        }
1407                    }
1408
1409                    let out_start = fi * silk_out_len;
1410                    let total = silk_out_len.min(output.len() - out_start);
1411                    for j in 0..total {
1412                        output[out_start + j] =
1413                            (self.w_silk_out[j] + self.w_celt_out[j]).clamp(-1.0, 1.0);
1414                    }
1415                }
1416                decoded_total
1417            }
1418        };
1419
1420        // Apply PLC-style bridging at mode transitions (libopus
1421        // opus_decoder.c:660-679). The first F2_5 of the output is replaced
1422        // with the previous frame's tail (PLC bridge), and the next F2_5 is
1423        // crossfaded between the bridge and the new frame's CELT output.
1424        // F5 = Fs/200, F2_5 = Fs/400.
1425        let f2_5 = self.sampling_rate as usize / 400;
1426        let f5 = f2_5 * 2;
1427        if mode_transition && f5 > 0 && decoded_total >= f5 {
1428            let window = modes::default_mode().window;
1429            let inc = (48000 / self.sampling_rate) as usize;
1430            let f2_5_ch = f2_5 * self.channels;
1431            let f5_ch = f5 * self.channels;
1432            // First F2_5: pure bridging audio from previous frame's tail.
1433            output[..f2_5_ch].copy_from_slice(&self.prev_pcm_tail[..f2_5_ch]);
1434            // Next F2_5: crossfade bridge → new CELT output.
1435            let new_mid: FixedVec<f32, OPUS_PCM_TAIL> = FixedVec::from_slice(&output[f2_5_ch..f5_ch]);
1436            smooth_fade(
1437                &self.prev_pcm_tail[f2_5_ch..f5_ch],
1438                &new_mid,
1439                &mut output[f2_5_ch..f5_ch],
1440                f2_5,
1441                self.channels,
1442                window,
1443                inc,
1444            );
1445        }
1446
1447        // Save the tail of this frame for the next transition (F5 samples).
1448        let tail_len = f5 * self.channels;
1449        let out_total = decoded_total * self.channels;
1450        if out_total >= tail_len && tail_len <= self.prev_pcm_tail.len() {
1451            self.prev_pcm_tail[..tail_len]
1452                .copy_from_slice(&output[out_total - tail_len..out_total]);
1453        }
1454
1455        self.prev_mode = Some(mode);
1456        self.prev_redundancy = has_redundancy;
1457        Ok(decoded_total)
1458    }
1459}
1460
1461impl OpusDecoder {
1462    #[inline(always)]
1463    fn celt_end_band_from_toc(&self, toc: u8) -> usize {
1464        let mode = modes::default_mode();
1465        let top = mode.eff_ebands;
1466        if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
1467            const FROM_OPUS_TABLE: [u8; 16] = [
1468                0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
1469                0x10, 0x18,
1470            ];
1471            let idx = ((toc >> 3) - 16) as usize;
1472            let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
1473            let trim = (data0 >> 5) as usize;
1474            return top.saturating_sub(2 * trim).max(1);
1475        }
1476        top
1477    }
1478}
1479
1480fn frame_rate_from_params(sampling_rate: i32, frame_size: usize) -> Option<i32> {
1481    let frame_size = frame_size as i32;
1482    if frame_size == 0 || sampling_rate % frame_size != 0 {
1483        return None;
1484    }
1485    Some(sampling_rate / frame_size)
1486}
1487
1488fn gen_toc(mode: OpusMode, frame_rate: i32, bandwidth: Bandwidth, channels: usize) -> u8 {
1489    let mut rate = frame_rate;
1490    let mut period = 0;
1491    while rate < 400 {
1492        rate <<= 1;
1493        period += 1;
1494    }
1495
1496    let mut toc = match mode {
1497        OpusMode::SilkOnly => {
1498            let bw = (bandwidth as i32 - Bandwidth::Narrowband as i32) << 5;
1499            let per = (period - 2) << 3;
1500            (bw | per) as u8
1501        }
1502        OpusMode::CeltOnly => {
1503            let mut tmp = bandwidth as i32 - Bandwidth::Mediumband as i32;
1504            if tmp < 0 {
1505                tmp = 0;
1506            }
1507            let per = period << 3;
1508            (0x80 | (tmp << 5) | per) as u8
1509        }
1510        OpusMode::Hybrid => {
1511            let base_config = if bandwidth == Bandwidth::Superwideband {
1512                12
1513            } else {
1514                14
1515            };
1516            let period_offset = if frame_rate >= 100 { 0 } else { 1 };
1517            ((base_config + period_offset) << 3) as u8
1518        }
1519    };
1520
1521    if channels == 2 {
1522        toc |= 0x04;
1523    }
1524    toc
1525}
1526
1527fn mode_from_toc(toc: u8) -> OpusMode {
1528    if toc & 0x80 != 0 {
1529        OpusMode::CeltOnly
1530    } else if toc & 0x60 == 0x60 {
1531        OpusMode::Hybrid
1532    } else {
1533        OpusMode::SilkOnly
1534    }
1535}
1536
1537fn bandwidth_from_toc(toc: u8) -> Bandwidth {
1538    let mode = mode_from_toc(toc);
1539    match mode {
1540        OpusMode::SilkOnly => {
1541            let bw_bits = (toc >> 5) & 0x03;
1542            match bw_bits {
1543                0 => Bandwidth::Narrowband,
1544                1 => Bandwidth::Mediumband,
1545                2 => Bandwidth::Wideband,
1546                _ => Bandwidth::Wideband,
1547            }
1548        }
1549        OpusMode::Hybrid => {
1550            let bw_bit = (toc >> 4) & 0x01;
1551            if bw_bit == 0 {
1552                Bandwidth::Superwideband
1553            } else {
1554                Bandwidth::Fullband
1555            }
1556        }
1557        OpusMode::CeltOnly => {
1558            let bw_bits = (toc >> 5) & 0x03;
1559            match bw_bits {
1560                0 => Bandwidth::Mediumband,
1561                1 => Bandwidth::Wideband,
1562                2 => Bandwidth::Superwideband,
1563                3 => Bandwidth::Fullband,
1564                _ => Bandwidth::Fullband,
1565            }
1566        }
1567    }
1568}
1569
1570fn frame_duration_ms_from_toc(toc: u8) -> i32 {
1571    let mode = mode_from_toc(toc);
1572    match mode {
1573        OpusMode::SilkOnly => {
1574            let config = (toc >> 3) & 0x03;
1575            match config {
1576                0 => 10,
1577                1 => 20,
1578                2 => 40,
1579                3 => 60,
1580                _ => 20,
1581            }
1582        }
1583        OpusMode::Hybrid => {
1584            let config = (toc >> 3) & 0x01;
1585            if config == 0 { 10 } else { 20 }
1586        }
1587        OpusMode::CeltOnly => {
1588            let config = (toc >> 3) & 0x03;
1589            match config {
1590                0 => 2,
1591                1 => 5,
1592                2 => 10,
1593                3 => 20,
1594                _ => 20,
1595            }
1596        }
1597    }
1598}
1599
1600/// Compute the per-frame sample count implied by the TOC byte at a given
1601/// sampling rate. For CELT this uses the frame-rate derivation (which handles
1602/// the 2.5 ms case correctly, unlike integer millisecond arithmetic).
1603fn frame_samples_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
1604    let mode = mode_from_toc(toc);
1605    match mode {
1606        OpusMode::CeltOnly => {
1607            let period = ((toc >> 3) & 0x03) as i32;
1608            let frame_rate = 400 >> period;
1609            if frame_rate == 0 || sampling_rate % frame_rate != 0 {
1610                return None;
1611            }
1612            Some((sampling_rate / frame_rate) as usize)
1613        }
1614        OpusMode::SilkOnly | OpusMode::Hybrid => {
1615            let duration_ms = frame_duration_ms_from_toc(toc);
1616            Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1617        }
1618    }
1619}
1620
1621fn channels_from_toc(toc: u8) -> usize {
1622    if toc & 0x04 != 0 { 2 } else { 1 }
1623}
1624
1625/// Crossfade two signals using a squared-sine window (libopus smooth_fade).
1626/// `window` is the 120-sample CELT window at 48 kHz; `inc` = 48000/Fs strides it.
1627fn smooth_fade(
1628    in1: &[f32],
1629    in2: &[f32],
1630    out: &mut [f32],
1631    overlap: usize,
1632    channels: usize,
1633    window: &[f32],
1634    inc: usize,
1635) {
1636    for c in 0..channels {
1637        for i in 0..overlap {
1638            let wi = i * inc;
1639            if wi >= window.len() {
1640                break;
1641            }
1642            let w = window[wi] * window[wi];
1643            out[i * channels + c] = w * in2[i * channels + c] + (1.0 - w) * in1[i * channels + c];
1644        }
1645    }
1646}
1647
1648/// Parse an Opus frame length per RFC 6716 §3.2.1, identical to libopus
1649/// `parse_size()`:
1650///   - `0`: no frame (DTX / lost packet)
1651///   - `1..=251`: length of the frame in bytes (one byte consumed)
1652///   - `252..=255`: a second byte is read; length = `second*4 + first`
1653///
1654/// Returns `(length, bytes_consumed)`.
1655fn parse_frame_size(data: &[u8]) -> Result<(usize, usize), &'static str> {
1656    let first = *data.first().ok_or("truncated frame length")? as usize;
1657    if first < 252 {
1658        Ok((first, 1))
1659    } else {
1660        let second = *data.get(1).ok_or("truncated frame length")? as usize;
1661        Ok((second * 4 + first, 2))
1662    }
1663}
1664
1665#[cfg(all(test, feature = "std"))]
1666mod tests {
1667    use super::*;
1668
1669    fn frame_size_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
1670        let mode = mode_from_toc(toc);
1671        match mode {
1672            OpusMode::CeltOnly => {
1673                let period = ((toc >> 3) & 0x03) as i32;
1674                let frame_rate = 400 >> period;
1675                if frame_rate == 0 || sampling_rate % frame_rate != 0 {
1676                    return None;
1677                }
1678                Some((sampling_rate / frame_rate) as usize)
1679            }
1680            OpusMode::SilkOnly => {
1681                let duration_ms = frame_duration_ms_from_toc(toc);
1682                Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1683            }
1684            OpusMode::Hybrid => {
1685                let duration_ms = frame_duration_ms_from_toc(toc);
1686                Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1687            }
1688        }
1689    }
1690
1691    #[test]
1692    fn gen_toc_matches_celt_reference_values() {
1693        let sampling_rate = 48_000;
1694        let cases = [
1695            (120usize, 0xE0u8),
1696            (240usize, 0xE8u8),
1697            (480usize, 0xF0u8),
1698            (960usize, 0xF8u8),
1699        ];
1700
1701        for (frame_size, expected_toc) in cases {
1702            let frame_rate = frame_rate_from_params(sampling_rate, frame_size).unwrap();
1703            let toc = gen_toc(OpusMode::CeltOnly, frame_rate, Bandwidth::Fullband, 1);
1704            assert_eq!(
1705                toc, expected_toc,
1706                "frame_size {} expected TOC {:02X} got {:02X}",
1707                frame_size, expected_toc, toc
1708            );
1709            let decoded_size = frame_size_from_toc(toc, sampling_rate).unwrap();
1710            assert_eq!(decoded_size, frame_size);
1711        }
1712
1713        let stereo_toc = gen_toc(
1714            OpusMode::CeltOnly,
1715            frame_rate_from_params(sampling_rate, 960).unwrap(),
1716            Bandwidth::Fullband,
1717            2,
1718        );
1719        assert_eq!(channels_from_toc(stereo_toc), 2);
1720    }
1721
1722    #[test]
1723    fn test_celt_decoder_large_frame_sizes() {
1724        let sampling_rate = 48000;
1725        let channels = 1;
1726
1727        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1728
1729        let frame_sizes = [120, 240, 480, 960];
1730
1731        for frame_size in frame_sizes {
1732            let toc = gen_toc(
1733                OpusMode::CeltOnly,
1734                frame_rate_from_params(sampling_rate, frame_size).unwrap(),
1735                Bandwidth::Fullband,
1736                channels,
1737            );
1738            let packet = [toc, 0, 0, 0, 0];
1739
1740            let mut output = vec![0.0f32; frame_size * channels];
1741
1742            let _ = decoder.decode(&packet, frame_size, &mut output);
1743        }
1744
1745        let channels = 2;
1746        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1747
1748        for frame_size in frame_sizes {
1749            let toc = gen_toc(
1750                OpusMode::CeltOnly,
1751                frame_rate_from_params(sampling_rate, frame_size).unwrap(),
1752                Bandwidth::Fullband,
1753                channels,
1754            );
1755            let packet = [toc, 0, 0, 0, 0];
1756
1757            let mut output = vec![0.0f32; frame_size * channels];
1758            let _ = decoder.decode(&packet, frame_size, &mut output);
1759        }
1760    }
1761
1762    #[test]
1763    fn test_celt_decoder_edge_case_frame_sizes() {
1764        let sampling_rate = 48000;
1765        let channels = 1;
1766        let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1767
1768        let edge_sizes = [2048, 2167, 2168, 2169, 2880, 3072];
1769
1770        for frame_size in edge_sizes {
1771            let mut output = vec![0.0f32; frame_size * channels];
1772
1773            let _ = decoder.decode(&[0x80, 0, 0, 0], frame_size, &mut output);
1774        }
1775    }
1776
1777    // Regression test for: "index out of bounds: the len is 48 but the index is 119"
1778    // Root cause: frame_size=48 at 48kHz gives frame_rate=1000, which is not a valid
1779    // Hybrid-mode frame rate but was not validated.  CELT's lm-search then silently
1780    // fell back to lm=0, computed n2=120, and wrote output[119] into a 48-element
1781    // slice.  Triggered via G.729-decoded PCM (8kHz) passed to a 48kHz Opus encoder
1782    // without proper resampling, so the encoder received 48 samples instead of 480.
1783    #[test]
1784    fn test_invalid_small_frame_size_returns_error_not_panic() {
1785        let mut enc = OpusEncoder::new(48000, 2, Application::Voip).unwrap();
1786        enc.bitrate_bps = 64000;
1787        enc.complexity = 5;
1788        enc.use_cbr = true;
1789
1790        // 48 samples at 48kHz = 1ms → frame_rate=1000, invalid for Hybrid mode.
1791        let input = vec![0.0f32; 48 * 2]; // stereo interleaved
1792        let mut output = vec![0u8; 256];
1793
1794        let result = enc.encode(&input, 48, &mut output);
1795        assert!(
1796            result.is_err(),
1797            "encode with invalid frame_size=48 should return Err, not panic"
1798        );
1799    }
1800
1801    // Also verify that the Audio application path (always Hybrid at 48 kHz) rejects
1802    // the same bad frame size.
1803    #[test]
1804    fn test_invalid_small_frame_size_audio_application_returns_error() {
1805        let mut enc = OpusEncoder::new(48000, 1, Application::Audio).unwrap();
1806        let input = vec![0.0f32; 48];
1807        let mut output = vec![0u8; 256];
1808
1809        let result = enc.encode(&input, 48, &mut output);
1810        assert!(
1811            result.is_err(),
1812            "Audio/48kHz encoder with frame_size=48 should return Err"
1813        );
1814    }
1815}