Skip to main content

opus_rs/
lib.rs

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