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
25use crate::fixedvec::FixedVec;
26pub use celt::{CeltDecoder, CeltEncoder};
27use hp_cutoff::{dc_reject_float, hp_cutoff, hp_cutoff_float};
28use range_coder::RangeCoder;
29use silk::control_codec::silk_control_encoder;
30use silk::enc_api::silk_encode;
31use silk::init_encoder::silk_init_encoder;
32use silk::lin2log::silk_lin2log;
33use silk::log2lin::silk_log2lin;
34use silk::macros::*;
35use silk::resampler::{silk_resampler_down2, silk_resampler_down2_3};
36use silk::structs::SilkEncoderState;
37
38const OPUS_MAX_CHANNELS: usize = 2;
40const OPUS_MAX_FRAME: usize = 5760;
43const OPUS_MAX_SUBFRAME: usize = 2880;
47const OPUS_SUBFRAME_SCRATCH: usize = OPUS_MAX_SUBFRAME * OPUS_MAX_CHANNELS;
49const OPUS_HP_MEM: usize = OPUS_MAX_CHANNELS * 2;
51const OPUS_PCM_I16: usize = 960 * OPUS_MAX_CHANNELS;
53const OPUS_PCM_TAIL: usize = 240 * OPUS_MAX_CHANNELS;
55const OPUS_MAX_PACKET_FRAMES: usize = 48;
58const OPUS_MAX_PACKET_BYTES: usize = 1276;
60const OPUS_DELAY_BUF: usize = 480 * OPUS_MAX_CHANNELS;
63const OPUS_PCM_BUF: usize = (192 + OPUS_MAX_SUBFRAME) * OPUS_MAX_CHANNELS;
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum Application {
69 Voip = 2048,
70 Audio = 2049,
71 RestrictedLowDelay = 2051,
72}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum Bandwidth {
76 Auto = -1000,
77 Narrowband = 1101,
78 Mediumband = 1102,
79 Wideband = 1103,
80 Superwideband = 1104,
81 Fullband = 1105,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85enum OpusMode {
86 SilkOnly,
87 Hybrid,
88 CeltOnly,
89}
90
91pub struct OpusEncoder {
92 #[cfg(not(feature = "heap"))]
93 celt_enc: CeltEncoder,
94 #[cfg(feature = "heap")]
95 celt_enc: Box<CeltEncoder>,
96 #[cfg(not(feature = "heap"))]
97 silk_enc: SilkEncoderState,
98 #[cfg(feature = "heap")]
99 silk_enc: Box<SilkEncoderState>,
100 application: Application,
101 sampling_rate: i32,
102 channels: usize,
103 bandwidth: Bandwidth,
104 pub bitrate_bps: i32,
105 pub complexity: i32,
106 pub use_cbr: bool,
107
108 pub use_inband_fec: bool,
109
110 pub packet_loss_perc: i32,
111 silk_initialized: bool,
112 mode: OpusMode,
113 prev_enc_mode: Option<OpusMode>,
114
115 variable_hp_smth2_q15: i32,
116 hp_mem: FixedVec<i32, OPUS_HP_MEM>,
117
118 #[cfg(not(feature = "heap"))]
119 buf_filtered: FixedVec<i16, OPUS_MAX_FRAME>,
120 #[cfg(feature = "heap")]
121 buf_filtered: Box<FixedVec<i16, OPUS_MAX_FRAME>>,
122 #[cfg(not(feature = "heap"))]
123 buf_silk_input: FixedVec<i16, OPUS_MAX_FRAME>,
124 #[cfg(feature = "heap")]
125 buf_silk_input: Box<FixedVec<i16, OPUS_MAX_FRAME>>,
126 #[cfg(not(feature = "heap"))]
127 buf_stereo_mid: FixedVec<i16, OPUS_MAX_FRAME>,
128 #[cfg(feature = "heap")]
129 buf_stereo_mid: Box<FixedVec<i16, OPUS_MAX_FRAME>>,
130 #[cfg(not(feature = "heap"))]
131 buf_stereo_side: FixedVec<i16, OPUS_MAX_FRAME>,
132 #[cfg(feature = "heap")]
133 buf_stereo_side: Box<FixedVec<i16, OPUS_MAX_FRAME>>,
134 #[cfg(not(feature = "heap"))]
135 buf_celt_input: FixedVec<f32, OPUS_MAX_FRAME>,
136 #[cfg(feature = "heap")]
137 buf_celt_input: Box<FixedVec<f32, OPUS_MAX_FRAME>>,
138 #[cfg(not(feature = "heap"))]
141 delay_buffer: FixedVec<f32, OPUS_DELAY_BUF>,
142 #[cfg(feature = "heap")]
143 delay_buffer: Box<FixedVec<f32, OPUS_DELAY_BUF>>,
144 #[cfg(not(feature = "heap"))]
147 buf_celt_pcm: FixedVec<f32, OPUS_PCM_BUF>,
148 #[cfg(feature = "heap")]
149 buf_celt_pcm: Box<FixedVec<f32, OPUS_PCM_BUF>>,
150 encoder_buffer: usize,
153 delay_compensation: usize,
156 hp_mem_float: [f32; 4],
159 down2_state_first: [i32; 2],
160 down2_state_second: [i32; 2],
161 down2_3_state: [i32; 6],
162 down_1_3_state: silk::resampler::SilkResamplerDown1_3,
163
164 rc: RangeCoder,
165}
166
167fn compute_equiv_rate(
168 bitrate: i32,
169 channels: usize,
170 frame_rate: i32,
171 vbr: bool,
172 complexity: i32,
173 loss: i32,
174) -> i32 {
175 let mut equiv = bitrate;
176 if frame_rate > 50 {
177 equiv -= (40 * channels as i32 + 20) * (frame_rate - 50);
178 }
179 if !vbr {
180 equiv -= equiv / 12;
181 }
182 equiv = equiv * (90 + complexity) / 100;
183 if loss > 0 {
184 equiv -= equiv * loss / (12 * loss + 20);
185 }
186 equiv
187}
188
189fn compute_mode_threshold(
190 application: Application,
191 channels: usize,
192 prev_was_celt: bool,
193 has_prev_mode: bool,
194 voice_est: i32,
195) -> i32 {
196 let mode_voice = if channels == 1 { 64000 } else { 44000 };
197 let mode_music = 10000;
198
199 let diff = mode_voice - mode_music;
200 let offset = (voice_est * voice_est * diff) >> 14;
201 let mut threshold = mode_music + offset;
202
203 if application == Application::Voip {
204 threshold += 8000;
205 }
206
207 if has_prev_mode {
208 if prev_was_celt {
209 threshold -= 4000;
210 } else {
211 threshold += 4000;
212 }
213 }
214
215 if application == Application::RestrictedLowDelay {
216 threshold = 0;
217 }
218
219 threshold
220}
221
222fn compute_silk_rate_for_hybrid(rate_bps: i32, frame20ms: bool) -> i32 {
223 const RATE_TABLE: &[(i32, i32, i32)] = &[
224 (0, 0, 0),
225 (12000, 10000, 10000),
226 (16000, 13500, 13500),
227 (20000, 16000, 16000),
228 (24000, 18000, 18000),
229 (32000, 22000, 22000),
230 (64000, 38000, 38000),
231 ];
232 let n = RATE_TABLE.len();
233 let mut i = 1;
234 while i < n && RATE_TABLE[i].0 <= rate_bps {
235 i += 1;
236 }
237 if i == n {
238 let (x_last, r10_last, r20_last) = RATE_TABLE[n - 1];
239 let base = if frame20ms { r20_last } else { r10_last };
240 base + (rate_bps - x_last) / 2
241 } else {
242 let (x0, lo10, lo20) = RATE_TABLE[i - 1];
243 let (x1, hi10, hi20) = RATE_TABLE[i];
244 let (lo, hi) = if frame20ms {
245 (lo20, hi20)
246 } else {
247 (lo10, hi10)
248 };
249 (lo * (x1 - rate_bps) + hi * (rate_bps - x0)) / (x1 - x0)
250 }
251}
252
253#[cfg(all(test, feature = "std"))]
254mod silk_rate_tests {
255 use super::compute_silk_rate_for_hybrid;
256
257 #[test]
258 fn test_reference_table_exact_entries() {
259 assert_eq!(compute_silk_rate_for_hybrid(12000, true), 10000);
260 assert_eq!(compute_silk_rate_for_hybrid(16000, true), 13500);
261 assert_eq!(compute_silk_rate_for_hybrid(20000, true), 16000);
262 assert_eq!(compute_silk_rate_for_hybrid(24000, true), 18000);
263 assert_eq!(compute_silk_rate_for_hybrid(32000, true), 22000);
264 assert_eq!(compute_silk_rate_for_hybrid(64000, true), 38000);
265 }
266
267 #[test]
268 fn test_32kbps_gives_22kbps_silk() {
269 assert_eq!(compute_silk_rate_for_hybrid(32000, true), 22000);
270 }
271
272 #[test]
273 fn test_interpolation_between_table_entries() {
274 let r = compute_silk_rate_for_hybrid(18000, true);
275 assert_eq!(r, 14750);
276 }
277
278 #[test]
279 fn test_above_table_max_gives_half_extra() {
280 let r = compute_silk_rate_for_hybrid(72000, true);
281 assert_eq!(r, 38000 + (72000 - 64000) / 2);
282 }
283}
284
285#[cfg(feature = "heap")]
294#[inline(always)]
295fn state_ref<T: core::ops::Deref>(b: &T) -> &T::Target {
296 b
297}
298#[cfg(not(feature = "heap"))]
299#[inline(always)]
300fn state_ref<T: ?Sized>(b: &T) -> &T {
301 b
302}
303
304#[cfg(feature = "heap")]
305#[inline(always)]
306fn state_mut<T: core::ops::DerefMut>(b: &mut T) -> &mut T::Target {
307 b
308}
309#[cfg(not(feature = "heap"))]
310#[inline(always)]
311fn state_mut<T: ?Sized>(b: &mut T) -> &mut T {
312 b
313}
314
315impl OpusEncoder {
316 pub fn new(
317 sampling_rate: i32,
318 channels: usize,
319 application: Application,
320 ) -> Result<Self, &'static str> {
321 if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
322 return Err("Invalid sampling rate");
323 }
324 if ![1, 2].contains(&channels) {
325 return Err("Invalid number of channels");
326 }
327
328 let mode = modes::default_mode();
329 #[cfg(feature = "heap")]
330 let celt_enc = Box::new(CeltEncoder::new(mode, channels));
331 #[cfg(not(feature = "heap"))]
332 let celt_enc = CeltEncoder::new(mode, channels);
333
334 #[cfg(feature = "heap")]
335 let mut silk_enc = Box::new(SilkEncoderState::default());
336 #[cfg(not(feature = "heap"))]
337 let mut silk_enc = SilkEncoderState::default();
338 if silk_init_encoder(state_mut(&mut silk_enc), 0) != 0 {
339 return Err("SILK encoder initialization failed");
340 }
341
342 let (opus_mode, bw) = match application {
343 Application::Voip => {
344 let bw = match sampling_rate {
345 8000 => Bandwidth::Narrowband,
346 12000 => Bandwidth::Mediumband,
347 16000 => Bandwidth::Wideband,
348 24000 => Bandwidth::Superwideband,
349 48000 => Bandwidth::Fullband,
350 _ => Bandwidth::Narrowband,
351 };
352
353 let mode = if sampling_rate > 16000 {
354 OpusMode::Hybrid
355 } else {
356 OpusMode::SilkOnly
357 };
358 (mode, bw)
359 }
360 Application::RestrictedLowDelay => {
361 let bw = match sampling_rate {
362 8000 => Bandwidth::Narrowband,
363 12000 => Bandwidth::Mediumband,
364 16000 => Bandwidth::Wideband,
365 24000 => Bandwidth::Superwideband,
366 _ => Bandwidth::Fullband,
367 };
368 (OpusMode::CeltOnly, bw)
369 }
370 Application::Audio => {
371 if sampling_rate <= 16000 {
372 let bw = match sampling_rate {
373 8000 => Bandwidth::Narrowband,
374 12000 => Bandwidth::Mediumband,
375 _ => Bandwidth::Wideband,
376 };
377 (OpusMode::SilkOnly, bw)
378 } else {
379 let bw = match sampling_rate {
380 24000 => Bandwidth::Superwideband,
381 _ => Bandwidth::Fullband,
382 };
383 (OpusMode::Hybrid, bw)
384 }
385 }
386 };
387
388 use silk::lin2log::silk_lin2log;
389 let variable_hp_smth2_q15 = silk_lin2log(60) << 8;
390
391 Ok(Self {
392 celt_enc,
393 silk_enc,
394 application,
395 sampling_rate,
396 channels,
397 bandwidth: bw,
398 bitrate_bps: 64000,
399 complexity: 9,
400 use_cbr: false,
401 use_inband_fec: false,
402 packet_loss_perc: 0,
403 silk_initialized: false,
404 prev_enc_mode: None,
405 mode: opus_mode,
406 variable_hp_smth2_q15,
407 hp_mem: FixedVec::from_value(0, channels * 2),
408
409 #[cfg(not(feature = "heap"))]
410 buf_filtered: FixedVec::new(),
411 #[cfg(feature = "heap")]
412 buf_filtered: Box::new(FixedVec::new()),
413 #[cfg(not(feature = "heap"))]
414 buf_silk_input: FixedVec::new(),
415 #[cfg(feature = "heap")]
416 buf_silk_input: Box::new(FixedVec::new()),
417 #[cfg(not(feature = "heap"))]
418 buf_stereo_mid: FixedVec::new(),
419 #[cfg(feature = "heap")]
420 buf_stereo_mid: Box::new(FixedVec::new()),
421 #[cfg(not(feature = "heap"))]
422 buf_stereo_side: FixedVec::new(),
423 #[cfg(feature = "heap")]
424 buf_stereo_side: Box::new(FixedVec::new()),
425 #[cfg(not(feature = "heap"))]
426 buf_celt_input: FixedVec::new(),
427 #[cfg(feature = "heap")]
428 buf_celt_input: Box::new(FixedVec::new()),
429 #[cfg(not(feature = "heap"))]
430 delay_buffer: FixedVec::from_value(0.0, OPUS_DELAY_BUF),
431 #[cfg(feature = "heap")]
432 delay_buffer: Box::new(FixedVec::from_value(0.0, OPUS_DELAY_BUF)),
433 #[cfg(not(feature = "heap"))]
434 buf_celt_pcm: FixedVec::new(),
435 #[cfg(feature = "heap")]
436 buf_celt_pcm: Box::new(FixedVec::new()),
437 encoder_buffer: if matches!(application, Application::RestrictedLowDelay) {
438 0
439 } else {
440 (sampling_rate / 100) as usize
441 },
442 delay_compensation: if matches!(application, Application::RestrictedLowDelay) {
443 0
444 } else {
445 (sampling_rate / 250) as usize
446 },
447 hp_mem_float: [0.0; 4],
448 down2_state_first: [0; 2],
449 down2_state_second: [0; 2],
450 down2_3_state: [0; 6],
451 down_1_3_state: silk::resampler::SilkResamplerDown1_3::default(),
452 rc: RangeCoder::new_encoder(1),
453 })
454 }
455
456 pub fn enable_hybrid_mode(&mut self) -> Result<(), &'static str> {
457 if self.sampling_rate != 24000 && self.sampling_rate != 48000 {
458 return Err("Hybrid mode requires 24kHz or 48kHz sampling rate");
459 }
460 let bw = if self.sampling_rate == 48000 {
461 Bandwidth::Fullband
462 } else {
463 Bandwidth::Superwideband
464 };
465 self.mode = OpusMode::Hybrid;
466 self.bandwidth = bw;
467 self.silk_initialized = false;
468 Ok(())
469 }
470
471 pub fn encode(
472 &mut self,
473 input: &[f32],
474 frame_size: usize,
475 output: &mut [u8],
476 ) -> Result<usize, &'static str> {
477 if output.len() < 2 {
478 return Err("Output buffer too small");
479 }
480
481 let frame_rate = frame_rate_from_params(self.sampling_rate, frame_size)
482 .ok_or("Invalid frame size for sampling rate")?;
483
484 self.bitrate_bps = self.bitrate_bps.clamp(500, 3_000_000);
490 self.complexity = self.complexity.clamp(0, 10);
491 self.packet_loss_perc = self.packet_loss_perc.clamp(0, 100);
492
493 if input.len() < frame_size * self.channels {
497 return Err("Input buffer too small for frame");
498 }
499
500 let mut mode = if self.application == Application::RestrictedLowDelay {
504 OpusMode::CeltOnly
505 } else {
506 let equiv = compute_equiv_rate(
507 self.bitrate_bps,
508 self.channels,
509 frame_rate,
510 !self.use_cbr,
511 self.complexity,
512 self.packet_loss_perc,
513 );
514 let prev_was_celt = self.prev_enc_mode == Some(OpusMode::CeltOnly);
515 let has_prev_mode = self.prev_enc_mode.is_some();
516 let voice_est = match self.application {
517 Application::Voip => 115,
518 Application::Audio => 48,
519 Application::RestrictedLowDelay => 0,
520 };
521 let threshold = compute_mode_threshold(
522 self.application,
523 self.channels,
524 prev_was_celt,
525 has_prev_mode,
526 voice_est,
527 );
528 if equiv >= threshold && self.sampling_rate >= 24000 {
529 OpusMode::CeltOnly
530 } else {
531 OpusMode::SilkOnly
532 }
533 };
534
535 let curr_bw = self.bandwidth;
536 if mode == OpusMode::SilkOnly
537 && (curr_bw == Bandwidth::Superwideband || curr_bw == Bandwidth::Fullband)
538 {
539 mode = OpusMode::Hybrid;
540 }
541 if mode == OpusMode::Hybrid
542 && (curr_bw == Bandwidth::Narrowband
543 || curr_bw == Bandwidth::Mediumband
544 || curr_bw == Bandwidth::Wideband)
545 {
546 mode = OpusMode::SilkOnly;
547 }
548
549 if mode == OpusMode::CeltOnly {
550 match frame_rate {
551 400 | 200 | 100 | 50 => {}
552 _ => return Err("Unsupported frame size for CELT-only mode"),
553 }
554 }
555
556 if mode == OpusMode::Hybrid {
557 match frame_rate {
558 100 | 50 => {}
559 _ => return Err("Unsupported frame size for Hybrid mode"),
560 }
561 }
562
563 if mode == OpusMode::SilkOnly {
564 match frame_rate {
565 400 | 200 | 100 | 50 | 25 => {}
566 _ => return Err("Unsupported frame size for SILK-only mode"),
567 }
568 }
569
570 let toc = gen_toc(mode, frame_rate, self.bandwidth, self.channels);
571 output[0] = toc;
572
573 let target_bits =
574 (self.bitrate_bps as i64 * frame_size as i64 / self.sampling_rate as i64) as i32;
575 let cbr_bytes = ((target_bits + 4) / 8) as usize;
576 let max_data_bytes = output.len();
577
578 let mut n_bytes = if self.use_cbr {
583 cbr_bytes
584 .min(max_data_bytes)
585 .max(1)
586 .min(OPUS_MAX_PACKET_BYTES)
587 } else {
588 max_data_bytes.max(1).min(OPUS_MAX_PACKET_BYTES)
589 };
590 let init_rc_size = n_bytes - 1;
591 self.rc.reset_for_encode(init_rc_size as u32);
592
593 let hp_freq_smth1 = if mode == OpusMode::CeltOnly {
598 silk_lin2log(60) << 8
599 } else {
600 self.silk_enc.s_cmn.variable_hp_smth1_q15
601 };
602
603 const VARIABLE_HP_SMTH_COEF2_Q16: i32 = 984;
604 self.variable_hp_smth2_q15 = silk_smlawb(
605 self.variable_hp_smth2_q15,
606 hp_freq_smth1 - self.variable_hp_smth2_q15,
607 VARIABLE_HP_SMTH_COEF2_Q16,
608 );
609
610 let cutoff_hz = silk_log2lin(silk_rshift(self.variable_hp_smth2_q15, 8));
611
612 if mode == OpusMode::SilkOnly || mode == OpusMode::Hybrid {
613 let silk_fs_khz = if mode == OpusMode::Hybrid {
614 16
615 } else {
616 self.sampling_rate.min(16000) / 1000
617 };
618
619 let frame_ms = (frame_size as i32 * 1000) / self.sampling_rate;
620 if !self.silk_initialized || self.silk_enc.s_cmn.fs_khz != silk_fs_khz {
621 let silk_init_bitrate = (((n_bytes - 1) * 8) as i64 * self.sampling_rate as i64
622 / frame_size as i64) as i32;
623 silk_control_encoder(
624 state_mut(&mut self.silk_enc),
625 silk_fs_khz,
626 frame_ms,
627 silk_init_bitrate,
628 self.complexity,
629 );
630 self.silk_enc.s_cmn.use_cbr = if self.use_cbr { 1 } else { 0 };
631
632 self.silk_enc.s_cmn.n_channels = self.channels as i32;
633 self.silk_initialized = true;
634 self.down2_state_first = [0; 2];
635 self.down2_state_second = [0; 2];
636 self.down2_3_state = [0; 6];
637 self.down_1_3_state = silk::resampler::SilkResamplerDown1_3::default();
638 }
639
640 self.silk_enc.s_cmn.use_in_band_fec = if self.use_inband_fec { 1 } else { 0 };
641 self.silk_enc.s_cmn.packet_loss_perc = self.packet_loss_perc.clamp(0, 100);
642
643 self.silk_enc.s_cmn.lbrr_enabled = if self.use_inband_fec { 1 } else { 0 };
644
645 if self.silk_enc.s_cmn.lbrr_gain_increases == 0 {
646 self.silk_enc.s_cmn.lbrr_gain_increases = 2;
647 }
648
649 let required_size = frame_size * self.channels;
650 self.buf_filtered.resize(required_size, 0);
651 if self.application == Application::Voip {
652 hp_cutoff(
653 input,
654 cutoff_hz,
655 state_mut(&mut self.buf_filtered),
656 &mut self.hp_mem,
657 frame_size,
658 self.channels,
659 self.sampling_rate,
660 );
661 } else {
662 let required_size = frame_size * self.channels;
663 for (i, &x) in input.iter().enumerate().take(required_size) {
664 self.buf_filtered[i] = (x * 32768.0).clamp(-32768.0, 32767.0) as i16;
665 }
666 }
667
668 let input_i16 = state_ref(&self.buf_filtered);
669
670 let silk_input: &[i16] = if mode == OpusMode::SilkOnly && self.sampling_rate > 16000 {
671 if self.sampling_rate == 48000 {
672 let stage1_size = frame_size / 2;
673 if stage1_size > 960 {
677 return Err("Invalid frame size for SILK mode");
678 }
679 let mut stage1_buf = [0i16; 960];
680 silk_resampler_down2(
681 &mut self.down2_state_first,
682 &mut stage1_buf[..stage1_size],
683 input_i16,
684 frame_size as i32,
685 );
686 let silk_frame_size = stage1_size * 2 / 3;
687 self.buf_silk_input.resize(silk_frame_size, 0);
688 silk_resampler_down2_3(
689 &mut self.down2_3_state,
690 state_mut(&mut self.buf_silk_input),
691 &stage1_buf[..stage1_size],
692 stage1_size as i32,
693 );
694 state_ref(&self.buf_silk_input)
695 } else if self.sampling_rate == 24000 {
696 let silk_frame_size = frame_size * 2 / 3;
697 self.buf_silk_input.resize(silk_frame_size, 0);
698 silk_resampler_down2_3(
699 &mut self.down2_3_state,
700 state_mut(&mut self.buf_silk_input),
701 input_i16,
702 frame_size as i32,
703 );
704 state_ref(&self.buf_silk_input)
705 } else {
706 input_i16
707 }
708 } else if mode == OpusMode::SilkOnly && self.channels == 2 {
709 let frame_length = input_i16.len() / 2;
710 self.buf_stereo_mid.resize(frame_length, 0);
711 self.buf_stereo_side.resize(frame_length, 0);
712 for i in 0..frame_length {
713 let l = input_i16[2 * i] as i32;
714 let r = input_i16[2 * i + 1] as i32;
715 self.buf_stereo_mid[i] = ((l + r) / 2) as i16;
716 self.buf_stereo_side[i] = (l - r) as i16;
717 }
718
719 self.silk_enc.stereo.side.resize(frame_length, 0);
720 self.silk_enc
721 .stereo
722 .side
723 .copy_from_slice(&self.buf_stereo_side[..frame_length]);
724 state_ref(&self.buf_stereo_mid)
725 } else if mode == OpusMode::Hybrid && self.sampling_rate > 16000 {
726 if self.sampling_rate == 48000 {
727 let silk_frame_size = frame_size / 3;
728 self.buf_silk_input.resize(silk_frame_size, 0);
729 silk::resampler::silk_resampler_down_1_3(
730 &mut self.down_1_3_state,
731 state_mut(&mut self.buf_silk_input),
732 input_i16,
733 );
734 } else {
735 let silk_frame_size = frame_size * 2 / 3;
736 self.buf_silk_input.resize(silk_frame_size, 0);
737 silk_resampler_down2_3(
738 &mut self.down2_3_state,
739 state_mut(&mut self.buf_silk_input),
740 input_i16,
741 frame_size as i32,
742 );
743 }
744 state_ref(&self.buf_silk_input)
745 } else {
746 input_i16
747 };
748
749 let mut pn_bytes = 0;
750
751 let silk_rate_for_calc = if mode == OpusMode::Hybrid {
752 16000
753 } else {
754 self.sampling_rate
755 };
756 let silk_frame_len = silk_input.len();
757
758 let silk_bitrate = if mode == OpusMode::Hybrid {
759 let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
760 let frame20ms = frame_duration_ms >= 20;
761 compute_silk_rate_for_hybrid(self.bitrate_bps, frame20ms)
762 } else {
763 (8i64 * (n_bytes - 1) as i64 * silk_rate_for_calc as i64 / silk_frame_len as i64)
764 as i32
765 };
766 let silk_max_bits = if mode == OpusMode::Hybrid {
767 let total_max_bits = ((n_bytes - 1) * 8) as i32;
768 if self.use_cbr {
769 let silk_bits = (silk_bitrate as i64 * silk_frame_len as i64
770 / silk_rate_for_calc as i64) as i32;
771 let other_bits = 0i32.max(total_max_bits - silk_bits);
772 0i32.max(total_max_bits - other_bits * 3 / 4)
773 } else {
774 let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
775 let frame20ms = frame_duration_ms >= 20;
776 let max_bit_rate = compute_silk_rate_for_hybrid(
777 total_max_bits * self.sampling_rate / frame_size as i32,
778 frame20ms,
779 );
780 max_bit_rate * frame_size as i32 / self.sampling_rate
781 }
782 } else {
783 ((n_bytes - 1) * 8) as i32
784 };
785 let silk_use_cbr = if mode == OpusMode::Hybrid && self.use_cbr {
786 0
787 } else if self.use_cbr {
788 1
789 } else {
790 0
791 };
792 let ret = silk_encode(
793 state_mut(&mut self.silk_enc),
794 silk_input,
795 silk_input.len(),
796 &mut self.rc,
797 &mut pn_bytes,
798 silk_bitrate,
799 silk_max_bits,
800 silk_use_cbr,
801 1,
802 );
803 if ret != 0 {
804 return Err("SILK encoding failed");
805 }
806 }
807
808 if mode == OpusMode::Hybrid {
809 self.rc.encode_bit_logp(false, 12); }
811
812 if mode == OpusMode::Hybrid {
813 let nb_compr_bytes = (n_bytes - 1) as u32;
814 self.rc.shrink(nb_compr_bytes);
815 }
816
817 let silk_ret_bytes = if mode == OpusMode::SilkOnly {
818 ((self.rc.tell() + 7) >> 3) as usize
819 } else {
820 0
821 };
822
823 if mode != OpusMode::SilkOnly && self.use_cbr {
829 let tell = self.rc.tell();
830 if tell > 1 {
831 let tmp = self.bitrate_bps as i64 * frame_size as i64
832 + tell as i64 * self.sampling_rate as i64;
833 let adjusted = ((tmp + 4 * self.sampling_rate as i64)
834 / (8 * self.sampling_rate as i64)) as usize;
835 let new_n = adjusted
836 .min(max_data_bytes)
837 .max(1)
838 .min(OPUS_MAX_PACKET_BYTES);
839 if new_n < n_bytes {
840 n_bytes = new_n;
841 let new_payload = n_bytes - 1;
843 self.rc.shrink(new_payload as u32);
844 }
845 }
846 }
847 if mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid {
848 self.celt_enc.complexity = self.complexity;
849 let start_band = if mode == OpusMode::Hybrid { 17 } else { 0 };
850 let total_packet_bits = ((n_bytes - 1) * 8) as i32;
851 let celt_bitrate = if mode == OpusMode::Hybrid {
853 let frame_ms = frame_size as i32 * 1000 / self.sampling_rate;
854 let frame20ms = frame_ms >= 20;
855 let silk_rate = compute_silk_rate_for_hybrid(self.bitrate_bps, frame20ms);
856 (self.bitrate_bps - silk_rate).max(8000)
857 } else {
858 self.bitrate_bps
859 };
860 self.celt_enc.set_bitrate(celt_bitrate);
861 self.celt_enc.set_vbr(!self.use_cbr);
862 self.celt_enc
864 .set_constrained_vbr(mode == OpusMode::CeltOnly);
865
866 let celt_input: &[f32] = if self.delay_compensation > 0 {
873 let delay = self.delay_compensation;
874 let ebuf = self.encoder_buffer;
875 let ch = self.channels;
876 let total = (delay + frame_size) * ch;
877 self.buf_celt_pcm.resize(total, 0.0);
878 let prefix = delay * ch;
880 let src_start = (ebuf - delay) * ch;
881 self.buf_celt_pcm[..prefix]
882 .copy_from_slice(&self.delay_buffer[src_start..src_start + prefix]);
883 let out = &mut self.buf_celt_pcm[prefix..];
885 if self.application == Application::Voip {
886 hp_cutoff_float(
887 input,
888 cutoff_hz,
889 out,
890 &mut self.hp_mem_float,
891 frame_size,
892 ch,
893 self.sampling_rate,
894 );
895 } else {
896 dc_reject_float(
897 input,
898 3,
899 out,
900 &mut self.hp_mem_float,
901 frame_size,
902 ch,
903 self.sampling_rate,
904 );
905 }
906 let mut sum = 0.0f32;
908 for &v in &self.buf_celt_pcm[prefix..] {
909 sum += v * v;
910 }
911 if !(sum < 1e9) || sum.is_nan() {
912 self.buf_celt_pcm[prefix..].fill(0.0);
913 self.hp_mem_float = [0.0; 4];
914 }
915 let keep = ebuf as i64 - (frame_size as i64 + delay as i64);
917 if keep > 0 {
918 let keep = keep as usize;
919 self.delay_buffer
920 .copy_within(ch * frame_size..ch * (frame_size + keep), 0);
921 let dst = ch * keep;
922 let n = (frame_size + delay) * ch;
923 self.delay_buffer[dst..dst + n].copy_from_slice(&self.buf_celt_pcm[..n]);
924 } else {
925 let n = ebuf * ch;
926 let src = (frame_size + delay - ebuf) * ch;
927 self.delay_buffer[..n].copy_from_slice(&self.buf_celt_pcm[src..src + n]);
928 }
929 let n = frame_size * ch;
932 self.buf_celt_input.resize(n, 0.0);
933 for i in 0..frame_size {
934 for c in 0..ch {
935 self.buf_celt_input[c * frame_size + i] = self.buf_celt_pcm[i * ch + c];
936 }
937 }
938 state_ref(&self.buf_celt_input)
939 } else if self.channels == 1 {
940 input
941 } else {
942 let n = frame_size * self.channels;
943 self.buf_celt_input.resize(n, 0.0);
944 for i in 0..frame_size {
945 for ch in 0..self.channels {
946 self.buf_celt_input[ch * frame_size + i] = input[i * self.channels + ch];
947 }
948 }
949 state_ref(&self.buf_celt_input)
950 };
951
952 if self.rc.tell() <= total_packet_bits {
953 let is_vbr = !self.use_cbr;
954 self.celt_enc.encode_with_budget_vbr(
955 celt_input,
956 frame_size,
957 &mut self.rc,
958 start_band,
959 total_packet_bits,
960 is_vbr,
961 );
962 }
963 }
964
965 self.rc.done();
966
967 if self.rc.error != 0 {
968 return Err("Range coder buffer overflow: encoded data exceeds packet budget");
969 }
970
971 if mode == OpusMode::SilkOnly {
972 let mut ret = silk_ret_bytes.min(self.rc.storage as usize);
973 while ret > 2 && self.rc.buf[ret - 1] == 0 {
974 ret -= 1;
975 }
976
977 let target_total = if self.use_cbr {
978 n_bytes.min(output.len())
979 } else {
980 (ret + 1).min(output.len())
981 };
982
983 let silk_len = ret;
984
985 if !self.use_cbr || silk_len + 1 >= target_total {
986 output[0] = toc;
988 let copy_len = silk_len.min(target_total - 1);
989 output[1..1 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
990 return Ok((copy_len + 1).min(output.len()));
991 }
992
993 output[0] = toc | 0x03;
994
995 if silk_len + 2 >= target_total {
996 output[1] = 0x01;
997 let copy_len = (target_total - 2).min(silk_len);
998 output[2..2 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
999 self.prev_enc_mode = Some(mode);
1000 return Ok(target_total.min(output.len()));
1001 }
1002
1003 let pad_amount = target_total - silk_len - 2;
1004 output[1] = 0x41;
1005
1006 let nb_255s = (pad_amount - 1) / 255;
1007 let mut ptr = 2;
1008 for _ in 0..nb_255s {
1009 output[ptr] = 255;
1010 ptr += 1;
1011 }
1012 output[ptr] = (pad_amount - 255 * nb_255s - 1) as u8;
1013 ptr += 1;
1014
1015 output[ptr..ptr + silk_len].copy_from_slice(&self.rc.buf[..silk_len]);
1016 ptr += silk_len;
1017
1018 let fill_end = target_total.min(output.len());
1019 for byte in output[ptr..fill_end].iter_mut() {
1020 *byte = 0;
1021 }
1022
1023 self.prev_enc_mode = Some(mode);
1024 return Ok(target_total.min(output.len()));
1025 }
1026
1027 let payload_len = (self.rc.storage as usize).min(output.len() - 1);
1029 output[1..1 + payload_len].copy_from_slice(&self.rc.buf[..payload_len]);
1030 self.prev_enc_mode = Some(mode);
1031 Ok(payload_len + 1)
1032 }
1033}
1034
1035pub struct OpusDecoder {
1036 #[cfg(not(feature = "heap"))]
1037 celt_dec: CeltDecoder,
1038 #[cfg(feature = "heap")]
1039 celt_dec: Box<CeltDecoder>,
1040 #[cfg(not(feature = "heap"))]
1041 silk_dec: silk::dec_api::SilkDecoder,
1042 #[cfg(feature = "heap")]
1043 silk_dec: Box<silk::dec_api::SilkDecoder>,
1044 sampling_rate: i32,
1045 channels: usize,
1046
1047 prev_mode: Option<OpusMode>,
1048
1049 prev_redundancy: bool,
1051 frame_size: usize,
1052
1053 bandwidth: Bandwidth,
1054
1055 stream_channels: usize,
1056
1057 silk_resampler: silk::resampler::SilkResampler,
1058
1059 silk_resampler_2: silk::resampler::SilkResampler,
1061
1062 prev_internal_rate: i32,
1063
1064 pub hybrid_skip_celt: bool,
1065
1066 #[cfg(not(feature = "heap"))]
1067 w_pcm_i16: FixedVec<i16, OPUS_PCM_I16>,
1068 #[cfg(feature = "heap")]
1069 w_pcm_i16: Box<FixedVec<i16, OPUS_PCM_I16>>,
1070 #[cfg(not(feature = "heap"))]
1071 w_silk_out: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
1072 #[cfg(feature = "heap")]
1073 w_silk_out: Box<FixedVec<f32, OPUS_SUBFRAME_SCRATCH>>,
1074 #[cfg(not(feature = "heap"))]
1075 w_pcm_resampled: FixedVec<i16, OPUS_SUBFRAME_SCRATCH>,
1076 #[cfg(feature = "heap")]
1077 w_pcm_resampled: Box<FixedVec<i16, OPUS_SUBFRAME_SCRATCH>>,
1078 #[cfg(not(feature = "heap"))]
1079 w_celt_planar: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
1080 #[cfg(feature = "heap")]
1081 w_celt_planar: Box<FixedVec<f32, OPUS_SUBFRAME_SCRATCH>>,
1082 #[cfg(not(feature = "heap"))]
1083 w_celt_out: FixedVec<f32, OPUS_SUBFRAME_SCRATCH>,
1084 #[cfg(feature = "heap")]
1085 w_celt_out: Box<FixedVec<f32, OPUS_SUBFRAME_SCRATCH>>,
1086
1087 #[cfg(not(feature = "heap"))]
1090 prev_pcm_tail: FixedVec<f32, OPUS_PCM_TAIL>,
1091 #[cfg(feature = "heap")]
1092 prev_pcm_tail: Box<FixedVec<f32, OPUS_PCM_TAIL>>,
1093}
1094
1095impl OpusDecoder {
1096 pub fn new(sampling_rate: i32, channels: usize) -> Result<Self, &'static str> {
1097 if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
1098 return Err("Invalid sampling rate");
1099 }
1100 if ![1, 2].contains(&channels) {
1101 return Err("Invalid number of channels");
1102 }
1103
1104 let mode = modes::default_mode();
1105 #[cfg(feature = "heap")]
1106 let celt_dec = Box::new(CeltDecoder::new(mode, channels, sampling_rate));
1107 #[cfg(not(feature = "heap"))]
1108 let celt_dec = CeltDecoder::new(mode, channels, sampling_rate);
1109
1110 #[cfg(feature = "heap")]
1111 let mut silk_dec = Box::new(silk::dec_api::SilkDecoder::new());
1112 #[cfg(not(feature = "heap"))]
1113 let mut silk_dec = silk::dec_api::SilkDecoder::new();
1114 silk_dec.init(sampling_rate.min(16000), channels as i32);
1115 silk_dec.channel_state[0].fs_api_hz = sampling_rate;
1116
1117 Ok(Self {
1118 celt_dec,
1119 silk_dec,
1120 sampling_rate,
1121 channels,
1122 prev_mode: None,
1123 prev_redundancy: false,
1124 frame_size: 0,
1125 bandwidth: Bandwidth::Auto,
1126 stream_channels: channels,
1127 silk_resampler: silk::resampler::SilkResampler::default(),
1128 silk_resampler_2: silk::resampler::SilkResampler::default(),
1129 prev_internal_rate: 0,
1130 hybrid_skip_celt: false,
1131
1132 #[cfg(not(feature = "heap"))]
1133 w_pcm_i16: FixedVec::from_value(0i16, 960 * channels),
1134 #[cfg(feature = "heap")]
1135 w_pcm_i16: Box::new(FixedVec::from_value(0i16, 960 * channels)),
1136
1137 #[cfg(not(feature = "heap"))]
1138 w_silk_out: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
1139 #[cfg(feature = "heap")]
1140 w_silk_out: Box::new(FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels)),
1141 #[cfg(not(feature = "heap"))]
1142 w_pcm_resampled: FixedVec::from_value(0i16, OPUS_MAX_SUBFRAME * channels),
1143 #[cfg(feature = "heap")]
1144 w_pcm_resampled: Box::new(FixedVec::from_value(0i16, OPUS_MAX_SUBFRAME * channels)),
1145 #[cfg(not(feature = "heap"))]
1146 w_celt_planar: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
1147 #[cfg(feature = "heap")]
1148 w_celt_planar: Box::new(FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels)),
1149 #[cfg(not(feature = "heap"))]
1150 w_celt_out: FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels),
1151 #[cfg(feature = "heap")]
1152 w_celt_out: Box::new(FixedVec::from_value(0.0f32, OPUS_MAX_SUBFRAME * channels)),
1153
1154 #[cfg(not(feature = "heap"))]
1155 prev_pcm_tail: FixedVec::from_value(0.0f32, 240 * channels),
1156 #[cfg(feature = "heap")]
1157 prev_pcm_tail: Box::new(FixedVec::from_value(0.0f32, 240 * channels)),
1158 })
1159 }
1160
1161 pub fn decode(
1162 &mut self,
1163 input: &[u8],
1164 frame_size: usize,
1165 output: &mut [f32],
1166 ) -> Result<usize, &'static str> {
1167 if input.is_empty() {
1168 return Err("Input packet empty");
1169 }
1170
1171 let toc = input[0];
1172 let mode = mode_from_toc(toc);
1173 let packet_channels = channels_from_toc(toc);
1174 let bandwidth = bandwidth_from_toc(toc);
1175 let frame_duration_ms = frame_duration_ms_from_toc(toc);
1176
1177 let lost_frame = input.len() <= 1;
1181
1182 if packet_channels != self.channels {
1183 return Err("Channel count mismatch between packet and decoder");
1184 }
1185
1186 let code = toc & 0x03;
1187 let frame_count: usize;
1188 let frame_payloads: FixedVec<&[u8], OPUS_MAX_PACKET_FRAMES>;
1189
1190 match code {
1191 0 => {
1192 frame_count = 1;
1193 frame_payloads = FixedVec::from_slice(&[&input[1..]]);
1194 }
1195 1 => {
1196 frame_count = 2;
1197 let data_len = input.len() - 1;
1198 if data_len % 2 != 0 {
1201 return Err("Code 1: payload length must be even");
1202 }
1203 let half = data_len / 2;
1204 if half == 0 {
1205 return Err("Code 1: empty frame");
1206 }
1207 frame_payloads = FixedVec::from_slice(&[&input[1..1 + half], &input[1 + half..]]);
1208 }
1209 2 => {
1210 frame_count = 2;
1211 let data = &input[1..];
1212 if data.is_empty() {
1213 return Err("Code 2 packet has no data");
1214 }
1215 let (first_len, header_size) = parse_frame_size(data)?;
1216 if header_size + first_len > data.len() {
1217 return Err("Code 2: first frame size exceeds packet");
1218 }
1219 frame_payloads = FixedVec::from_slice(&[
1220 &data[header_size..header_size + first_len],
1221 &data[header_size + first_len..],
1222 ]);
1223 }
1224 3 => {
1225 if input.len() < 2 {
1226 return Err("Code 3 packet too short");
1227 }
1228 let count_byte = input[1];
1229 let n_frames = (count_byte & 0x3F) as usize;
1230 if n_frames < 1 || n_frames > 48 {
1231 return Err("Code 3: invalid frame count");
1232 }
1233 frame_count = n_frames;
1234 let padding_flag = (count_byte & 0x40) != 0;
1236 let vbr = (count_byte & 0x80) != 0;
1237
1238 let mut ptr = 2usize;
1242 let mut pad_len = 0usize;
1243 if padding_flag {
1244 loop {
1245 if ptr >= input.len() {
1246 return Err("Code 3: padding overflow");
1247 }
1248 let p = input[ptr] as usize;
1249 ptr += 1;
1250 if p == 255 {
1251 pad_len += 254;
1252 } else {
1253 pad_len += p;
1254 break;
1255 }
1256 }
1257 }
1258 if ptr + pad_len > input.len() {
1259 return Err("Code 3: padding exceeds packet");
1260 }
1261 let payload_end = input.len() - pad_len;
1262 let payload = &input[ptr..payload_end];
1263
1264 let mut payloads: FixedVec<&[u8], OPUS_MAX_PACKET_FRAMES> = FixedVec::new();
1265 if frame_count == 1 {
1266 payloads.push(payload);
1269 } else if vbr {
1270 let mut cursor = 0usize;
1273 for i in 0..frame_count {
1274 if i + 1 < frame_count {
1275 if cursor >= payload.len() {
1276 return Err("Code 3: unexpected end in VBR header");
1277 }
1278 let (frame_len, header_bytes) = parse_frame_size(&payload[cursor..])?;
1279 cursor += header_bytes;
1280 if cursor + frame_len > payload.len() {
1281 return Err("Code 3: frame length exceeds packet");
1282 }
1283 payloads.push(&payload[cursor..cursor + frame_len]);
1284 cursor += frame_len;
1285 } else {
1286 if cursor > payload.len() {
1288 return Err("Code 3: no data for last frame");
1289 }
1290 payloads.push(&payload[cursor..]);
1291 }
1292 }
1293 } else {
1294 if payload.len() % frame_count != 0 {
1298 return Err("Code 3 CBR: payload not divisible by frame count");
1299 }
1300 let frame_len = payload.len() / frame_count;
1301 for i in 0..frame_count {
1302 payloads.push(&payload[i * frame_len..(i + 1) * frame_len]);
1303 }
1304 }
1305 frame_payloads = payloads;
1306 }
1307 _ => unreachable!(),
1308 }
1309
1310 self.frame_size = frame_size;
1311 self.bandwidth = bandwidth;
1312 self.stream_channels = packet_channels;
1313
1314 let toc_frame_size = frame_samples_from_toc(toc, self.sampling_rate)
1319 .ok_or("Invalid TOC for sampling rate")?;
1320 let decoded_total = toc_frame_size * frame_count;
1321 if frame_size < decoded_total {
1322 return Err("frame_size too small for packet");
1323 }
1324 if output.len() < decoded_total * self.channels {
1325 return Err("Output buffer too small for packet");
1326 }
1327 if output.len() > decoded_total * self.channels {
1330 for v in &mut output[decoded_total * self.channels..] {
1331 *v = 0.0;
1332 }
1333 }
1334 let sub_frame_size = toc_frame_size;
1335 let sub_output_len = sub_frame_size * self.channels;
1336
1337 let mode_transition = match self.prev_mode {
1343 Some(prev) if prev != mode && !self.prev_redundancy => true,
1344 _ => false,
1345 };
1346 if mode_transition {
1347 self.celt_dec.reset_state();
1348 }
1349
1350 let f5_bridge = self.sampling_rate as usize / 200; if mode_transition
1356 && f5_bridge > 0
1357 && matches!(
1358 self.prev_mode,
1359 Some(OpusMode::SilkOnly) | Some(OpusMode::Hybrid)
1360 )
1361 && self.prev_internal_rate > 0
1362 {
1363 let internal_rate = self.prev_internal_rate;
1364 let plc_internal_len = (10 * internal_rate / 1000) as usize;
1365 let mut plc_rc = RangeCoder::new_decoder(&[]);
1366 let mut plc_i16: FixedVec<i16, OPUS_PCM_I16> =
1367 FixedVec::from_value(0i16, plc_internal_len * self.channels);
1368 let n = self.silk_dec.decode(
1369 &mut plc_rc,
1370 &mut plc_i16,
1371 silk::decode_frame::FLAG_PACKET_LOST,
1372 true,
1373 10,
1374 internal_rate,
1375 );
1376 if n > 0 {
1377 let bridge_ch = f5_bridge * self.channels;
1378 let bridge_len = bridge_ch.min(self.prev_pcm_tail.len());
1379 if internal_rate == self.sampling_rate {
1380 let n_us = n as usize;
1382 for ch in 0..self.channels {
1383 let src_base = ch * n_us;
1384 for i in 0..(bridge_len / self.channels).min(n_us) {
1385 let dst = i * self.channels + ch;
1386 if dst < bridge_len {
1387 self.prev_pcm_tail[dst] = plc_i16[src_base + i] as f32 / 32768.0;
1388 }
1389 }
1390 }
1391 } else if self.silk_resampler.is_initialized() {
1392 let ratio = self.sampling_rate as f64 / internal_rate as f64;
1398 let full_len = ((n as f64 * ratio) as usize).max(1);
1399 let out_len = full_len.min(f5_bridge);
1400 let n_us = n as usize;
1401 let mut resampled: FixedVec<i16, OPUS_MAX_FRAME> =
1402 FixedVec::from_value(0i16, full_len);
1403 self.silk_resampler
1404 .process(&mut resampled, &plc_i16[..n_us], n);
1405 for i in 0..out_len {
1406 if i < bridge_len / self.channels {
1407 for ch in 0..self.channels {
1408 self.prev_pcm_tail[i * self.channels + ch] =
1409 resampled[i] as f32 / 32768.0;
1410 }
1411 }
1412 }
1413 }
1414 }
1415 }
1416
1417 let mut has_redundancy = false;
1419
1420 match mode {
1421 OpusMode::SilkOnly => {
1422 let internal_sample_rate = match bandwidth {
1423 Bandwidth::Narrowband => 8000,
1424 Bandwidth::Mediumband => 12000,
1425 Bandwidth::Wideband => 16000,
1426 _ => 16000,
1427 };
1428 let internal_frame_size =
1429 (frame_duration_ms * internal_sample_rate / 1000) as usize;
1430
1431 if self.sampling_rate != internal_sample_rate
1432 && internal_sample_rate != self.prev_internal_rate
1433 {
1434 self.silk_resampler
1435 .init(internal_sample_rate, self.sampling_rate);
1436 self.silk_resampler_2
1437 .init(internal_sample_rate, self.sampling_rate);
1438 }
1439 self.prev_internal_rate = internal_sample_rate;
1443
1444 for (fi, payload) in frame_payloads.iter().enumerate() {
1445 let mut rc = RangeCoder::new_decoder(payload);
1446 let pcm_i16_len = internal_frame_size * self.channels;
1447 debug_assert!(pcm_i16_len <= self.w_pcm_i16.len());
1448
1449 let lost_flag = if lost_frame {
1455 silk::decode_frame::FLAG_PACKET_LOST
1456 } else {
1457 silk::decode_frame::FLAG_DECODE_NORMAL
1458 };
1459 let out_start = fi * sub_output_len;
1460 let mut frame_pos = 0usize; let mut new_packet = true;
1462 while frame_pos < internal_frame_size {
1463 let ret = {
1464 let (silk_dec, pcm_i16) = (
1465 state_mut(&mut self.silk_dec),
1466 state_mut(&mut self.w_pcm_i16),
1467 );
1468 silk_dec.decode(
1469 &mut rc,
1470 &mut pcm_i16[..pcm_i16_len],
1471 lost_flag,
1472 new_packet,
1473 frame_duration_ms,
1474 internal_sample_rate,
1475 )
1476 };
1477 new_packet = false;
1478
1479 if ret < 0 {
1480 return Err("SILK decoding failed");
1481 }
1482 let decoded_samples = ret as usize;
1483 if decoded_samples == 0 {
1484 break;
1485 }
1486
1487 if self.sampling_rate == internal_sample_rate {
1490 let frames = decoded_samples.min(internal_frame_size - frame_pos);
1491 for i in 0..frames {
1492 for ch in 0..self.channels {
1493 let src = if ch == 0 { i } else { decoded_samples + i };
1494 let v = self.w_pcm_i16[src] as f32 / 32768.0;
1495 let idx = out_start + (frame_pos + i) * self.channels + ch;
1496 if idx < output.len() {
1497 output[idx] = v;
1498 }
1499 }
1500 }
1501 } else {
1502 let resampled_len = decoded_samples * self.sampling_rate as usize
1503 / internal_sample_rate as usize;
1504 let api_pos = frame_pos * self.sampling_rate as usize
1505 / internal_sample_rate as usize;
1506 let copy_len = resampled_len.min(sub_frame_size - api_pos);
1507 debug_assert!(
1508 resampled_len * self.channels <= self.w_pcm_resampled.len()
1509 );
1510 {
1512 let (res, inp, out) = (
1513 &mut self.silk_resampler,
1514 state_ref(&self.w_pcm_i16),
1515 state_mut(&mut self.w_pcm_resampled),
1516 );
1517 res.process(
1518 &mut out[..resampled_len],
1519 &inp[..decoded_samples],
1520 decoded_samples as i32,
1521 );
1522 }
1523 if self.channels == 2 {
1525 let (res, inp, out) = (
1526 &mut self.silk_resampler_2,
1527 state_ref(&self.w_pcm_i16),
1528 state_mut(&mut self.w_pcm_resampled),
1529 );
1530 res.process(
1531 &mut out[resampled_len..2 * resampled_len],
1532 &inp[decoded_samples..2 * decoded_samples],
1533 decoded_samples as i32,
1534 );
1535 }
1536 for i in 0..copy_len {
1537 for ch in 0..self.channels {
1538 let v = self.w_pcm_resampled[ch * resampled_len + i] as f32
1539 / 32768.0;
1540 let idx = out_start + (api_pos + i) * self.channels + ch;
1541 if idx < output.len() {
1542 output[idx] = v;
1543 }
1544 }
1545 }
1546 }
1547 frame_pos += decoded_samples;
1548 }
1549 }
1550 decoded_total
1551 }
1552
1553 OpusMode::CeltOnly => {
1554 let celt_end_band = self.celt_end_band_from_toc(toc);
1555
1556 for (fi, payload) in frame_payloads.iter().enumerate() {
1557 let mut rc = RangeCoder::new_decoder(payload);
1558 let total_bits = (payload.len() * 8) as i32;
1559 let needed = sub_frame_size * self.channels;
1560 let out_start = fi * needed;
1561 let out_end = (out_start + needed).min(output.len());
1562
1563 if output.len() < out_end {
1564 return Err("Output buffer too small");
1565 }
1566
1567 if self.channels == 1 {
1568 self.celt_dec.decode_from_range_coder_with_band_range(
1569 &mut rc,
1570 total_bits,
1571 sub_frame_size,
1572 &mut output[out_start..out_end],
1573 0,
1574 celt_end_band,
1575 );
1576 for sample in &mut output[out_start..out_end] {
1577 *sample = sample.clamp(-1.0, 1.0);
1578 }
1579 } else {
1580 self.celt_dec.decode_from_range_coder_with_band_range(
1581 &mut rc,
1582 total_bits,
1583 sub_frame_size,
1584 &mut self.w_celt_planar[..needed],
1585 0,
1586 celt_end_band,
1587 );
1588 for i in 0..sub_frame_size {
1589 for ch in 0..self.channels {
1590 let idx = out_start + i * self.channels + ch;
1591 output[idx] =
1592 self.w_celt_planar[ch * sub_frame_size + i].clamp(-1.0, 1.0);
1593 }
1594 }
1595 }
1596 }
1597 decoded_total
1598 }
1599
1600 OpusMode::Hybrid => {
1601 let internal_sample_rate = 16000;
1602 let internal_frame_size =
1603 (frame_duration_ms * internal_sample_rate / 1000) as usize;
1604 let celt_end_band = self.celt_end_band_from_toc(toc);
1605
1606 if self.sampling_rate != internal_sample_rate
1607 && internal_sample_rate != self.prev_internal_rate
1608 {
1609 self.silk_resampler
1610 .init(internal_sample_rate, self.sampling_rate);
1611 self.silk_resampler_2
1612 .init(internal_sample_rate, self.sampling_rate);
1613 }
1614 self.prev_internal_rate = internal_sample_rate;
1615
1616 for (fi, payload) in frame_payloads.iter().enumerate() {
1617 let mut rc = RangeCoder::new_decoder(payload);
1618 let pcm_silk_i16_len = internal_frame_size * self.channels;
1619 debug_assert!(pcm_silk_i16_len <= self.w_pcm_i16.len());
1620
1621 let silk_out_len = sub_frame_size * self.channels;
1625 self.w_silk_out[..silk_out_len].fill(0.0);
1626 let lost_flag = if lost_frame {
1627 silk::decode_frame::FLAG_PACKET_LOST
1628 } else {
1629 silk::decode_frame::FLAG_DECODE_NORMAL
1630 };
1631 let mut frame_pos = 0usize;
1632 let mut new_packet = true;
1633 while frame_pos < internal_frame_size {
1634 let ret = {
1635 let (silk_dec, pcm_i16) = (
1636 state_mut(&mut self.silk_dec),
1637 state_mut(&mut self.w_pcm_i16),
1638 );
1639 silk_dec.decode(
1640 &mut rc,
1641 &mut pcm_i16[..pcm_silk_i16_len],
1642 lost_flag,
1643 new_packet,
1644 frame_duration_ms,
1645 internal_sample_rate,
1646 )
1647 };
1648 new_packet = false;
1649
1650 if ret < 0 {
1651 return Err("SILK decoding failed");
1652 }
1653 let decoded_samples = ret as usize;
1654 if decoded_samples == 0 {
1655 break;
1656 }
1657
1658 if self.sampling_rate == internal_sample_rate {
1661 let frames = decoded_samples.min(internal_frame_size - frame_pos);
1662 for i in 0..frames {
1663 for ch in 0..self.channels {
1664 let src = if ch == 0 { i } else { decoded_samples + i };
1665 let v = self.w_pcm_i16[src] as f32 / 32768.0;
1666 let idx = (frame_pos + i) * self.channels + ch;
1667 if idx < silk_out_len {
1668 self.w_silk_out[idx] = v;
1669 }
1670 }
1671 }
1672 } else {
1673 let resampled_len = decoded_samples * self.sampling_rate as usize
1674 / internal_sample_rate as usize;
1675 let api_pos = frame_pos * self.sampling_rate as usize
1676 / internal_sample_rate as usize;
1677 let copy_len = resampled_len.min(sub_frame_size - api_pos);
1678 debug_assert!(
1679 resampled_len * self.channels <= self.w_pcm_resampled.len()
1680 );
1681 {
1683 let (res, inp, out) = (
1684 &mut self.silk_resampler,
1685 state_ref(&self.w_pcm_i16),
1686 state_mut(&mut self.w_pcm_resampled),
1687 );
1688 res.process(
1689 &mut out[..resampled_len],
1690 &inp[..decoded_samples],
1691 decoded_samples as i32,
1692 );
1693 }
1694 if self.channels == 2 {
1696 let (res, inp, out) = (
1697 &mut self.silk_resampler_2,
1698 state_ref(&self.w_pcm_i16),
1699 state_mut(&mut self.w_pcm_resampled),
1700 );
1701 res.process(
1702 &mut out[resampled_len..2 * resampled_len],
1703 &inp[decoded_samples..2 * decoded_samples],
1704 decoded_samples as i32,
1705 );
1706 }
1707 for i in 0..copy_len {
1708 for ch in 0..self.channels {
1709 let v = self.w_pcm_resampled[ch * resampled_len + i] as f32
1710 / 32768.0;
1711 let idx = (api_pos + i) * self.channels + ch;
1712 if idx < silk_out_len {
1713 self.w_silk_out[idx] = v;
1714 }
1715 }
1716 }
1717 }
1718 frame_pos += decoded_samples;
1719 }
1720
1721 let total_bits = (payload.len() * 8) as i32;
1722 let redundancy = rc.decode_bit_logp(12);
1723 let skip_celt = if redundancy {
1724 let _celt_to_silk = rc.decode_bit_logp(1);
1725 has_redundancy = true;
1726 true
1732 } else {
1733 false
1734 };
1735
1736 if skip_celt {
1737 self.w_celt_out[..silk_out_len].fill(0.0);
1738 } else {
1739 let (celt_dec, celt_planar) = (
1740 state_mut(&mut self.celt_dec),
1741 state_mut(&mut self.w_celt_planar),
1742 );
1743 celt_dec.decode_from_range_coder_with_band_range(
1744 &mut rc,
1745 total_bits,
1746 sub_frame_size,
1747 &mut celt_planar[..silk_out_len],
1748 17,
1749 celt_end_band,
1750 );
1751
1752 if self.channels == 1 {
1753 self.w_celt_out[..silk_out_len]
1754 .copy_from_slice(&self.w_celt_planar[..silk_out_len]);
1755 } else {
1756 for i in 0..sub_frame_size {
1757 for ch in 0..self.channels {
1758 self.w_celt_out[i * self.channels + ch] =
1759 self.w_celt_planar[ch * sub_frame_size + i];
1760 }
1761 }
1762 }
1763 }
1764
1765 let out_start = fi * silk_out_len;
1766 let total = silk_out_len.min(output.len() - out_start);
1767 for j in 0..total {
1768 output[out_start + j] =
1769 (self.w_silk_out[j] + self.w_celt_out[j]).clamp(-1.0, 1.0);
1770 }
1771 }
1772 decoded_total
1773 }
1774 };
1775
1776 let f2_5 = self.sampling_rate as usize / 400;
1782 let f5 = f2_5 * 2;
1783 if mode_transition && f5 > 0 && decoded_total >= f5 {
1784 let window = modes::default_mode().window;
1785 let inc = (48000 / self.sampling_rate) as usize;
1786 let f2_5_ch = f2_5 * self.channels;
1787 let f5_ch = f5 * self.channels;
1788 output[..f2_5_ch].copy_from_slice(&self.prev_pcm_tail[..f2_5_ch]);
1790 let new_mid: FixedVec<f32, OPUS_PCM_TAIL> =
1792 FixedVec::from_slice(&output[f2_5_ch..f5_ch]);
1793 smooth_fade(
1794 &self.prev_pcm_tail[f2_5_ch..f5_ch],
1795 &new_mid,
1796 &mut output[f2_5_ch..f5_ch],
1797 f2_5,
1798 self.channels,
1799 window,
1800 inc,
1801 );
1802 }
1803
1804 let tail_len = f5 * self.channels;
1806 let out_total = decoded_total * self.channels;
1807 if out_total >= tail_len && tail_len <= self.prev_pcm_tail.len() {
1808 self.prev_pcm_tail[..tail_len]
1809 .copy_from_slice(&output[out_total - tail_len..out_total]);
1810 }
1811
1812 self.prev_mode = Some(mode);
1813 self.prev_redundancy = has_redundancy;
1814 Ok(decoded_total)
1815 }
1816}
1817
1818impl OpusDecoder {
1819 #[inline(always)]
1820 fn celt_end_band_from_toc(&self, toc: u8) -> usize {
1821 let mode = modes::default_mode();
1822 let top = mode.eff_ebands;
1823 if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
1824 const FROM_OPUS_TABLE: [u8; 16] = [
1825 0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
1826 0x10, 0x18,
1827 ];
1828 let idx = ((toc >> 3) - 16) as usize;
1829 let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
1830 let trim = (data0 >> 5) as usize;
1831 return top.saturating_sub(2 * trim).max(1);
1832 }
1833 top
1834 }
1835}
1836
1837fn frame_rate_from_params(sampling_rate: i32, frame_size: usize) -> Option<i32> {
1838 let frame_size = frame_size as i32;
1839 if frame_size == 0 || sampling_rate % frame_size != 0 {
1840 return None;
1841 }
1842 Some(sampling_rate / frame_size)
1843}
1844
1845fn gen_toc(mode: OpusMode, frame_rate: i32, bandwidth: Bandwidth, channels: usize) -> u8 {
1846 let mut rate = frame_rate;
1847 let mut period = 0;
1848 while rate < 400 {
1849 rate <<= 1;
1850 period += 1;
1851 }
1852
1853 let mut toc = match mode {
1854 OpusMode::SilkOnly => {
1855 let bw = (bandwidth as i32 - Bandwidth::Narrowband as i32) << 5;
1856 let per = (period - 2) << 3;
1857 (bw | per) as u8
1858 }
1859 OpusMode::CeltOnly => {
1860 let mut tmp = bandwidth as i32 - Bandwidth::Mediumband as i32;
1861 if tmp < 0 {
1862 tmp = 0;
1863 }
1864 let per = period << 3;
1865 (0x80 | (tmp << 5) | per) as u8
1866 }
1867 OpusMode::Hybrid => {
1868 let base_config = if bandwidth == Bandwidth::Superwideband {
1869 12
1870 } else {
1871 14
1872 };
1873 let period_offset = if frame_rate >= 100 { 0 } else { 1 };
1874 ((base_config + period_offset) << 3) as u8
1875 }
1876 };
1877
1878 if channels == 2 {
1879 toc |= 0x04;
1880 }
1881 toc
1882}
1883
1884fn mode_from_toc(toc: u8) -> OpusMode {
1885 if toc & 0x80 != 0 {
1886 OpusMode::CeltOnly
1887 } else if toc & 0x60 == 0x60 {
1888 OpusMode::Hybrid
1889 } else {
1890 OpusMode::SilkOnly
1891 }
1892}
1893
1894fn bandwidth_from_toc(toc: u8) -> Bandwidth {
1895 let mode = mode_from_toc(toc);
1896 match mode {
1897 OpusMode::SilkOnly => {
1898 let bw_bits = (toc >> 5) & 0x03;
1899 match bw_bits {
1900 0 => Bandwidth::Narrowband,
1901 1 => Bandwidth::Mediumband,
1902 2 => Bandwidth::Wideband,
1903 _ => Bandwidth::Wideband,
1904 }
1905 }
1906 OpusMode::Hybrid => {
1907 let bw_bit = (toc >> 4) & 0x01;
1908 if bw_bit == 0 {
1909 Bandwidth::Superwideband
1910 } else {
1911 Bandwidth::Fullband
1912 }
1913 }
1914 OpusMode::CeltOnly => {
1915 let bw_bits = (toc >> 5) & 0x03;
1916 match bw_bits {
1917 0 => Bandwidth::Mediumband,
1918 1 => Bandwidth::Wideband,
1919 2 => Bandwidth::Superwideband,
1920 3 => Bandwidth::Fullband,
1921 _ => Bandwidth::Fullband,
1922 }
1923 }
1924 }
1925}
1926
1927fn frame_duration_ms_from_toc(toc: u8) -> i32 {
1928 let mode = mode_from_toc(toc);
1929 match mode {
1930 OpusMode::SilkOnly => {
1931 let config = (toc >> 3) & 0x03;
1932 match config {
1933 0 => 10,
1934 1 => 20,
1935 2 => 40,
1936 3 => 60,
1937 _ => 20,
1938 }
1939 }
1940 OpusMode::Hybrid => {
1941 let config = (toc >> 3) & 0x01;
1942 if config == 0 { 10 } else { 20 }
1943 }
1944 OpusMode::CeltOnly => {
1945 let config = (toc >> 3) & 0x03;
1946 match config {
1947 0 => 2,
1948 1 => 5,
1949 2 => 10,
1950 3 => 20,
1951 _ => 20,
1952 }
1953 }
1954 }
1955}
1956
1957fn frame_samples_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
1961 let mode = mode_from_toc(toc);
1962 match mode {
1963 OpusMode::CeltOnly => {
1964 let period = ((toc >> 3) & 0x03) as i32;
1965 let frame_rate = 400 >> period;
1966 if frame_rate == 0 || sampling_rate % frame_rate != 0 {
1967 return None;
1968 }
1969 Some((sampling_rate / frame_rate) as usize)
1970 }
1971 OpusMode::SilkOnly | OpusMode::Hybrid => {
1972 let duration_ms = frame_duration_ms_from_toc(toc);
1973 Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1974 }
1975 }
1976}
1977
1978fn channels_from_toc(toc: u8) -> usize {
1979 if toc & 0x04 != 0 { 2 } else { 1 }
1980}
1981
1982fn smooth_fade(
1985 in1: &[f32],
1986 in2: &[f32],
1987 out: &mut [f32],
1988 overlap: usize,
1989 channels: usize,
1990 window: &[f32],
1991 inc: usize,
1992) {
1993 for c in 0..channels {
1994 for i in 0..overlap {
1995 let wi = i * inc;
1996 if wi >= window.len() {
1997 break;
1998 }
1999 let w = window[wi] * window[wi];
2000 out[i * channels + c] = w * in2[i * channels + c] + (1.0 - w) * in1[i * channels + c];
2001 }
2002 }
2003}
2004
2005fn parse_frame_size(data: &[u8]) -> Result<(usize, usize), &'static str> {
2013 let first = *data.first().ok_or("truncated frame length")? as usize;
2014 if first < 252 {
2015 Ok((first, 1))
2016 } else {
2017 let second = *data.get(1).ok_or("truncated frame length")? as usize;
2018 Ok((second * 4 + first, 2))
2019 }
2020}
2021
2022#[cfg(all(test, feature = "std"))]
2023mod tests {
2024 use super::*;
2025
2026 fn frame_size_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
2027 let mode = mode_from_toc(toc);
2028 match mode {
2029 OpusMode::CeltOnly => {
2030 let period = ((toc >> 3) & 0x03) as i32;
2031 let frame_rate = 400 >> period;
2032 if frame_rate == 0 || sampling_rate % frame_rate != 0 {
2033 return None;
2034 }
2035 Some((sampling_rate / frame_rate) as usize)
2036 }
2037 OpusMode::SilkOnly => {
2038 let duration_ms = frame_duration_ms_from_toc(toc);
2039 Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
2040 }
2041 OpusMode::Hybrid => {
2042 let duration_ms = frame_duration_ms_from_toc(toc);
2043 Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
2044 }
2045 }
2046 }
2047
2048 #[test]
2049 fn gen_toc_matches_celt_reference_values() {
2050 let sampling_rate = 48_000;
2051 let cases = [
2052 (120usize, 0xE0u8),
2053 (240usize, 0xE8u8),
2054 (480usize, 0xF0u8),
2055 (960usize, 0xF8u8),
2056 ];
2057
2058 for (frame_size, expected_toc) in cases {
2059 let frame_rate = frame_rate_from_params(sampling_rate, frame_size).unwrap();
2060 let toc = gen_toc(OpusMode::CeltOnly, frame_rate, Bandwidth::Fullband, 1);
2061 assert_eq!(
2062 toc, expected_toc,
2063 "frame_size {} expected TOC {:02X} got {:02X}",
2064 frame_size, expected_toc, toc
2065 );
2066 let decoded_size = frame_size_from_toc(toc, sampling_rate).unwrap();
2067 assert_eq!(decoded_size, frame_size);
2068 }
2069
2070 let stereo_toc = gen_toc(
2071 OpusMode::CeltOnly,
2072 frame_rate_from_params(sampling_rate, 960).unwrap(),
2073 Bandwidth::Fullband,
2074 2,
2075 );
2076 assert_eq!(channels_from_toc(stereo_toc), 2);
2077 }
2078
2079 #[test]
2080 fn test_celt_decoder_large_frame_sizes() {
2081 let sampling_rate = 48000;
2082 let channels = 1;
2083
2084 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2085
2086 let frame_sizes = [120, 240, 480, 960];
2087
2088 for frame_size in frame_sizes {
2089 let toc = gen_toc(
2090 OpusMode::CeltOnly,
2091 frame_rate_from_params(sampling_rate, frame_size).unwrap(),
2092 Bandwidth::Fullband,
2093 channels,
2094 );
2095 let packet = [toc, 0, 0, 0, 0];
2096
2097 let mut output = vec![0.0f32; frame_size * channels];
2098
2099 let _ = decoder.decode(&packet, frame_size, &mut output);
2100 }
2101
2102 let channels = 2;
2103 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2104
2105 for frame_size in frame_sizes {
2106 let toc = gen_toc(
2107 OpusMode::CeltOnly,
2108 frame_rate_from_params(sampling_rate, frame_size).unwrap(),
2109 Bandwidth::Fullband,
2110 channels,
2111 );
2112 let packet = [toc, 0, 0, 0, 0];
2113
2114 let mut output = vec![0.0f32; frame_size * channels];
2115 let _ = decoder.decode(&packet, frame_size, &mut output);
2116 }
2117 }
2118
2119 #[test]
2120 fn test_celt_decoder_edge_case_frame_sizes() {
2121 let sampling_rate = 48000;
2122 let channels = 1;
2123 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
2124
2125 let edge_sizes = [2048, 2167, 2168, 2169, 2880, 3072];
2126
2127 for frame_size in edge_sizes {
2128 let mut output = vec![0.0f32; frame_size * channels];
2129
2130 let _ = decoder.decode(&[0x80, 0, 0, 0], frame_size, &mut output);
2131 }
2132 }
2133
2134 #[test]
2141 fn test_invalid_small_frame_size_returns_error_not_panic() {
2142 let mut enc = OpusEncoder::new(48000, 2, Application::Voip).unwrap();
2143 enc.bitrate_bps = 64000;
2144 enc.complexity = 5;
2145 enc.use_cbr = true;
2146
2147 let input = vec![0.0f32; 48 * 2]; let mut output = vec![0u8; 256];
2150
2151 let result = enc.encode(&input, 48, &mut output);
2152 assert!(
2153 result.is_err(),
2154 "encode with invalid frame_size=48 should return Err, not panic"
2155 );
2156 }
2157
2158 #[test]
2161 fn test_invalid_small_frame_size_audio_application_returns_error() {
2162 let mut enc = OpusEncoder::new(48000, 1, Application::Audio).unwrap();
2163 let input = vec![0.0f32; 48];
2164 let mut output = vec![0u8; 256];
2165
2166 let result = enc.encode(&input, 48, &mut output);
2167 assert!(
2168 result.is_err(),
2169 "Audio/48kHz encoder with frame_size=48 should return Err"
2170 );
2171 }
2172}