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 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 let toc = gen_toc(mode, frame_rate, self.bandwidth, self.channels);
395 output[0] = toc;
396
397 let target_bits =
398 (self.bitrate_bps as i64 * frame_size as i64 / self.sampling_rate as i64) as i32;
399 let cbr_bytes = ((target_bits + 4) / 8) as usize;
400 let max_data_bytes = output.len();
401
402 let n_bytes = cbr_bytes.min(max_data_bytes).max(1);
403
404 let init_rc_size = n_bytes - 1;
405 self.rc.reset_for_encode(init_rc_size as u32);
406
407 if mode == OpusMode::SilkOnly || mode == OpusMode::Hybrid {
408 let silk_fs_khz = if mode == OpusMode::Hybrid {
409 16
410 } else {
411 self.sampling_rate.min(16000) / 1000
412 };
413
414 let frame_ms = (frame_size as i32 * 1000) / self.sampling_rate;
415 if !self.silk_initialized || self.silk_enc.s_cmn.fs_khz != silk_fs_khz {
416 let silk_init_bitrate = (((n_bytes - 1) * 8) as i64 * self.sampling_rate as i64
417 / frame_size as i64) as i32;
418 silk_control_encoder(
419 &mut self.silk_enc,
420 silk_fs_khz,
421 frame_ms,
422 silk_init_bitrate,
423 self.complexity,
424 );
425 self.silk_enc.s_cmn.use_cbr = if self.use_cbr { 1 } else { 0 };
426
427 self.silk_enc.s_cmn.n_channels = self.channels as i32;
428 self.silk_initialized = true;
429 self.down2_state_first = [0; 2];
430 self.down2_state_second = [0; 2];
431 self.down2_3_state = [0; 6];
432 self.down_1_3_state = silk::resampler::SilkResamplerDown1_3::default();
433 }
434
435 self.silk_enc.s_cmn.use_in_band_fec = if self.use_inband_fec { 1 } else { 0 };
436 self.silk_enc.s_cmn.packet_loss_perc = self.packet_loss_perc.clamp(0, 100);
437
438 self.silk_enc.s_cmn.lbrr_enabled = if self.use_inband_fec { 1 } else { 0 };
439
440 if self.silk_enc.s_cmn.lbrr_gain_increases == 0 {
441 self.silk_enc.s_cmn.lbrr_gain_increases = 2;
442 }
443
444 let hp_freq_smth1 = if mode == OpusMode::CeltOnly {
445 silk_lin2log(60) << 8
446 } else {
447 self.silk_enc.s_cmn.variable_hp_smth1_q15
448 };
449
450 const VARIABLE_HP_SMTH_COEF2_Q16: i32 = 984;
451 self.variable_hp_smth2_q15 = silk_smlawb(
452 self.variable_hp_smth2_q15,
453 hp_freq_smth1 - self.variable_hp_smth2_q15,
454 VARIABLE_HP_SMTH_COEF2_Q16,
455 );
456
457 let cutoff_hz = silk_log2lin(silk_rshift(self.variable_hp_smth2_q15, 8));
458
459 let required_size = frame_size * self.channels;
460 self.buf_filtered.resize(required_size, 0);
461 if self.application == Application::Voip {
462 hp_cutoff(
463 input,
464 cutoff_hz,
465 &mut self.buf_filtered,
466 &mut self.hp_mem,
467 frame_size,
468 self.channels,
469 self.sampling_rate,
470 );
471 } else {
472 for (i, &x) in input.iter().enumerate() {
473 self.buf_filtered[i] = (x * 32768.0).clamp(-32768.0, 32767.0) as i16;
474 }
475 }
476
477 let input_i16 = &self.buf_filtered;
478
479 let silk_input: &[i16] = if mode == OpusMode::SilkOnly && self.sampling_rate > 16000 {
480 if self.sampling_rate == 48000 {
481 let stage1_size = frame_size / 2;
482 let mut stage1_buf = [0i16; 480];
483 silk_resampler_down2(
484 &mut self.down2_state_first,
485 &mut stage1_buf[..stage1_size],
486 input_i16,
487 frame_size as i32,
488 );
489 let silk_frame_size = stage1_size * 2 / 3;
490 self.buf_silk_input.resize(silk_frame_size, 0);
491 silk_resampler_down2_3(
492 &mut self.down2_3_state,
493 &mut self.buf_silk_input,
494 &stage1_buf[..stage1_size],
495 stage1_size as i32,
496 );
497 &self.buf_silk_input
498 } else if self.sampling_rate == 24000 {
499 let silk_frame_size = frame_size * 2 / 3;
500 self.buf_silk_input.resize(silk_frame_size, 0);
501 silk_resampler_down2_3(
502 &mut self.down2_3_state,
503 &mut self.buf_silk_input,
504 input_i16,
505 frame_size as i32,
506 );
507 &self.buf_silk_input
508 } else {
509 input_i16
510 }
511 } else if mode == OpusMode::SilkOnly && self.channels == 2 {
512 let frame_length = input_i16.len() / 2;
513 self.buf_stereo_mid.resize(frame_length, 0);
514 self.buf_stereo_side.resize(frame_length, 0);
515 for i in 0..frame_length {
516 let l = input_i16[2 * i] as i32;
517 let r = input_i16[2 * i + 1] as i32;
518 self.buf_stereo_mid[i] = ((l + r) / 2) as i16;
519 self.buf_stereo_side[i] = (l - r) as i16;
520 }
521
522 self.silk_enc.stereo.side.resize(frame_length, 0);
523 self.silk_enc
524 .stereo
525 .side
526 .copy_from_slice(&self.buf_stereo_side[..frame_length]);
527 &self.buf_stereo_mid
528 } else if mode == OpusMode::Hybrid && self.sampling_rate > 16000 {
529 if self.sampling_rate == 48000 {
530 let silk_frame_size = frame_size / 3;
531 self.buf_silk_input.resize(silk_frame_size, 0);
532 silk::resampler::silk_resampler_down_1_3(
533 &mut self.down_1_3_state,
534 &mut self.buf_silk_input,
535 input_i16,
536 );
537 } else {
538 let silk_frame_size = frame_size * 2 / 3;
539 self.buf_silk_input.resize(silk_frame_size, 0);
540 silk_resampler_down2_3(
541 &mut self.down2_3_state,
542 &mut self.buf_silk_input,
543 input_i16,
544 frame_size as i32,
545 );
546 }
547 &self.buf_silk_input
548 } else {
549 input_i16
550 };
551
552 let mut pn_bytes = 0;
553
554 let silk_rate_for_calc = if mode == OpusMode::Hybrid {
555 16000
556 } else {
557 self.sampling_rate
558 };
559 let silk_frame_len = silk_input.len();
560
561 let silk_bitrate = if mode == OpusMode::Hybrid {
562 let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
563 let frame20ms = frame_duration_ms >= 20;
564 compute_silk_rate_for_hybrid(self.bitrate_bps, frame20ms)
565 } else {
566 (8i64 * (n_bytes - 1) as i64 * silk_rate_for_calc as i64 / silk_frame_len as i64)
567 as i32
568 };
569 let silk_max_bits = if mode == OpusMode::Hybrid {
570 let total_max_bits = ((n_bytes - 1) * 8) as i32;
571 if self.use_cbr {
572 let silk_bits = (silk_bitrate as i64 * silk_frame_len as i64
573 / silk_rate_for_calc as i64) as i32;
574 let other_bits = 0i32.max(total_max_bits - silk_bits);
575 0i32.max(total_max_bits - other_bits * 3 / 4)
576 } else {
577 let frame_duration_ms = frame_size as i32 * 1000 / self.sampling_rate;
578 let frame20ms = frame_duration_ms >= 20;
579 let max_bit_rate = compute_silk_rate_for_hybrid(
580 total_max_bits * self.sampling_rate / frame_size as i32,
581 frame20ms,
582 );
583 max_bit_rate * frame_size as i32 / self.sampling_rate
584 }
585 } else {
586 ((n_bytes - 1) * 8) as i32
587 };
588 let silk_use_cbr = if mode == OpusMode::Hybrid && self.use_cbr {
589 0
590 } else if self.use_cbr {
591 1
592 } else {
593 0
594 };
595 let ret = silk_encode(
596 &mut self.silk_enc,
597 silk_input,
598 silk_input.len(),
599 &mut self.rc,
600 &mut pn_bytes,
601 silk_bitrate,
602 silk_max_bits,
603 silk_use_cbr,
604 1,
605 );
606 if ret != 0 {
607 return Err("SILK encoding failed");
608 }
609 }
610
611 if mode == OpusMode::Hybrid {
612 self.rc.encode_bit_logp(false, 12); }
614
615 if mode == OpusMode::Hybrid {
616 let nb_compr_bytes = (n_bytes - 1) as u32;
617 self.rc.shrink(nb_compr_bytes);
618 }
619
620 let silk_ret_bytes = if mode == OpusMode::SilkOnly {
621 ((self.rc.tell() + 7) >> 3) as usize
622 } else {
623 0
624 };
625
626 if mode == OpusMode::CeltOnly || mode == OpusMode::Hybrid {
627 self.celt_enc.complexity = self.complexity;
628 let start_band = if mode == OpusMode::Hybrid { 17 } else { 0 };
629 let total_packet_bits = ((n_bytes - 1) * 8) as i32;
630
631 let celt_input: &[f32] = if self.channels == 1 {
632 input
633 } else {
634 let n = frame_size * self.channels;
635 self.buf_celt_input.resize(n, 0.0);
636 for i in 0..frame_size {
637 for ch in 0..self.channels {
638 self.buf_celt_input[ch * frame_size + i] = input[i * self.channels + ch];
639 }
640 }
641 &self.buf_celt_input
642 };
643
644 if self.rc.tell() <= total_packet_bits {
645 self.celt_enc.encode_with_budget(
646 celt_input,
647 frame_size,
648 &mut self.rc,
649 start_band,
650 total_packet_bits,
651 );
652 }
653 }
654
655 self.rc.done();
656
657 if mode == OpusMode::SilkOnly {
658 let mut ret = silk_ret_bytes.min(self.rc.storage as usize);
659 while ret > 2 && self.rc.buf[ret - 1] == 0 {
660 ret -= 1;
661 }
662
663 let target_total = if self.use_cbr {
664 n_bytes.min(output.len())
665 } else {
666 (ret + 1).min(output.len())
667 };
668
669 let silk_len = ret;
670
671 if !self.use_cbr || silk_len + 1 >= target_total {
672 output[0] = toc;
674 let copy_len = silk_len.min(target_total - 1);
675 output[1..1 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
676 return Ok((copy_len + 1).min(output.len()));
677 }
678
679 output[0] = toc | 0x03;
680
681 if silk_len + 2 >= target_total {
682 output[1] = 0x01;
683 let copy_len = (target_total - 2).min(silk_len);
684 output[2..2 + copy_len].copy_from_slice(&self.rc.buf[..copy_len]);
685 self.prev_enc_mode = Some(mode);
686 return Ok(target_total.min(output.len()));
687 }
688
689 let pad_amount = target_total - silk_len - 2;
690 output[1] = 0x41;
691
692 let nb_255s = (pad_amount - 1) / 255;
693 let mut ptr = 2;
694 for _ in 0..nb_255s {
695 output[ptr] = 255;
696 ptr += 1;
697 }
698 output[ptr] = (pad_amount - 255 * nb_255s - 1) as u8;
699 ptr += 1;
700
701 output[ptr..ptr + silk_len].copy_from_slice(&self.rc.buf[..silk_len]);
702 ptr += silk_len;
703
704 let fill_end = target_total.min(output.len());
705 for byte in output[ptr..fill_end].iter_mut() {
706 *byte = 0;
707 }
708
709 self.prev_enc_mode = Some(mode);
710 return Ok(target_total.min(output.len()));
711 }
712
713 let payload_len = n_bytes - 1;
714 output[1..1 + payload_len].copy_from_slice(&self.rc.buf[..payload_len]);
715 self.prev_enc_mode = Some(mode);
716 Ok(n_bytes)
717 }
718}
719
720pub struct OpusDecoder {
721 celt_dec: CeltDecoder,
722 silk_dec: silk::dec_api::SilkDecoder,
723 sampling_rate: i32,
724 channels: usize,
725
726 prev_mode: Option<OpusMode>,
727 frame_size: usize,
728
729 bandwidth: Bandwidth,
730
731 stream_channels: usize,
732
733 silk_resampler: silk::resampler::SilkResampler,
734
735 prev_internal_rate: i32,
736
737 pub hybrid_skip_celt: bool,
738
739 w_pcm_i16: Vec<i16>,
740 w_silk_out: Vec<f32>,
741 w_pcm_resampled: Vec<i16>,
742 w_celt_planar: Vec<f32>,
743 w_celt_out: Vec<f32>,
744}
745
746impl OpusDecoder {
747 pub fn new(sampling_rate: i32, channels: usize) -> Result<Self, &'static str> {
748 if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
749 return Err("Invalid sampling rate");
750 }
751 if ![1, 2].contains(&channels) {
752 return Err("Invalid number of channels");
753 }
754
755 let mode = modes::default_mode();
756 let celt_dec = CeltDecoder::new(mode, channels);
757
758 let mut silk_dec = silk::dec_api::SilkDecoder::new();
759 silk_dec.init(sampling_rate.min(16000), channels as i32);
760 silk_dec.channel_state[0].fs_api_hz = sampling_rate;
761
762 Ok(Self {
763 celt_dec,
764 silk_dec,
765 sampling_rate,
766 channels,
767 prev_mode: None,
768 frame_size: 0,
769 bandwidth: Bandwidth::Auto,
770 stream_channels: channels,
771 silk_resampler: silk::resampler::SilkResampler::default(),
772 prev_internal_rate: 0,
773 hybrid_skip_celt: false,
774
775 w_pcm_i16: vec![0i16; 640],
776
777 w_silk_out: vec![0.0f32; 5760 * channels],
778 w_pcm_resampled: vec![0i16; 5760 * channels],
779 w_celt_planar: vec![0.0f32; 5760 * channels],
780 w_celt_out: vec![0.0f32; 5760 * channels],
781 })
782 }
783
784 pub fn decode(
785 &mut self,
786 input: &[u8],
787 frame_size: usize,
788 output: &mut [f32],
789 ) -> Result<usize, &'static str> {
790 if input.is_empty() {
791 return Err("Input packet empty");
792 }
793
794 let toc = input[0];
795 let mode = mode_from_toc(toc);
796 let packet_channels = channels_from_toc(toc);
797 let bandwidth = bandwidth_from_toc(toc);
798 let frame_duration_ms = frame_duration_ms_from_toc(toc);
799
800 if packet_channels != self.channels {
801 return Err("Channel count mismatch between packet and decoder");
802 }
803
804 let code = toc & 0x03;
805 let frame_count: usize;
806 let frame_payloads: Vec<&[u8]>;
807
808 match code {
809 0 => {
810 frame_count = 1;
811 frame_payloads = vec![&input[1..]];
812 }
813 1 => {
814 frame_count = 2;
815 let half = (input.len() - 1) / 2;
816 if half == 0 {
817 return Err("Code 1: empty frame");
818 }
819 frame_payloads = vec![&input[1..1 + half], &input[1 + half..]];
820 }
821 2 => {
822 frame_count = 2;
823 let data = &input[1..];
824 if data.is_empty() {
825 return Err("Code 2 packet has no data");
826 }
827 let (first_len, header_size) = if data[0] & 0x80 != 0 {
828 if data.len() < 2 {
829 return Err("Code 2 packet too short for 2-byte length");
830 }
831 (((data[0] & 0x7F) as usize) << 8 | data[1] as usize, 2)
832 } else {
833 (data[0] as usize, 1)
834 };
835 if header_size + first_len > data.len() {
836 return Err("Code 2: first frame size exceeds packet");
837 }
838 frame_payloads = vec![
839 &data[header_size..header_size + first_len],
840 &data[header_size + first_len..],
841 ];
842 }
843 3 => {
844 if input.len() < 2 {
845 return Err("Code 3 packet too short");
846 }
847 let count_byte = input[1];
848 let n_frames = (count_byte & 0x3F) as usize;
849 if n_frames < 1 || n_frames > 48 {
850 return Err("Code 3: invalid frame count");
851 }
852 frame_count = n_frames;
853 let padding_flag = (count_byte & 0x40) != 0;
854
855 if padding_flag {
856 let mut ptr = 2usize;
857 let mut pad_len = 0usize;
858 loop {
859 if ptr >= input.len() {
860 return Err("Padding overflow");
861 }
862 let p = input[ptr] as usize;
863 ptr += 1;
864 if p == 255 {
865 pad_len += 254;
866 } else {
867 pad_len += p;
868 break;
869 }
870 }
871
872 let end = input.len().saturating_sub(pad_len);
873 if ptr > end {
874 return Err("Padding exceeds packet");
875 }
876 let compressed = &input[ptr..end];
877 let frame_len = compressed.len() / frame_count;
878 if frame_len == 0 {
879 return Err("Code 3 with padding: empty frame");
880 }
881 frame_payloads = compressed.chunks(frame_len).collect();
882 if frame_payloads.len() != frame_count {
883 return Err("Code 3: frame count mismatch");
884 }
885 } else {
886 let mut payload_ptr = 2usize;
890 if frame_count == 1 {
891 frame_payloads = vec![&input[payload_ptr..]];
892 } else {
893 let mut payloads = Vec::with_capacity(frame_count);
894 for _f in 0..frame_count - 1 {
895 if payload_ptr >= input.len() {
896 return Err("Code 3: unexpected end in self-delimiting header");
897 }
898 let (frame_len, header_bytes) = if input[payload_ptr] & 0x80 != 0 {
899 if payload_ptr + 2 > input.len() {
900 return Err("Code 3: short frame length");
901 }
902 (
903 ((input[payload_ptr] & 0x7F) as usize) << 8
904 | input[payload_ptr + 1] as usize,
905 2,
906 )
907 } else {
908 (input[payload_ptr] as usize, 1)
909 };
910 payload_ptr += header_bytes;
911 if payload_ptr + frame_len > input.len() {
912 return Err("Code 3: frame length exceeds packet");
913 }
914 payloads.push(&input[payload_ptr..payload_ptr + frame_len]);
915 payload_ptr += frame_len;
916 }
917 if payload_ptr > input.len() {
919 return Err("Code 3: no data for last frame");
920 }
921 payloads.push(&input[payload_ptr..]);
922 frame_payloads = payloads;
923 }
924 }
925 }
926 _ => unreachable!(),
927 }
928
929 self.frame_size = frame_size;
930 self.bandwidth = bandwidth;
931 self.stream_channels = packet_channels;
932
933 let sub_frame_size = frame_size / frame_count;
934 let sub_output_len = sub_frame_size * self.channels;
935
936 match mode {
937 OpusMode::SilkOnly => {
938 let internal_sample_rate = match bandwidth {
939 Bandwidth::Narrowband => 8000,
940 Bandwidth::Mediumband => 12000,
941 Bandwidth::Wideband => 16000,
942 _ => 16000,
943 };
944 let internal_frame_size =
945 (frame_duration_ms * internal_sample_rate / 1000) as usize;
946
947 if self.sampling_rate != internal_sample_rate
948 && internal_sample_rate != self.prev_internal_rate
949 {
950 self.silk_resampler
951 .init(internal_sample_rate, self.sampling_rate);
952 self.prev_internal_rate = internal_sample_rate;
953 }
954
955 for (fi, payload) in frame_payloads.iter().enumerate() {
956 let mut rc = RangeCoder::new_decoder(payload);
957 let pcm_i16_len = internal_frame_size * self.channels;
958 debug_assert!(pcm_i16_len <= self.w_pcm_i16.len());
959
960 let ret = {
961 let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
962 silk_dec.decode(
963 &mut rc,
964 &mut pcm_i16[..pcm_i16_len],
965 silk::decode_frame::FLAG_DECODE_NORMAL,
966 true,
967 frame_duration_ms,
968 internal_sample_rate,
969 )
970 };
971
972 if ret < 0 {
973 return Err("SILK decoding failed");
974 }
975
976 let decoded_samples = ret as usize;
977 let out_start = fi * sub_output_len;
978
979 if self.sampling_rate == internal_sample_rate {
982 let frames = decoded_samples.min(sub_frame_size);
983 for i in 0..frames {
984 let v = self.w_pcm_i16[i] as f32 / 32768.0;
985 for ch in 0..self.channels {
986 let idx = out_start + i * self.channels + ch;
987 if idx < output.len() {
988 output[idx] = v;
989 }
990 }
991 }
992 } else {
993 let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
994 let out_len =
995 ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
996 debug_assert!(out_len <= self.w_pcm_resampled.len());
997 {
998 let (silk_res, pcm_i16, pcm_out) = (
999 &mut self.silk_resampler,
1000 &self.w_pcm_i16,
1001 &mut self.w_pcm_resampled,
1002 );
1003 silk_res.process(
1004 &mut pcm_out[..out_len],
1005 &pcm_i16[..decoded_samples],
1006 decoded_samples as i32,
1007 );
1008 }
1009 let frames = out_len.min(sub_frame_size);
1010 for i in 0..frames {
1011 let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1012 for ch in 0..self.channels {
1013 let idx = out_start + i * self.channels + ch;
1014 if idx < output.len() {
1015 output[idx] = v;
1016 }
1017 }
1018 }
1019 }
1020 }
1021 self.prev_mode = Some(OpusMode::SilkOnly);
1022 Ok(frame_size)
1023 }
1024
1025 OpusMode::CeltOnly => {
1026 let celt_end_band = self.celt_end_band_from_toc(toc);
1027
1028 for (fi, payload) in frame_payloads.iter().enumerate() {
1029 let mut rc = RangeCoder::new_decoder(payload);
1030 let total_bits = (payload.len() * 8) as i32;
1031 let needed = sub_frame_size * self.channels;
1032 let out_start = fi * needed;
1033 let out_end = (out_start + needed).min(output.len());
1034
1035 if output.len() < out_end {
1036 return Err("Output buffer too small");
1037 }
1038
1039 if self.channels == 1 {
1040 self.celt_dec.decode_from_range_coder_with_band_range(
1041 &mut rc,
1042 total_bits,
1043 sub_frame_size,
1044 &mut output[out_start..out_end],
1045 0,
1046 celt_end_band,
1047 );
1048 for sample in &mut output[out_start..out_end] {
1049 *sample = sample.clamp(-1.0, 1.0);
1050 }
1051 } else {
1052 self.celt_dec.decode_from_range_coder_with_band_range(
1053 &mut rc,
1054 total_bits,
1055 sub_frame_size,
1056 &mut self.w_celt_planar[..needed],
1057 0,
1058 celt_end_band,
1059 );
1060 for i in 0..sub_frame_size {
1061 for ch in 0..self.channels {
1062 let idx = out_start + i * self.channels + ch;
1063 output[idx] =
1064 self.w_celt_planar[ch * sub_frame_size + i].clamp(-1.0, 1.0);
1065 }
1066 }
1067 }
1068 }
1069 self.prev_mode = Some(OpusMode::CeltOnly);
1070 Ok(frame_size)
1071 }
1072
1073 OpusMode::Hybrid => {
1074 let internal_sample_rate = 16000;
1075 let internal_frame_size =
1076 (frame_duration_ms * internal_sample_rate / 1000) as usize;
1077 let celt_end_band = self.celt_end_band_from_toc(toc);
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.prev_internal_rate = internal_sample_rate;
1085 }
1086
1087 for (fi, payload) in frame_payloads.iter().enumerate() {
1088 let mut rc = RangeCoder::new_decoder(payload);
1089 let pcm_silk_i16_len = internal_frame_size * self.channels;
1090 debug_assert!(pcm_silk_i16_len <= self.w_pcm_i16.len());
1091
1092 let ret = {
1093 let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1094 silk_dec.decode(
1095 &mut rc,
1096 &mut pcm_i16[..pcm_silk_i16_len],
1097 silk::decode_frame::FLAG_DECODE_NORMAL,
1098 true,
1099 frame_duration_ms,
1100 internal_sample_rate,
1101 )
1102 };
1103
1104 if ret < 0 {
1105 return Err("SILK decoding failed");
1106 }
1107
1108 let silk_out_len = sub_frame_size * self.channels;
1109 self.w_silk_out[..silk_out_len].fill(0.0);
1110 if ret > 0 {
1111 let decoded_samples = ret as usize;
1112 if self.sampling_rate == internal_sample_rate {
1115 let frames = decoded_samples.min(sub_frame_size);
1116 for i in 0..frames {
1117 let v = self.w_pcm_i16[i] as f32 / 32768.0;
1118 for ch in 0..self.channels {
1119 let idx = i * self.channels + ch;
1120 if idx < silk_out_len {
1121 self.w_silk_out[idx] = v;
1122 }
1123 }
1124 }
1125 } else {
1126 let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1127 let out_len =
1128 ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
1129 debug_assert!(out_len <= self.w_pcm_resampled.len());
1130 {
1131 let (silk_res, pcm_i16, pcm_resampled) = (
1132 &mut self.silk_resampler,
1133 &self.w_pcm_i16,
1134 &mut self.w_pcm_resampled,
1135 );
1136 silk_res.process(
1137 &mut pcm_resampled[..out_len],
1138 &pcm_i16[..decoded_samples],
1139 decoded_samples as i32,
1140 );
1141 }
1142 let frames = out_len.min(sub_frame_size);
1143 for i in 0..frames {
1144 let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1145 for ch in 0..self.channels {
1146 let idx = i * self.channels + ch;
1147 if idx < silk_out_len {
1148 self.w_silk_out[idx] = v;
1149 }
1150 }
1151 }
1152 }
1153 }
1154
1155 let total_bits = (payload.len() * 8) as i32;
1156 let redundancy = rc.decode_bit_logp(12);
1157 let skip_celt = if redundancy {
1158 let _ = rc.decode_bit_logp(1);
1159 true
1160 } else {
1161 false
1162 };
1163
1164 if skip_celt {
1165 self.w_celt_out[..silk_out_len].fill(0.0);
1166 } else {
1167 let (celt_dec, celt_planar) = (&mut self.celt_dec, &mut self.w_celt_planar);
1168 celt_dec.decode_from_range_coder_with_band_range(
1169 &mut rc,
1170 total_bits,
1171 sub_frame_size,
1172 &mut celt_planar[..silk_out_len],
1173 17,
1174 celt_end_band,
1175 );
1176
1177 if self.channels == 1 {
1178 self.w_celt_out[..silk_out_len]
1179 .copy_from_slice(&self.w_celt_planar[..silk_out_len]);
1180 } else {
1181 for i in 0..sub_frame_size {
1182 for ch in 0..self.channels {
1183 self.w_celt_out[i * self.channels + ch] =
1184 self.w_celt_planar[ch * sub_frame_size + i];
1185 }
1186 }
1187 }
1188 }
1189
1190 let out_start = fi * silk_out_len;
1191 let total = silk_out_len.min(output.len() - out_start);
1192 for j in 0..total {
1193 output[out_start + j] =
1194 (self.w_silk_out[j] + self.w_celt_out[j]).clamp(-1.0, 1.0);
1195 }
1196 }
1197 self.prev_mode = Some(OpusMode::Hybrid);
1198 Ok(frame_size)
1199 }
1200 }
1201 }
1202}
1203
1204impl OpusDecoder {
1205 #[inline(always)]
1206 fn celt_end_band_from_toc(&self, toc: u8) -> usize {
1207 let mode = modes::default_mode();
1208 let top = mode.eff_ebands;
1209 if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
1210 const FROM_OPUS_TABLE: [u8; 16] = [
1211 0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
1212 0x10, 0x18,
1213 ];
1214 let idx = ((toc >> 3) - 16) as usize;
1215 let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
1216 let trim = (data0 >> 5) as usize;
1217 return top.saturating_sub(2 * trim).max(1);
1218 }
1219 top
1220 }
1221}
1222
1223fn frame_rate_from_params(sampling_rate: i32, frame_size: usize) -> Option<i32> {
1224 let frame_size = frame_size as i32;
1225 if frame_size == 0 || sampling_rate % frame_size != 0 {
1226 return None;
1227 }
1228 Some(sampling_rate / frame_size)
1229}
1230
1231fn gen_toc(mode: OpusMode, frame_rate: i32, bandwidth: Bandwidth, channels: usize) -> u8 {
1232 let mut rate = frame_rate;
1233 let mut period = 0;
1234 while rate < 400 {
1235 rate <<= 1;
1236 period += 1;
1237 }
1238
1239 let mut toc = match mode {
1240 OpusMode::SilkOnly => {
1241 let bw = (bandwidth as i32 - Bandwidth::Narrowband as i32) << 5;
1242 let per = (period - 2) << 3;
1243 (bw | per) as u8
1244 }
1245 OpusMode::CeltOnly => {
1246 let mut tmp = bandwidth as i32 - Bandwidth::Mediumband as i32;
1247 if tmp < 0 {
1248 tmp = 0;
1249 }
1250 let per = period << 3;
1251 (0x80 | (tmp << 5) | per) as u8
1252 }
1253 OpusMode::Hybrid => {
1254 let base_config = if bandwidth == Bandwidth::Superwideband {
1255 12
1256 } else {
1257 14
1258 };
1259 let period_offset = if frame_rate >= 100 { 0 } else { 1 };
1260 ((base_config + period_offset) << 3) as u8
1261 }
1262 };
1263
1264 if channels == 2 {
1265 toc |= 0x04;
1266 }
1267 toc
1268}
1269
1270fn mode_from_toc(toc: u8) -> OpusMode {
1271 if toc & 0x80 != 0 {
1272 OpusMode::CeltOnly
1273 } else if toc & 0x60 == 0x60 {
1274 OpusMode::Hybrid
1275 } else {
1276 OpusMode::SilkOnly
1277 }
1278}
1279
1280fn bandwidth_from_toc(toc: u8) -> Bandwidth {
1281 let mode = mode_from_toc(toc);
1282 match mode {
1283 OpusMode::SilkOnly => {
1284 let bw_bits = (toc >> 5) & 0x03;
1285 match bw_bits {
1286 0 => Bandwidth::Narrowband,
1287 1 => Bandwidth::Mediumband,
1288 2 => Bandwidth::Wideband,
1289 _ => Bandwidth::Wideband,
1290 }
1291 }
1292 OpusMode::Hybrid => {
1293 let bw_bit = (toc >> 4) & 0x01;
1294 if bw_bit == 0 {
1295 Bandwidth::Superwideband
1296 } else {
1297 Bandwidth::Fullband
1298 }
1299 }
1300 OpusMode::CeltOnly => {
1301 let bw_bits = (toc >> 5) & 0x03;
1302 match bw_bits {
1303 0 => Bandwidth::Mediumband,
1304 1 => Bandwidth::Wideband,
1305 2 => Bandwidth::Superwideband,
1306 3 => Bandwidth::Fullband,
1307 _ => Bandwidth::Fullband,
1308 }
1309 }
1310 }
1311}
1312
1313fn frame_duration_ms_from_toc(toc: u8) -> i32 {
1314 let mode = mode_from_toc(toc);
1315 match mode {
1316 OpusMode::SilkOnly => {
1317 let config = (toc >> 3) & 0x03;
1318 match config {
1319 0 => 10,
1320 1 => 20,
1321 2 => 40,
1322 3 => 60,
1323 _ => 20,
1324 }
1325 }
1326 OpusMode::Hybrid => {
1327 let config = (toc >> 3) & 0x01;
1328 if config == 0 { 10 } else { 20 }
1329 }
1330 OpusMode::CeltOnly => {
1331 let config = (toc >> 3) & 0x03;
1332 match config {
1333 0 => 2,
1334 1 => 5,
1335 2 => 10,
1336 3 => 20,
1337 _ => 20,
1338 }
1339 }
1340 }
1341}
1342
1343fn channels_from_toc(toc: u8) -> usize {
1344 if toc & 0x04 != 0 { 2 } else { 1 }
1345}
1346
1347#[cfg(test)]
1348mod tests {
1349 use super::*;
1350
1351 fn frame_size_from_toc(toc: u8, sampling_rate: i32) -> Option<usize> {
1352 let mode = mode_from_toc(toc);
1353 match mode {
1354 OpusMode::CeltOnly => {
1355 let period = ((toc >> 3) & 0x03) as i32;
1356 let frame_rate = 400 >> period;
1357 if frame_rate == 0 || sampling_rate % frame_rate != 0 {
1358 return None;
1359 }
1360 Some((sampling_rate / frame_rate) as usize)
1361 }
1362 OpusMode::SilkOnly => {
1363 let duration_ms = frame_duration_ms_from_toc(toc);
1364 Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1365 }
1366 OpusMode::Hybrid => {
1367 let duration_ms = frame_duration_ms_from_toc(toc);
1368 Some((sampling_rate as i64 * duration_ms as i64 / 1000) as usize)
1369 }
1370 }
1371 }
1372
1373 #[test]
1374 fn gen_toc_matches_celt_reference_values() {
1375 let sampling_rate = 48_000;
1376 let cases = [
1377 (120usize, 0xE0u8),
1378 (240usize, 0xE8u8),
1379 (480usize, 0xF0u8),
1380 (960usize, 0xF8u8),
1381 ];
1382
1383 for (frame_size, expected_toc) in cases {
1384 let frame_rate = frame_rate_from_params(sampling_rate, frame_size).unwrap();
1385 let toc = gen_toc(OpusMode::CeltOnly, frame_rate, Bandwidth::Fullband, 1);
1386 assert_eq!(
1387 toc, expected_toc,
1388 "frame_size {} expected TOC {:02X} got {:02X}",
1389 frame_size, expected_toc, toc
1390 );
1391 let decoded_size = frame_size_from_toc(toc, sampling_rate).unwrap();
1392 assert_eq!(decoded_size, frame_size);
1393 }
1394
1395 let stereo_toc = gen_toc(
1396 OpusMode::CeltOnly,
1397 frame_rate_from_params(sampling_rate, 960).unwrap(),
1398 Bandwidth::Fullband,
1399 2,
1400 );
1401 assert_eq!(channels_from_toc(stereo_toc), 2);
1402 }
1403
1404 #[test]
1405 fn test_celt_decoder_large_frame_sizes() {
1406 let sampling_rate = 48000;
1407 let channels = 1;
1408
1409 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1410
1411 let frame_sizes = [120, 240, 480, 960];
1412
1413 for frame_size in frame_sizes {
1414 let toc = gen_toc(
1415 OpusMode::CeltOnly,
1416 frame_rate_from_params(sampling_rate, frame_size).unwrap(),
1417 Bandwidth::Fullband,
1418 channels,
1419 );
1420 let packet = [toc, 0, 0, 0, 0];
1421
1422 let mut output = vec![0.0f32; frame_size * channels];
1423
1424 let _ = decoder.decode(&packet, frame_size, &mut output);
1425 }
1426
1427 let channels = 2;
1428 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1429
1430 for frame_size in frame_sizes {
1431 let toc = gen_toc(
1432 OpusMode::CeltOnly,
1433 frame_rate_from_params(sampling_rate, frame_size).unwrap(),
1434 Bandwidth::Fullband,
1435 channels,
1436 );
1437 let packet = [toc, 0, 0, 0, 0];
1438
1439 let mut output = vec![0.0f32; frame_size * channels];
1440 let _ = decoder.decode(&packet, frame_size, &mut output);
1441 }
1442 }
1443
1444 #[test]
1445 fn test_celt_decoder_edge_case_frame_sizes() {
1446 let sampling_rate = 48000;
1447 let channels = 1;
1448 let mut decoder = OpusDecoder::new(sampling_rate, channels).unwrap();
1449
1450 let edge_sizes = [2048, 2167, 2168, 2169, 2880, 3072];
1451
1452 for frame_size in edge_sizes {
1453 let mut output = vec![0.0f32; frame_size * channels];
1454
1455 let _ = decoder.decode(&[0x80, 0, 0, 0], frame_size, &mut output);
1456 }
1457 }
1458}