opus_pure/decoder.rs
1//! The Opus decoder.
2
3use crate::celt::{self, CeltDecoder};
4use crate::config::{Bandwidth, OpusMode};
5use crate::range_coder::RangeCoder;
6use crate::repacketizer;
7use crate::silk;
8use crate::soft_clip::{SoftClip, float_to_i16};
9use crate::toc::{
10 bandwidth_from_toc, celt_endband_for_bandwidth, channels_from_toc, frame_duration_ms_from_toc,
11 mode_from_toc,
12};
13use crate::{Error, Result};
14
15/// An Opus decoder: Opus packets in, PCM out.
16///
17/// One decoder handles one stream, and almost everything it needs is carried
18/// between packets rather than contained in them: filter histories, the
19/// overlap-add buffer, the resampler, and which layer coded the previous frame.
20/// So the same instance has to be fed the whole stream in order, and handing a
21/// packet to a fresh decoder does not produce the same audio as decoding it in
22/// sequence.
23///
24/// A packet says for itself how long it is and which bandwidth and layer it
25/// used, so a decoder needs no configuration beyond the rate and channel count
26/// the caller wants back. It follows the stream wherever the encoder went,
27/// including mode and bandwidth changes mid-stream.
28///
29/// Missing packets are expected rather than exceptional. Call
30/// [`decode`](Self::decode) with an empty slice to conceal a loss, or
31/// [`decode_fec`](Self::decode_fec) on the *following* packet to recover the
32/// gap from a redundant copy if the encoder coded one.
33///
34/// ```
35/// use opus_pure::{Application, OpusDecoder, OpusEncoder};
36///
37/// let mut encoder = OpusEncoder::new(48_000, 2, Application::Audio)?;
38/// let mut decoder = OpusDecoder::new(48_000, 2)?;
39///
40/// let mut packet = vec![0u8; 4000];
41/// let n = encoder.encode(&vec![0.0f32; 960 * 2], 960, &mut packet)?;
42///
43/// let mut pcm = vec![0.0f32; 960 * 2];
44/// assert_eq!(decoder.decode(&packet[..n], 960, &mut pcm)?, 960);
45/// assert_eq!(decoder.decode(&[], 960, &mut pcm)?, 960); // conceal a loss
46/// # Ok::<(), opus_pure::Error>(())
47/// ```
48pub struct OpusDecoder {
49 /// Bits the SILK layer consumed in the last hybrid packet.
50 ///
51 /// Not part of the public API: this exists so `reference/speed/split` can
52 /// measure how a hybrid packet divides between its two layers, which is not
53 /// otherwise observable from outside. Off unless the `probe` feature is on,
54 /// and what it exposes can change or disappear without a version bump.
55 #[cfg(feature = "probe")]
56 pub probe_silk_bits: i32,
57 /// The last hybrid packet's total bits, the denominator for
58 /// [`probe_silk_bits`](Self::probe_silk_bits). Not public API, on the same
59 /// terms.
60 #[cfg(feature = "probe")]
61 pub probe_total_bits: i32,
62 celt_dec: CeltDecoder,
63 silk_dec: silk::dec_api::SilkDecoder,
64 sampling_rate: i32,
65 channels: usize,
66
67 prev_mode: Option<OpusMode>,
68 frame_size: usize,
69
70 stream_channels: usize,
71
72 silk_resampler: silk::resampler::SilkResampler,
73 // Second resampler for the SILK stereo right channel (L uses silk_resampler).
74 silk_resampler_r: silk::resampler::SilkResampler,
75
76 prev_internal_rate: i32,
77
78 /// Carries the soft-clipping curve between packets for the 16-bit output
79 /// path. libopus keeps the same state on its decoder (`softclip_mem`).
80 softclip: SoftClip,
81 /// Float scratch the 16-bit entry points decode into before converting.
82 w_pcm_f32: Vec<f32>,
83
84 w_pcm_i16: Vec<i16>,
85 w_silk_out: Vec<f32>,
86 w_pcm_resampled: Vec<i16>,
87 w_celt_out: Vec<f32>,
88
89 // SILK per-frame history: libopus prepends the previous frame's last two
90 // decoded samples (`sStereo.sMid`) and feeds the resampler from offset 1, a
91 // 1-internal-sample delay line. Replicated here so our SILK output aligns
92 // with the reference across every bandwidth (was leading by 1 internal
93 // sample = 3/4/6 output samples at WB/MB/NB).
94 silk_s_mid: [i16; 2],
95
96 /// Range-coder state left by the last decoded frame; read through
97 /// [`final_range`](Self::final_range).
98 last_range: u32,
99
100 /// Output gain, in Q8 dB. Applied to every decoded sample; 0 is unity.
101 ///
102 /// This is libopus's `OPUS_SET_GAIN`, and the reason it exists is
103 /// [`OpusHead::output_gain_q8`](crate::OpusHead::output_gain_q8): RFC 7845
104 /// §5.1 puts a gain in the Ogg header and says players SHOULD apply it, but
105 /// nothing in a container can reach inside a decoder to do so. Copy it
106 /// across after reading the header and the stream plays at the loudness its
107 /// author asked for.
108 ///
109 /// Applied before the soft clip on the 16-bit path, as libopus does, so a
110 /// gain that pushes the signal past full scale is clipped rather than
111 /// wrapped.
112 pub gain_q8: i32,
113
114 // libopus st->prev_redundancy: the previous frame carried a SILK->CELT
115 // redundant frame (redundancy && !celt_to_silk). Suppresses the CELT reset on
116 // the following mode change (the redundant frame already primed CELT state).
117 prev_redundancy: bool,
118
119 /// libopus `st->DecControl.internalSampleRate`: the rate the SILK layer ran
120 /// at in the last frame that carried one. Concealment reuses it instead of
121 /// re-deriving it from the packet bandwidth, because libopus only assigns
122 /// `internalSampleRate` when it has a packet in hand (opus_decoder.c:423) —
123 /// during a mode-switch cross-fade the packet in hand belongs to the *new*
124 /// mode and would give the wrong answer.
125 silk_internal_rate: i32,
126 /// libopus `st->end`: the CELT end band the last real frame set. Concealment
127 /// keeps it for the same reason — libopus's `st->bandwidth` is 0 on that
128 /// path, so the `CELT_SET_END_BAND` block is skipped (opus_decoder.c:546).
129 celt_end_band: usize,
130 /// libopus `pcm_transition`: 5 ms of *previous*-mode audio, synthesised by
131 /// concealment at a SILK<->CELT switch and cross-faded over the head of the
132 /// new frame. Interleaved.
133 w_transition: Vec<f32>,
134 /// Concealment scratch. The SILK PLC cannot produce a frame shorter than
135 /// 10 ms, so a shorter request is concealed here and only its head is kept.
136 w_plc: Vec<f32>,
137 /// Concealment scratch for the hybrid high band, which is summed onto the
138 /// SILK concealment rather than replacing it (libopus `celt_accum`).
139 w_plc_celt: Vec<f32>,
140}
141
142/// Shows the decoder's configuration and omits its coding state, for the same
143/// reason [`OpusEncoder`](crate::OpusEncoder)'s does.
144impl std::fmt::Debug for OpusDecoder {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 f.debug_struct("OpusDecoder")
147 .field("sampling_rate", &self.sampling_rate)
148 .field("channels", &self.channels)
149 .field("final_range", &self.last_range)
150 .field("gain_q8", &self.gain_q8)
151 .finish_non_exhaustive()
152 }
153}
154
155impl OpusDecoder {
156 /// Create a decoder producing `sampling_rate` Hz and `channels` channels.
157 ///
158 /// The rate must be one of 8000, 12000, 16000, 24000 or 48000, and the
159 /// channel count 1 or 2; anything else is
160 /// [`Error::InvalidArgument`].
161 ///
162 /// Neither has to match how the stream was encoded. These describe the PCM
163 /// the caller wants back, and the decoder resamples and mixes to reach it,
164 /// so a mono stream decodes to stereo and a 48 kHz one decodes to 16 kHz.
165 /// Requesting 48000 avoids a resampling step on the way out.
166 ///
167 /// For more than two channels, see
168 /// [`OpusMSDecoder`](crate::OpusMSDecoder).
169 pub fn new(sampling_rate: i32, channels: usize) -> Result<Self> {
170 if ![8000, 12000, 16000, 24000, 48000].contains(&sampling_rate) {
171 return Err(Error::InvalidArgument("Invalid sampling rate"));
172 }
173 if ![1, 2].contains(&channels) {
174 return Err(Error::InvalidArgument("Invalid number of channels"));
175 }
176
177 let mode = celt::modes::default_mode();
178 let mut celt_dec = CeltDecoder::new(mode, channels);
179 // CELT only has the 48 kHz mode; a lower API rate decimates its output.
180 celt_dec.set_downsample((48_000 / sampling_rate) as usize);
181
182 let mut silk_dec = silk::dec_api::SilkDecoder::new();
183 silk_dec.init(sampling_rate.min(16000), channels as i32);
184 silk_dec.channel_state[0].fs_api_hz = sampling_rate;
185
186 Ok(Self {
187 #[cfg(feature = "probe")]
188 probe_silk_bits: 0,
189 #[cfg(feature = "probe")]
190 probe_total_bits: 0,
191 celt_dec,
192 silk_dec,
193 sampling_rate,
194 channels,
195 prev_mode: None,
196 frame_size: 0,
197 stream_channels: channels,
198 silk_resampler: silk::resampler::SilkResampler::default(),
199 silk_resampler_r: silk::resampler::SilkResampler::default(),
200 prev_internal_rate: 0,
201
202 // SILK internal scratch: max frame is 60 ms at the 16 kHz WB internal
203 // rate (960 samples/ch), i.e. 1920 stereo. Sized like the sibling
204 // buffers below for headroom — the old fixed 640 overflowed on any
205 // 60 ms SILK frame (panic decoding valid streams).
206 w_pcm_i16: vec![0i16; 5760 * channels],
207
208 w_silk_out: vec![0.0f32; 5760 * channels],
209 w_pcm_resampled: vec![0i16; 5760 * channels],
210 softclip: SoftClip::new(channels),
211 w_pcm_f32: Vec::new(),
212 w_celt_out: vec![0.0f32; 5760 * channels],
213 silk_s_mid: [0; 2],
214 last_range: 0,
215 gain_q8: 0,
216 prev_redundancy: false,
217 silk_internal_rate: 16_000,
218 celt_end_band: 21,
219 w_transition: Vec::new(),
220 w_plc: Vec::new(),
221 w_plc_celt: Vec::new(),
222 })
223 }
224
225 /// Write one decoded SILK frame into `output`, resampling to the API rate.
226 ///
227 /// Always through the resampler, even where the API rate already equals
228 /// SILK's internal one. Its copy path is not a plain copy: it still carries
229 /// the `delay_matrix_dec` input delay, 4, 9 and 12 samples at 8, 12 and
230 /// 16 kHz, and `silk_Decode` calls `silk_resampler` unconditionally for
231 /// exactly that reason. Short-circuiting it put every SILK-only stream that
232 /// many samples ahead of the reference decoder. `base` is an index into `output` in
233 /// interleaved samples; the return is output samples per channel.
234 ///
235 /// `stereo` selects the true L/R low band that `dec_api` reconstructs from
236 /// mid/side. A mono frame in a stereo stream is duplicated to both channels,
237 /// but is still pushed through the right-channel resampler as well, so that
238 /// resampler's state stays continuous for the next stereo packet.
239 fn render_silk_frame(
240 &mut self,
241 output: &mut [f32],
242 base: usize,
243 decoded_samples: usize,
244 stereo: bool,
245 internal_rate: i32,
246 ) -> usize {
247 let ratio = self.sampling_rate as f64 / internal_rate as f64;
248 let out_len = (decoded_samples as f64 * ratio) as usize;
249 debug_assert!(out_len <= self.w_pcm_resampled.len());
250 let channels = self.channels;
251
252 // How many whole output samples actually fit, decided once. These loops
253 // are the entire SILK output path, and testing the bound inside them
254 // cost both the branch and any chance of vectorising the conversion:
255 // profiled against libopus, this function was eight times the
256 // reference's cost for work the reference does in a single pass.
257 // Callers size `output` in whole frames, so `fit` is `out_len` in
258 // practice and the clamp only reproduces the old truncation.
259 let fit = out_len.min(output.len().saturating_sub(base) / channels);
260 let out = &mut output[base..base + fit * channels];
261
262 if stereo {
263 self.silk_resampler.process(
264 &mut self.w_pcm_resampled[..out_len],
265 &self.silk_dec.l_out[..decoded_samples],
266 decoded_samples as i32,
267 );
268 for (frame, &v) in out
269 .as_chunks_mut::<2>()
270 .0
271 .iter_mut()
272 .zip(&self.w_pcm_resampled[..fit])
273 {
274 frame[0] = v as f32 / 32768.0;
275 }
276 // Right (reuse the scratch)
277 self.silk_resampler_r.process(
278 &mut self.w_pcm_resampled[..out_len],
279 &self.silk_dec.r_out[..decoded_samples],
280 decoded_samples as i32,
281 );
282 for (frame, &v) in out
283 .as_chunks_mut::<2>()
284 .0
285 .iter_mut()
286 .zip(&self.w_pcm_resampled[..fit])
287 {
288 frame[1] = v as f32 / 32768.0;
289 }
290 } else {
291 {
292 let (silk_res, pcm_i16, pcm_out) = (
293 &mut self.silk_resampler,
294 &self.w_pcm_i16,
295 &mut self.w_pcm_resampled,
296 );
297 silk_res.process(
298 &mut pcm_out[..out_len],
299 &pcm_i16[1..1 + decoded_samples],
300 decoded_samples as i32,
301 );
302 }
303 if channels == 1 {
304 for (o, &v) in out.iter_mut().zip(&self.w_pcm_resampled[..fit]) {
305 *o = v as f32 / 32768.0;
306 }
307 } else {
308 for (frame, &v) in out
309 .as_chunks_mut::<2>()
310 .0
311 .iter_mut()
312 .zip(&self.w_pcm_resampled[..fit])
313 {
314 let f = v as f32 / 32768.0;
315 frame[0] = f;
316 frame[1] = f;
317 }
318 // Stereo output, mono packet: also run the mono signal
319 // through the RIGHT-channel resampler so its state stays
320 // continuous for the next stereo packet (libopus
321 // dec_API.c:351-355). Its output overwrites channel 1,
322 // which is numerically ~identical to the left here.
323 self.silk_resampler_r.process(
324 &mut self.w_pcm_resampled[..out_len],
325 &self.w_pcm_i16[1..1 + decoded_samples],
326 decoded_samples as i32,
327 );
328 for (frame, &v) in out
329 .as_chunks_mut::<2>()
330 .0
331 .iter_mut()
332 .zip(&self.w_pcm_resampled[..fit])
333 {
334 frame[1] = v as f32 / 32768.0;
335 }
336 }
337 }
338 out_len
339 }
340
341 /// Packet-loss concealment for a lost frame (empty/None packet). Runs the
342 /// SILK PLC (LTP+LPC extrapolation) for the last-known SILK/hybrid mode,
343 /// resamples to the output rate, and sums the CELT high band's own
344 /// concealment on top when that mode was hybrid. Mono conceal is duplicated
345 /// to both channels on a stereo output.
346 ///
347 /// Also drives the cross-fade at a SILK<->CELT mode switch, where libopus
348 /// calls it for 5 ms of *previous*-mode audio (see [`Self::fill_transition`]).
349 fn decode_plc(&mut self, frame_size: usize, output: &mut [f32]) -> Result<usize> {
350 // "Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5
351 // (CELT), 10, or 20" (opus_decoder.c:344): a request longer than 20 ms
352 // is concealed in 20 ms pieces, because 20 ms is the longest frame CELT
353 // has. Its decode buffer holds exactly one, and the pitch branch of
354 // concealment indexes `DECODE_BUFFER_SIZE - MAX_PERIOD - n`, which goes
355 // negative past that. Concealing a lost 40 or 60 ms packet is an
356 // ordinary thing to ask a decoder for, and it reached that subtraction:
357 // found by the `decode_stream` fuzz target, pinned in
358 // `robustness.rs::concealment_longer_than_a_celt_frame_is_chunked`.
359 debug_assert!(output.len() >= frame_size * self.channels);
360 let longest = (self.sampling_rate / 50) as usize;
361 if frame_size > longest {
362 let mut done = 0usize;
363 while done < frame_size {
364 let take = longest.min(frame_size - done);
365 let span = done * self.channels..(done + take) * self.channels;
366 self.decode_plc(take, &mut output[span])?;
367 done += take;
368 }
369 return Ok(frame_size);
370 }
371
372 let out_samples = frame_size * self.channels;
373 for v in output.iter_mut().take(out_samples) {
374 *v = 0.0;
375 }
376 // libopus opus_decoder.c:331 — conceal in the last mode that actually
377 // produced audio, which is CELT when the previous frame ended on a
378 // SILK->CELT redundant frame.
379 //
380 // Before any packet has been decoded there is no such mode, and libopus
381 // returns the silence above without touching a decoder (`if (mode == 0)`
382 // at opus_decoder.c:334). Concealing in a guessed mode instead produces
383 // the same silence but leaves SILK's state advanced by a frame — a bumped
384 // `lossCnt`, a rotated output history, a stepped PLC seed — so the first
385 // real packet decoded its LPC coefficients through the after-loss
386 // bandwidth expansion that libopus had no reason to apply.
387 let Some(prev_mode) = self.prev_mode else {
388 return Ok(frame_size);
389 };
390 let mode = if self.prev_redundancy {
391 OpusMode::CeltOnly
392 } else {
393 prev_mode
394 };
395 if mode == OpusMode::CeltOnly {
396 // CELT packet-loss concealment (noise-based celt_decode_lost): real
397 // attenuating audio instead of silence.
398 self.celt_dec
399 .conceal_lost_bands(frame_size, output, 0, self.celt_end_band);
400 self.prev_mode = Some(mode);
401 return Ok(frame_size);
402 }
403
404 // "The SILK PLC cannot produce frames of less than 10 ms"
405 // (opus_decoder.c:420): a shorter request still runs a 10 ms
406 // concealment, and only its head reaches the caller. That happens on
407 // every mode-switch cross-fade, which asks for 5 ms.
408 let want_ms = (frame_size as i32 * 1000 / self.sampling_rate).max(1);
409 let frame_ms = want_ms.max(10);
410 let internal_rate = self.silk_internal_rate;
411 if internal_rate != self.prev_internal_rate {
412 self.silk_resampler.init(internal_rate, self.sampling_rate);
413 self.silk_resampler_r
414 .init(internal_rate, self.sampling_rate);
415 self.prev_internal_rate = internal_rate;
416 }
417 let n_silk = match frame_ms {
418 40 => 2,
419 60 => 3,
420 _ => 1,
421 };
422 let internal_frame = (frame_ms * internal_rate / 1000) as usize;
423 let internal_sub = internal_frame / n_silk;
424 // libopus carries the previous frame's channel configuration through a
425 // concealed frame, so a stereo stream conceals both channels and rebuilds
426 // L/R the same way a decoded frame does. Forcing mono here instead let the
427 // image collapse to the centre for the length of the concealment.
428 self.silk_dec.produce_lr = self.channels == 2 && self.silk_dec.n_channels_internal == 2;
429
430 // SILK writes a whole `frame_ms` here; `output` only gets its head.
431 let plc_samples = (frame_ms as usize * self.sampling_rate as usize) / 1000;
432 let need = plc_samples * self.channels;
433 let mut scratch = std::mem::take(&mut self.w_plc);
434 if scratch.len() < need {
435 scratch.resize(need, 0.0);
436 }
437 scratch[..need].fill(0.0);
438 let conceal = self.conceal_silk(&mut scratch, frame_ms, n_silk, internal_sub);
439 if conceal.is_ok() {
440 let copy = out_samples.min(need);
441 output[..copy].copy_from_slice(&scratch[..copy]);
442 }
443 self.w_plc = scratch;
444 conceal?;
445
446 // Hybrid: the CELT layer conceals its own high band and sums onto the
447 // SILK output, exactly as `celt_accum` does on the decode path
448 // (opus_decoder.c:599 with data == NULL).
449 if mode == OpusMode::Hybrid {
450 let mut celt = std::mem::take(&mut self.w_plc_celt);
451 if celt.len() < out_samples {
452 celt.resize(out_samples, 0.0);
453 }
454 self.celt_dec.conceal_lost_bands(
455 frame_size,
456 &mut celt,
457 HYBRID_START_BAND,
458 self.celt_end_band,
459 );
460 for (o, c) in output[..out_samples].iter_mut().zip(&celt[..out_samples]) {
461 *o += *c;
462 }
463 self.w_plc_celt = celt;
464 }
465
466 self.prev_mode = Some(mode);
467 Ok(frame_size)
468 }
469
470 /// The SILK half of [`Self::decode_plc`]: `n_silk` concealed internal frames
471 /// resampled into `out` (interleaved, `frame_ms` worth).
472 fn conceal_silk(
473 &mut self,
474 out: &mut [f32],
475 frame_ms: i32,
476 n_silk: usize,
477 internal_sub: usize,
478 ) -> Result<()> {
479 let mut off = 0usize; // output samples/ch written so far
480 for sf in 0..n_silk {
481 let mut rc = RangeCoder::new_decoder(&[]);
482 let n16 = internal_sub;
483 if n16 + 2 > self.w_pcm_i16.len() {
484 return Err(Error::InvalidPacket("opus PLC: frame exceeds buffer"));
485 }
486 self.w_pcm_i16[0] = self.silk_s_mid[0];
487 self.w_pcm_i16[1] = self.silk_s_mid[1];
488 let ret = self.silk_dec.decode(
489 &mut rc,
490 &mut self.w_pcm_i16[2..n16 + 2],
491 silk::decode_frame::FLAG_PACKET_LOST,
492 sf == 0,
493 frame_ms,
494 self.silk_internal_rate,
495 );
496 if ret < 0 {
497 return Err(Error::Internal("SILK PLC failed"));
498 }
499 let dec = ret as usize;
500 if dec >= 2 {
501 self.silk_s_mid[0] = self.w_pcm_i16[dec];
502 self.silk_s_mid[1] = self.w_pcm_i16[dec + 1];
503 }
504 // A stereo stream conceals both channels and reconstructs L/R the
505 // same way a decoded frame does. Writing the mid to both outputs
506 // instead collapses the image for the length of the concealment,
507 // which at a mode switch is audible as the stereo field snapping to
508 // the centre for one 5 ms window. That reconstruction is exactly
509 // what render_silk_frame does, so concealment shares it.
510 let stereo = self.channels == 2 && self.silk_dec.produce_lr;
511 let base = off * self.channels;
512 off += self.render_silk_frame(out, base, dec, stereo, self.silk_internal_rate);
513 }
514 Ok(())
515 }
516
517 /// libopus opus_decoder.c:417 — the SILK layer carries no state across a
518 /// CELT-only stretch, so it restarts from scratch when the stream comes
519 /// back to it. Without this the first SILK frame after a CELT run predicts
520 /// from LPC/LTP history that belongs to whatever came before the CELT run.
521 fn reset_silk_after_celt_only(&mut self) {
522 if self.prev_mode != Some(OpusMode::CeltOnly) {
523 return;
524 }
525 for ch in 0..2 {
526 silk::init_decoder::silk_init_decoder(&mut self.silk_dec.channel_state[ch]);
527 }
528 self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
529 self.silk_dec.s_stereo_mid = [0; 2];
530 self.silk_dec.s_stereo_side = [0; 2];
531 self.silk_dec.prev_decode_only_middle = 0;
532 self.silk_s_mid = [0; 2];
533 }
534
535 /// libopus `pcm_transition` (opus_decoder.c:388 and :540). A SILK<->CELT
536 /// switch with no redundancy hands the new layer no history to overlap-add
537 /// against, so its first samples start from silence. libopus covers the seam
538 /// by concealing 5 ms in the *previous* mode and cross-fading that over the
539 /// head of the frame.
540 ///
541 /// The concealment call is a synthesis side-channel, not a decoded frame, so
542 /// `prev_mode` / `prev_redundancy` are restored afterwards. libopus leaves
543 /// them equal too: `transition` already implies `prev_redundancy` is clear,
544 /// and the recursive call re-stores the same `prev_mode` it read.
545 fn fill_transition(&mut self, sub_frame_size: usize, end_band: usize) -> Result<()> {
546 let n = ((self.sampling_rate / 200) as usize).min(sub_frame_size);
547 let need = n * self.channels;
548 let mut buf = std::mem::take(&mut self.w_transition);
549 if buf.len() < need {
550 buf.resize(need, 0.0);
551 }
552 let saved_mode = self.prev_mode;
553 let saved_redundancy = self.prev_redundancy;
554 let saved_end_band = std::mem::replace(&mut self.celt_end_band, end_band);
555 let r = self.decode_plc(n, &mut buf);
556 self.w_transition = buf;
557 self.prev_mode = saved_mode;
558 self.prev_redundancy = saved_redundancy;
559 self.celt_end_band = saved_end_band;
560 r.map(|_| ())
561 }
562
563 /// Blend the concealed previous-mode head from [`Self::fill_transition`]
564 /// into the start of `region` (opus_decoder.c:660): the first 2.5 ms comes
565 /// from the concealment outright, the next 2.5 ms cross-fades into the
566 /// decoded frame. A frame shorter than 5 ms has no room for both, so it
567 /// gets the cross-fade alone.
568 fn apply_transition(&self, region: &mut [f32], sub_frame_size: usize) {
569 let f5 = (self.sampling_rate / 200) as usize;
570 let f2_5 = f5 / 2;
571 let inc = (48_000 / self.sampling_rate) as usize;
572 let window = celt::modes::default_mode().window;
573 let ch = self.channels;
574 let trans = &self.w_transition;
575 let head = if sub_frame_size >= f5 {
576 region[..f2_5 * ch].copy_from_slice(&trans[..f2_5 * ch]);
577 f2_5
578 } else {
579 0
580 };
581 for i in 0..f2_5 {
582 let w = window[i * inc] * window[i * inc];
583 for c in 0..ch {
584 let idx = (head + i) * ch + c;
585 region[idx] = w * region[idx] + (1.0 - w) * trans[idx];
586 }
587 }
588 }
589
590 /// Forward-error-correction decode: reconstruct a LOST frame from the
591 /// low-bitrate redundancy (LBRR) embedded in the NEXT received `packet`.
592 ///
593 /// The SILK decoder runs in `FLAG_DECODE_LBRR` mode, which self-selects: it
594 /// decodes the redundant copy when the packet carries one for this frame,
595 /// and extrapolates as for a lost frame when it does not. After this call
596 /// the caller decodes `packet` normally for the following frame.
597 ///
598 /// Redundancy only ever covers one SILK frame, so when `frame_size` is
599 /// longer than the packet's own frames the excess ahead of it is concealed
600 /// and only the tail is recovered. A CELT-only packet, or one arriving
601 /// while the stream is in CELT-only mode, carries no redundancy at all and
602 /// falls back to plain concealment.
603 /// Per-packet internal channel switch (libopus `dec_API.c:119-166`).
604 ///
605 /// Returns whether SILK should produce L/R directly for this packet. All
606 /// three decode paths (FEC, normal, PLC) need exactly this bookkeeping, so
607 /// it lives here once rather than being repeated at each of them.
608 fn setup_silk_channels(&mut self, packet_channels: usize) -> bool {
609 let silk_lr = self.channels == 2 && packet_channels == 2;
610 self.silk_dec.produce_lr = silk_lr;
611 let prev_internal_ch = self.silk_dec.n_channels_internal;
612 if packet_channels as i32 > prev_internal_ch {
613 // mono -> stereo: reset the side channel decoder.
614 silk::init_decoder::silk_init_decoder(&mut self.silk_dec.channel_state[1]);
615 }
616 if silk_lr && prev_internal_ch == 1 {
617 // Switching to stereo: clear stereo prediction/side history and
618 // seed the right-channel resampler from the (continuous) left.
619 self.silk_dec.s_stereo_pred_prev_q13 = [0; 2];
620 self.silk_dec.s_stereo_side = [0; 2];
621 self.silk_resampler_r = self.silk_resampler.clone();
622 }
623 self.silk_dec.n_channels_internal = packet_channels as i32;
624 silk_lr
625 }
626
627 /// The sample rate this decoder was created with, in Hz.
628 pub fn sample_rate(&self) -> i32 {
629 self.sampling_rate
630 }
631
632 /// The channel count this decoder was created with.
633 pub fn channels(&self) -> usize {
634 self.channels
635 }
636
637 /// Range-coder state left by the last decoded frame (libopus
638 /// `OPUS_GET_FINAL_RANGE`).
639 ///
640 /// A decoder that has read a packet correctly ends in exactly the state the
641 /// encoder ended in, so comparing this against
642 /// [`OpusEncoder::final_range`](crate::OpusEncoder::final_range) is a cheap
643 /// check that the two agree bit for bit. That is what the RFC 6716 test
644 /// vectors compare, and what tells a desync apart from a merely
645 /// disappointing decode. It is not needed to decode audio.
646 pub fn final_range(&self) -> u32 {
647 self.last_range
648 }
649
650 /// Samples per channel in the last packet decoded from real data (libopus
651 /// `OPUS_GET_LAST_PACKET_DURATION`), or 0 before the first one.
652 ///
653 /// Concealed and FEC-recovered frames do not change it, so after a loss it
654 /// still reports the last packet that actually arrived. To ask the same
655 /// question of a packet you are holding but have not decoded — which is
656 /// what a muxer or a jitter buffer wants — use
657 /// [`packet::samples`](crate::packet::samples) instead; it reads the TOC
658 /// and needs no decoder at all.
659 pub fn last_packet_duration(&self) -> usize {
660 self.frame_size
661 }
662
663 /// Discard everything the decoder has learned, keeping its settings.
664 ///
665 /// This is libopus's `OPUS_RESET_STATE`, and the moment to call it is
666 /// between two unrelated streams sharing one decoder. Almost everything
667 /// interesting in an Opus decoder is carried *between* packets — the LTP
668 /// and LPC histories, the overlap-add buffer, the resampler, which layer
669 /// coded the previous frame — so a second stream started on a used decoder
670 /// begins by blending into the end of the first.
671 ///
672 /// Equivalent to building a new decoder with the same sample rate and
673 /// channel count, and carrying [`gain_q8`](Self::gain_q8) across. It resets
674 /// in place and allocates nothing, so a player can call it at every loop
675 /// point.
676 pub fn reset_state(&mut self) -> Result<()> {
677 // Exhaustive, so a field added to the decoder does not compile until
678 // this says how it resets. Each is set to what `new` gives it.
679 let Self {
680 #[cfg(feature = "probe")]
681 probe_silk_bits,
682 #[cfg(feature = "probe")]
683 probe_total_bits,
684 celt_dec,
685 silk_dec,
686 sampling_rate,
687 channels,
688 prev_mode,
689 frame_size,
690 stream_channels,
691 silk_resampler,
692 silk_resampler_r,
693 prev_internal_rate,
694 softclip,
695 w_pcm_f32,
696 w_pcm_i16,
697 w_silk_out,
698 w_pcm_resampled,
699 w_celt_out,
700 silk_s_mid,
701 last_range,
702 gain_q8: _,
703 prev_redundancy,
704 silk_internal_rate,
705 celt_end_band,
706 w_transition,
707 w_plc,
708 w_plc_celt,
709 } = self;
710 #[cfg(feature = "probe")]
711 {
712 *probe_silk_bits = 0;
713 *probe_total_bits = 0;
714 }
715 // The rate and channel count are settings, as is the CELT downsample
716 // factor derived from the rate, which `reset` keeps.
717 celt_dec.reset();
718 celt_dec.set_stream_channels(*channels);
719 // The SILK decoder holds no heap memory, so a new one costs no
720 // allocation.
721 *silk_dec = silk::dec_api::SilkDecoder::new();
722 silk_dec.init((*sampling_rate).min(16000), *channels as i32);
723 silk_dec.channel_state[0].fs_api_hz = *sampling_rate;
724 *prev_mode = None;
725 *frame_size = 0;
726 *stream_channels = *channels;
727 *silk_resampler = silk::resampler::SilkResampler::default();
728 *silk_resampler_r = silk::resampler::SilkResampler::default();
729 *prev_internal_rate = 0;
730 softclip.reset();
731 *silk_s_mid = [0; 2];
732 *last_range = 0;
733 *prev_redundancy = false;
734 *silk_internal_rate = 16_000;
735 *celt_end_band = 21;
736 // Scratch starts as `new` leaves it, zeroed or empty, with its
737 // capacity kept.
738 w_pcm_i16.fill(0);
739 w_silk_out.fill(0.0);
740 w_pcm_resampled.fill(0);
741 w_celt_out.fill(0.0);
742 w_pcm_f32.clear();
743 w_transition.clear();
744 w_plc.clear();
745 w_plc_celt.clear();
746 Ok(())
747 }
748
749 /// Decode one packet into `frame_size` samples per channel of float PCM,
750 /// returning how many it produced.
751 ///
752 /// `output` is interleaved and must hold `frame_size * channels` samples.
753 /// An empty `input` means a lost packet and runs packet-loss concealment.
754 ///
755 /// The output is **not** bounded by ±1: the codec rings, and a signal
756 /// mastered near full scale comes back slightly over it. libopus behaves
757 /// the same way. Convert to integer PCM with
758 /// [`decode_s16`](Self::decode_s16), which handles that, or apply
759 /// [`SoftClip`] yourself if you need the float and are converting later.
760 pub fn decode(&mut self, input: &[u8], frame_size: usize, output: &mut [f32]) -> Result<usize> {
761 self.decode_native(input, frame_size, output, false)
762 }
763
764 /// Decode one packet into `frame_size` samples per channel of 16-bit PCM,
765 /// returning how many it produced.
766 ///
767 /// Soft-clips before converting, so the result is inside the 16-bit range
768 /// without the broadband distortion that saturating there would cause, and
769 /// without a step at the packet boundary when a peak straddles one. This is
770 /// what libopus's `opus_decode` does and `opus_decode_float` does not, and
771 /// it is the reason to prefer this entry point over converting the float
772 /// output by hand. See [`SoftClip`] for what the curve is.
773 ///
774 /// ```
775 /// # use opus_pure::{Application, OpusDecoder, OpusEncoder};
776 /// # let mut encoder = OpusEncoder::new(48_000, 2, Application::Audio)?;
777 /// # let mut packet = vec![0u8; 4000];
778 /// # let n = encoder.encode_s16(&vec![0i16; 960 * 2], 960, &mut packet)?;
779 /// let mut decoder = OpusDecoder::new(48_000, 2)?;
780 /// let mut pcm = vec![0i16; 960 * 2];
781 /// let samples = decoder.decode_s16(&packet[..n], 960, &mut pcm)?;
782 /// # assert_eq!(samples, 960);
783 /// # Ok::<(), opus_pure::Error>(())
784 /// ```
785 pub fn decode_s16(
786 &mut self,
787 input: &[u8],
788 frame_size: usize,
789 output: &mut [i16],
790 ) -> Result<usize> {
791 self.decode_as_s16(frame_size, output, |d, pcm| {
792 d.decode_native(input, frame_size, pcm, true)
793 })
794 }
795
796 /// Reconstruct the previous packet from this one's in-band FEC, as float.
797 ///
798 /// Call this when a packet is lost and the packet *after* it has arrived:
799 /// SILK and hybrid streams can carry a low-rate copy of the frame before,
800 /// which reconstructs it far better than concealment can. Falls back to
801 /// concealment when the packet carries no such copy.
802 pub fn decode_fec(
803 &mut self,
804 packet: &[u8],
805 frame_size: usize,
806 output: &mut [f32],
807 ) -> Result<usize> {
808 self.decode_fec_native(packet, frame_size, output, false)
809 }
810
811 /// [`decode_fec`](Self::decode_fec) into 16-bit PCM, soft-clipped the same
812 /// way [`decode_s16`](Self::decode_s16) is.
813 pub fn decode_fec_s16(
814 &mut self,
815 packet: &[u8],
816 frame_size: usize,
817 output: &mut [i16],
818 ) -> Result<usize> {
819 self.decode_as_s16(frame_size, output, |d, pcm| {
820 d.decode_fec_native(packet, frame_size, pcm, true)
821 })
822 }
823
824 /// Run `decode` into the float scratch, then convert what it produced.
825 ///
826 /// The scratch is moved out of `self` and back because the decode needs
827 /// `&mut self` and a buffer that lives on it at the same time; it stays
828 /// allocated between calls either way.
829 fn decode_as_s16(
830 &mut self,
831 frame_size: usize,
832 output: &mut [i16],
833 decode: impl FnOnce(&mut Self, &mut [f32]) -> Result<usize>,
834 ) -> Result<usize> {
835 let capacity = frame_size * self.channels;
836 if output.len() < capacity {
837 return Err(Error::buffer_too_small(capacity, output.len()));
838 }
839 let mut pcm = std::mem::take(&mut self.w_pcm_f32);
840 pcm.clear();
841 pcm.resize(capacity, 0.0);
842 let result = decode(self, &mut pcm);
843 if let Ok(produced) = result {
844 let n = produced * self.channels;
845 for (o, &s) in output[..n].iter_mut().zip(&pcm[..n]) {
846 *o = float_to_i16(s);
847 }
848 }
849 self.w_pcm_f32 = pcm;
850 result
851 }
852
853 /// Decode as float, then either apply the soft-clipping curve or clear it.
854 ///
855 /// Clearing on the float path is deliberate and matches libopus
856 /// (`opus_decode_native`): a curve left half-applied by a 16-bit call would
857 /// otherwise bend the start of the next frame a caller asked for in float,
858 /// where nothing is going to clip it.
859 pub(crate) fn decode_native(
860 &mut self,
861 input: &[u8],
862 frame_size: usize,
863 output: &mut [f32],
864 soft_clip: bool,
865 ) -> Result<usize> {
866 let produced = self.decode_impl(input, frame_size, output)?;
867 self.finish(&mut output[..produced * self.channels], soft_clip);
868 Ok(produced)
869 }
870
871 /// [`decode_native`](Self::decode_native) for the FEC path.
872 fn decode_fec_native(
873 &mut self,
874 packet: &[u8],
875 frame_size: usize,
876 output: &mut [f32],
877 soft_clip: bool,
878 ) -> Result<usize> {
879 let produced = self.decode_fec_impl(packet, frame_size, output)?;
880 self.finish(&mut output[..produced * self.channels], soft_clip);
881 Ok(produced)
882 }
883
884 fn finish(&mut self, pcm: &mut [f32], soft_clip: bool) {
885 // libopus `opus_decode_native`: the gain goes on before the soft clip,
886 // so boosting past full scale is clipped rather than wrapped. The
887 // constant converts Q8 dB into an exponent of two —
888 // `10^(g/(20*256)) == 2^(g * log2(10) / 5120)`.
889 if self.gain_q8 != 0 {
890 let gain = (self.gain_q8 as f32 * 6.488_141e-4).exp2();
891 for s in pcm.iter_mut() {
892 *s *= gain;
893 }
894 }
895 if soft_clip {
896 self.softclip.apply(pcm);
897 } else {
898 self.softclip.reset();
899 }
900 }
901
902 fn decode_fec_impl(
903 &mut self,
904 packet: &[u8],
905 frame_size: usize,
906 output: &mut [f32],
907 ) -> Result<usize> {
908 let capacity = frame_size * self.channels;
909 if output.len() < capacity {
910 return Err(Error::buffer_too_small(capacity, output.len()));
911 }
912 if packet.is_empty() {
913 return self.decode_plc(frame_size, output);
914 }
915 let toc = packet[0];
916 let mode = mode_from_toc(toc);
917 if mode == OpusMode::CeltOnly || self.prev_mode == Some(OpusMode::CeltOnly) {
918 return self.decode_plc(frame_size, output);
919 }
920 let packet_frame_ms = frame_duration_ms_from_toc(toc);
921 let packet_frame_size = (packet_frame_ms * self.sampling_rate / 1000) as usize;
922 if packet_frame_size == 0 || frame_size < packet_frame_size {
923 return self.decode_plc(frame_size, output);
924 }
925
926 // The redundancy lives in the packet's FIRST frame; anything the request
927 // covers ahead of it has no redundant copy and is concealed instead.
928 let lead = frame_size - packet_frame_size;
929 if lead > 0 {
930 self.decode_plc(lead, &mut output[..lead * self.channels])?;
931 }
932 let base = lead * self.channels;
933 for v in output[base..capacity].iter_mut() {
934 *v = 0.0;
935 }
936
937 let (_, frames, _) = crate::repacketizer::parse_packet(packet, false)?;
938 let payload = frames[0];
939
940 let bandwidth = bandwidth_from_toc(toc);
941 let packet_channels = channels_from_toc(toc);
942 let internal_rate = if mode == OpusMode::Hybrid {
943 16000
944 } else {
945 match bandwidth {
946 Bandwidth::Narrowband => 8000,
947 Bandwidth::Mediumband => 12000,
948 _ => 16000,
949 }
950 };
951 if internal_rate != self.prev_internal_rate {
952 self.silk_resampler.init(internal_rate, self.sampling_rate);
953 self.silk_resampler_r
954 .init(internal_rate, self.sampling_rate);
955 self.prev_internal_rate = internal_rate;
956 }
957 self.silk_internal_rate = internal_rate;
958
959 // Same channel bookkeeping as a normal SILK frame: a redundant frame is
960 // an ordinary coded frame, so a stereo one has to reconstruct L/R rather
961 // than collapse to the mid.
962 let silk_lr = self.setup_silk_channels(packet_channels);
963
964 // A 40 or 60 ms packet holds two or three SILK frames, each redundantly
965 // coded in its own right; libopus keeps calling the SILK decoder until
966 // the requested duration is filled.
967 let n_silk = match packet_frame_ms {
968 40 => 2,
969 60 => 3,
970 _ => 1,
971 };
972 let internal_sub_frame = (packet_frame_ms * internal_rate / 1000) as usize / n_silk;
973 let pcm_i16_len = internal_sub_frame * self.channels;
974 if pcm_i16_len + 2 > self.w_pcm_i16.len() {
975 return Err(Error::InvalidPacket("opus FEC: frame exceeds buffer"));
976 }
977
978 let mut rc = RangeCoder::new_decoder(payload);
979 let mut written = 0usize;
980 for sf in 0..n_silk {
981 let s_mid = self.silk_s_mid;
982 let ret = {
983 let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
984 pcm_i16[0] = s_mid[0];
985 pcm_i16[1] = s_mid[1];
986 silk_dec.decode(
987 &mut rc,
988 &mut pcm_i16[2..pcm_i16_len + 2],
989 silk::decode_frame::FLAG_DECODE_LBRR,
990 sf == 0,
991 packet_frame_ms,
992 internal_rate,
993 )
994 };
995 if ret < 0 {
996 return Err(Error::Internal("SILK FEC failed"));
997 }
998 let decoded_samples = ret as usize;
999 if decoded_samples >= 2 {
1000 self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1001 self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1002 }
1003 written += self.render_silk_frame(
1004 output,
1005 base + written * self.channels,
1006 decoded_samples,
1007 silk_lr,
1008 internal_rate,
1009 );
1010 }
1011
1012 // Hybrid: the redundancy only ever covers the SILK low band, so the CELT
1013 // high band conceals itself and is summed on top, as it is for a lost
1014 // frame (opus_decoder.c passes NULL to the CELT decoder here).
1015 if mode == OpusMode::Hybrid {
1016 let tail = capacity - base;
1017 let mut celt = std::mem::take(&mut self.w_plc_celt);
1018 if celt.len() < tail {
1019 celt.resize(tail, 0.0);
1020 }
1021 self.celt_dec.conceal_lost_bands(
1022 packet_frame_size,
1023 &mut celt,
1024 HYBRID_START_BAND,
1025 self.celt_end_band,
1026 );
1027 for (o, c) in output[base..capacity].iter_mut().zip(&celt[..tail]) {
1028 *o += *c;
1029 }
1030 self.w_plc_celt = celt;
1031 }
1032
1033 self.prev_mode = Some(mode);
1034 self.prev_redundancy = false;
1035 Ok(frame_size)
1036 }
1037
1038 fn decode_impl(
1039 &mut self,
1040 input: &[u8],
1041 frame_size: usize,
1042 output: &mut [f32],
1043 ) -> Result<usize> {
1044 // `frame_size` is the room available in `output`, counted per channel.
1045 // libopus takes that on trust because C hands it a bare pointer; here
1046 // the slice knows its own length, so hold the caller to what they
1047 // declared rather than letting a short buffer truncate the decode.
1048 let capacity = frame_size * self.channels;
1049 if output.len() < capacity {
1050 return Err(Error::buffer_too_small(capacity, output.len()));
1051 }
1052 // Lost packet (data==NULL / empty) -> packet-loss concealment.
1053 if input.is_empty() {
1054 return self.decode_plc(frame_size, output);
1055 }
1056
1057 let toc = input[0];
1058 let mode = mode_from_toc(toc);
1059 let packet_channels = channels_from_toc(toc);
1060 let bandwidth = bandwidth_from_toc(toc);
1061 let frame_duration_ms = frame_duration_ms_from_toc(toc);
1062
1063 // Every packet decodes through this one decoder, whatever its channel
1064 // count. A stream may switch between mono and stereo at any packet, and
1065 // libopus keeps a single decoder across those switches so that the SILK
1066 // stereo/resampler state and the CELT overlap-add, prefilter and
1067 // preemphasis histories stay one continuous chain. Rendering to a
1068 // different output channel count happens *inside* each layer, where the
1069 // reference does it:
1070 //
1071 // mono packet, stereo output (C=1, CC=2) — SILK emits the mid through
1072 // both channels' resamplers; CELT re-runs its inverse MDCT per output
1073 // channel off the single decoded spectrum.
1074 //
1075 // stereo packet, mono output (C=2, CC=1) — SILK emits the mid, which
1076 // *is* (L+R)/2 by construction, and never reconstructs L/R; CELT sums
1077 // the two spectra before a single inverse MDCT.
1078 //
1079 // Both are `stream_channels` on the CELT decoder and `n_channels_internal`
1080 // on the SILK one; neither needs a second decoder.
1081
1082 // One packet parser for the whole crate. `repacketizer::parse_packet`
1083 // is the port of libopus `opus_packet_parse_impl`, and `decode_fec` and
1084 // the repacketizer already went through it; the copy that used to live
1085 // here had drifted from it, accepting frames past the 1275-byte limit
1086 // of RFC 6716 §3.4 and rejecting the zero-length DTX frames of a code 1
1087 // packet that libopus accepts.
1088 let (_, frame_payloads, _) = repacketizer::parse_packet(input, false)?;
1089 let frame_count = frame_payloads.len();
1090
1091 // libopus opus_decoder.c opus_decode_native:
1092 // if (count*packet_frame_size > frame_size)
1093 // return OPUS_BUFFER_TOO_SMALL;
1094 // The packet's own TOC duration must fit the caller's frame_size. We split
1095 // the caller's buffer as sub_frame_size = frame_size / frame_count, so a
1096 // malformed multi-frame packet (large frame count vs. a small caller
1097 // buffer) would otherwise make sub_frame_size smaller than the 2.5/5 ms
1098 // redundancy-fade region — the fuzzer-found out-of-bounds/underflow panics
1099 // in redundancy_fade_start/redundancy_fade_end. C rejects such packets
1100 // here; so do we.
1101 let packet_frame_samples =
1102 repacketizer::samples_per_frame(toc, self.sampling_rate) as usize;
1103 if frame_count * packet_frame_samples > frame_size {
1104 return Err(Error::buffer_too_small(
1105 frame_count * packet_frame_samples,
1106 frame_size,
1107 ));
1108 }
1109
1110 // From here on, work in the packet's own duration rather than the
1111 // caller's buffer size. libopus does the same: `frame_size` is the room
1112 // available in `output`, and `opus_decode` returns however many samples
1113 // the packet actually held. Treating it as the exact output length
1114 // instead stretched a 20 ms packet across whatever buffer it was given.
1115 let frame_size = frame_count * packet_frame_samples;
1116
1117 self.frame_size = frame_size;
1118 self.stream_channels = packet_channels;
1119 // libopus sets `st->end` from the packet's bandwidth (opus_decoder.c:546)
1120 // *after* the mode-switch concealment runs, so that concealment still
1121 // sees the band range the outgoing mode was decoded with.
1122 let prev_celt_end_band = self.celt_end_band;
1123 self.celt_end_band = celt_endband_for_bandwidth(bandwidth);
1124
1125 let sub_frame_size = frame_size / frame_count;
1126 let sub_output_len = sub_frame_size * self.channels;
1127
1128 // libopus opus_decoder.c:374 — a SILK<->CELT switch leaves the layer
1129 // taking over with no overlap-add history, so its first samples start
1130 // from silence. Unless the encoder bridged the seam with a redundant
1131 // frame, libopus conceals 5 ms of the outgoing mode and cross-fades it
1132 // over the head of this frame. Only the packet's first Opus frame can
1133 // be a transition: after it, the previous mode is this one.
1134 let transition = match self.prev_mode {
1135 Some(prev) => {
1136 (mode == OpusMode::CeltOnly && prev != OpusMode::CeltOnly && !self.prev_redundancy)
1137 || (mode != OpusMode::CeltOnly && prev == OpusMode::CeltOnly)
1138 }
1139 None => false,
1140 };
1141
1142 match mode {
1143 OpusMode::SilkOnly => {
1144 let internal_sample_rate = match bandwidth {
1145 Bandwidth::Narrowband => 8000,
1146 Bandwidth::Mediumband => 12000,
1147 Bandwidth::Wideband => 16000,
1148 _ => 16000,
1149 };
1150 let internal_frame_size =
1151 (frame_duration_ms * internal_sample_rate / 1000) as usize;
1152
1153 // Initialised even where the rates already match: the copy
1154 // path still applies the resampler's input delay, and
1155 // `render_silk_frame` now routes every SILK frame through it.
1156 if internal_sample_rate != self.prev_internal_rate {
1157 self.silk_resampler
1158 .init(internal_sample_rate, self.sampling_rate);
1159 self.silk_resampler_r
1160 .init(internal_sample_rate, self.sampling_rate);
1161 self.prev_internal_rate = internal_sample_rate;
1162 }
1163 self.silk_internal_rate = internal_sample_rate;
1164 self.reset_silk_after_celt_only();
1165
1166 // Pure-SILK stereo (both stream and output are 2ch): reconstruct
1167 // true L/R via SILK MS->LR instead of duplicating the mono mid.
1168 let silk_lr = self.setup_silk_channels(packet_channels);
1169
1170 // A 40/60 ms Opus frame carries 2/3 internal 20 ms SILK frames;
1171 // 10/20 ms carry one. libopus calls silk_Decode once per internal
1172 // frame (continuing the same range coder within the payload). We
1173 // must too — decoding only the first internal frame leaves the
1174 // rest of a 40/60 ms packet silent (the "collapse" bug).
1175 let n_silk = match frame_duration_ms {
1176 40 => 2,
1177 60 => 3,
1178 _ => 1,
1179 };
1180 let internal_sub_frame_size = internal_frame_size / n_silk;
1181 // Per-FRAME previous mode (libopus updates prev_mode per frame; for
1182 // payloads after the first, the previous frame is this same packet).
1183 let mut prev_mode_frame = self.prev_mode;
1184
1185 for (fi, payload) in frame_payloads.iter().enumerate() {
1186 let mut rc = RangeCoder::new_decoder(payload);
1187 let pcm_i16_len = internal_sub_frame_size * self.channels;
1188 // A malformed packet can imply a frame larger than our scratch
1189 // buffer; reject it gracefully instead of slicing out of bounds
1190 // (a decode-path DoS on attacker-controlled input).
1191 if pcm_i16_len + 2 > self.w_pcm_i16.len() {
1192 return Err(Error::InvalidPacket("opus: SILK frame size exceeds buffer"));
1193 }
1194 let out_start = fi * sub_output_len;
1195 let mut silk_off = 0usize; // output samples/ch within this Opus frame
1196
1197 for sf in 0..n_silk {
1198 let s_mid = self.silk_s_mid;
1199 let ret = {
1200 let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1201 // Prepend the previous frame's last two samples (sMid) at
1202 // [0..2] and decode at offset 2, matching libopus's
1203 // samplesOut1_tmp[n][2] layout.
1204 pcm_i16[0] = s_mid[0];
1205 pcm_i16[1] = s_mid[1];
1206 silk_dec.decode(
1207 &mut rc,
1208 &mut pcm_i16[2..pcm_i16_len + 2],
1209 silk::decode_frame::FLAG_DECODE_NORMAL,
1210 sf == 0,
1211 frame_duration_ms,
1212 internal_sample_rate,
1213 )
1214 };
1215
1216 if ret < 0 {
1217 return Err(Error::Internal("SILK decoding failed"));
1218 }
1219
1220 let decoded_samples = ret as usize;
1221 // Carry the last two decoded samples as next frame's sMid.
1222 if decoded_samples >= 2 {
1223 self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1224 self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1225 }
1226 let base = out_start + silk_off * self.channels;
1227
1228 // Stereo SILK: L in silk_dec.l_out, R in silk_dec.r_out,
1229 // both already in the 1-sample-delay-line layout. Resample
1230 // each channel through its own resampler.
1231 let out_len = self.render_silk_frame(
1232 output,
1233 base,
1234 decoded_samples,
1235 silk_lr,
1236 internal_sample_rate,
1237 );
1238 silk_off += out_len;
1239 }
1240
1241 // --- Opus redundancy layer (opus_decoder.c:420-580) ---
1242 // A SILK-only frame carries IMPLICIT CELT redundancy: if >= 17
1243 // bits remain after SILK, the trailing bytes ARE a 5 ms CELT
1244 // frame (no flag) used to smooth mode/bandwidth transitions.
1245 let mut redundant_rng = 0u32;
1246 let mut redundancy = false;
1247 let mut celt_to_silk = false;
1248 let plen = payload.len();
1249 let f5 = (self.sampling_rate / 200) as usize;
1250 let f2_5 = f5 / 2;
1251 let red_end_band = celt_endband_for_bandwidth(bandwidth);
1252 let mut red_buf = [0.0f32; 480]; // F5 * <=2ch, planar
1253 let mut red_bytes = 0usize;
1254 if self.sampling_rate == 48000 && rc.tell() + 17 <= (plen as i32) * 8 {
1255 redundancy = true;
1256 celt_to_silk = rc.decode_bit_logp(1);
1257 red_bytes = plen - (((rc.tell() + 7) >> 3) as usize);
1258 if red_bytes < 2 || red_bytes >= plen {
1259 redundancy = false;
1260 red_bytes = 0;
1261 }
1262 }
1263 // A redundant frame already bridges the seam, so it replaces
1264 // the cross-fade rather than stacking with it
1265 // (opus_decoder.c:532). Conceal before the redundant frame
1266 // below advances the CELT state it reads.
1267 let fade_transition = transition && fi == 0 && !redundancy;
1268 if fade_transition {
1269 self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1270 }
1271 // CELT->SILK: the redundant frame continues the prior CELT
1272 // state (a fade-out of the previous CELT mode). Decode BEFORE
1273 // the hybrid->SILK silence frame to keep libopus state order.
1274 if redundancy && celt_to_silk {
1275 redundant_rng = self.decode_redundant_celt(
1276 &payload[plen - red_bytes..],
1277 false,
1278 packet_channels,
1279 red_end_band,
1280 &mut red_buf[..f5 * self.channels],
1281 );
1282 }
1283 // Hybrid->SILK transition: let the CELT MDCT fade out by
1284 // decoding a 2-byte silence frame; its 2.5 ms overlap tail is
1285 // ADDED to the output (libopus decodes it into pcm before the
1286 // SILK sum).
1287 if self.sampling_rate == 48000
1288 && prev_mode_frame == Some(OpusMode::Hybrid)
1289 && !(redundancy && celt_to_silk && self.prev_redundancy)
1290 {
1291 let silence = [0xFFu8, 0xFF];
1292 let mut sil_buf = [0.0f32; 240]; // F2_5 * <=2ch
1293 self.celt_dec.set_stream_channels(packet_channels);
1294 let mut src = RangeCoder::new_decoder(&silence);
1295 self.celt_dec.decode_from_range_coder_with_band_range(
1296 &mut src,
1297 16,
1298 f2_5,
1299 &mut sil_buf[..f2_5 * self.channels],
1300 0,
1301 red_end_band,
1302 );
1303 let region = &mut output[out_start..out_start + sub_output_len];
1304 for (o, s) in region.iter_mut().zip(&sil_buf[..f2_5 * self.channels]) {
1305 *o += *s;
1306 }
1307 }
1308 // SILK->CELT: reset, then decode — this PRIMES the CELT state
1309 // for the upcoming CELT-mode frames (which is why the next mode
1310 // change skips its reset when prev_redundancy is set).
1311 if redundancy && !celt_to_silk {
1312 redundant_rng = self.decode_redundant_celt(
1313 &payload[plen - red_bytes..],
1314 true,
1315 packet_channels,
1316 red_end_band,
1317 &mut red_buf[..f5 * self.channels],
1318 );
1319 }
1320 if redundancy {
1321 let window = celt::modes::default_mode().window;
1322 let region = &mut output[out_start..out_start + sub_output_len];
1323 if celt_to_silk {
1324 redundancy_fade_start(region, &red_buf, f2_5, self.channels, window);
1325 } else {
1326 redundancy_fade_end(
1327 region,
1328 sub_frame_size,
1329 &red_buf,
1330 f2_5,
1331 self.channels,
1332 window,
1333 );
1334 }
1335 }
1336 if fade_transition {
1337 self.apply_transition(
1338 &mut output[out_start..out_start + sub_output_len],
1339 sub_frame_size,
1340 );
1341 }
1342 self.prev_redundancy = redundancy && !celt_to_silk;
1343 prev_mode_frame = Some(OpusMode::SilkOnly);
1344 self.last_range = rc.rng ^ redundant_rng;
1345 }
1346 self.prev_mode = Some(OpusMode::SilkOnly);
1347 Ok(frame_size)
1348 }
1349
1350 OpusMode::CeltOnly => {
1351 let celt_end_band = self.celt_end_band_from_toc(toc);
1352 // Conceal the outgoing SILK/hybrid mode BEFORE the reset below
1353 // wipes the state it reads (opus_decoder.c:388).
1354 if transition {
1355 self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1356 }
1357 // libopus opus_decoder.c:515 — discard CELT state on a mode change
1358 // unless the previous frame's SILK->CELT redundant frame already
1359 // primed it.
1360 if let Some(pm) = self.prev_mode
1361 && pm != OpusMode::CeltOnly
1362 && !self.prev_redundancy
1363 {
1364 self.celt_dec.reset();
1365 }
1366 self.prev_redundancy = false;
1367 // Mono packet in a stereo stream => C=1, CC=2 (continuous state).
1368 self.celt_dec.set_stream_channels(packet_channels);
1369
1370 for (fi, payload) in frame_payloads.iter().enumerate() {
1371 let mut rc = RangeCoder::new_decoder(payload);
1372 let total_bits = (payload.len() * 8) as i32;
1373 let needed = sub_frame_size * self.channels;
1374 let out_start = fi * needed;
1375 let out_end = (out_start + needed).min(output.len());
1376
1377 if output.len() < out_end {
1378 return Err(Error::buffer_too_small(out_end, output.len()));
1379 }
1380
1381 // No clamping: libopus's float API returns the
1382 // reconstruction as-is, and codec ringing legitimately
1383 // overshoots slightly. Clamping here also made this path
1384 // disagree with the SILK path, which never did.
1385 self.celt_dec.decode_from_range_coder_with_band_range(
1386 &mut rc,
1387 total_bits,
1388 sub_frame_size,
1389 &mut output[out_start..out_end],
1390 0,
1391 celt_end_band,
1392 );
1393 self.last_range = rc.rng;
1394 }
1395 if transition {
1396 self.apply_transition(&mut output[..sub_output_len], sub_frame_size);
1397 }
1398 self.prev_mode = Some(OpusMode::CeltOnly);
1399 Ok(frame_size)
1400 }
1401
1402 OpusMode::Hybrid => {
1403 let internal_sample_rate = 16000;
1404 let internal_frame_size =
1405 (frame_duration_ms * internal_sample_rate / 1000) as usize;
1406 let celt_end_band = self.celt_end_band_from_toc(toc);
1407
1408 // Initialised even where the rates already match: the copy
1409 // path still applies the resampler's input delay, and
1410 // `render_silk_frame` now routes every SILK frame through it.
1411 if internal_sample_rate != self.prev_internal_rate {
1412 self.silk_resampler
1413 .init(internal_sample_rate, self.sampling_rate);
1414 self.silk_resampler_r
1415 .init(internal_sample_rate, self.sampling_rate);
1416 self.prev_internal_rate = internal_sample_rate;
1417 }
1418 self.silk_internal_rate = internal_sample_rate;
1419 self.reset_silk_after_celt_only();
1420
1421 // Same SILK stereo/channel handling as the SilkOnly arm: true L/R
1422 // low band via MS->LR for stereo packets; per-packet internal
1423 // channel switch with side-channel/stereo-state resets.
1424 let silk_lr = self.setup_silk_channels(packet_channels);
1425
1426 for (fi, payload) in frame_payloads.iter().enumerate() {
1427 let mut rc = RangeCoder::new_decoder(payload);
1428 let pcm_silk_i16_len = internal_frame_size * self.channels;
1429 if pcm_silk_i16_len + 2 > self.w_pcm_i16.len() {
1430 return Err(Error::InvalidPacket("opus: SILK frame size exceeds buffer"));
1431 }
1432
1433 // Prepend the previous frame's last two samples (sMid) and
1434 // decode at offset 2, matching libopus's samplesOut1_tmp[n][2]
1435 // layout — the resampler is fed from offset 1 (the 1-sample
1436 // delay line), keeping the SILK low band aligned with the CELT
1437 // high band exactly as in the reference.
1438 let s_mid = self.silk_s_mid;
1439 let ret = {
1440 let (silk_dec, pcm_i16) = (&mut self.silk_dec, &mut self.w_pcm_i16);
1441 pcm_i16[0] = s_mid[0];
1442 pcm_i16[1] = s_mid[1];
1443 silk_dec.decode(
1444 &mut rc,
1445 &mut pcm_i16[2..pcm_silk_i16_len + 2],
1446 silk::decode_frame::FLAG_DECODE_NORMAL,
1447 true,
1448 frame_duration_ms,
1449 internal_sample_rate,
1450 )
1451 };
1452
1453 if ret < 0 {
1454 return Err(Error::Internal("SILK decoding failed"));
1455 }
1456
1457 let silk_out_len = sub_frame_size * self.channels;
1458 self.w_silk_out[..silk_out_len].fill(0.0);
1459 if ret > 0 {
1460 let decoded_samples = ret as usize;
1461 if decoded_samples >= 2 {
1462 self.silk_s_mid[0] = self.w_pcm_i16[decoded_samples];
1463 self.silk_s_mid[1] = self.w_pcm_i16[decoded_samples + 1];
1464 }
1465 let ratio = self.sampling_rate as f64 / internal_sample_rate as f64;
1466 let out_len =
1467 ((decoded_samples as f64 * ratio) as usize).min(sub_frame_size);
1468 debug_assert!(out_len <= self.w_pcm_resampled.len());
1469 if silk_lr {
1470 // Stereo low band: L/R from dec_api (already in the
1471 // 1-sample-delay layout), each through its own resampler.
1472 self.silk_resampler.process(
1473 &mut self.w_pcm_resampled[..out_len],
1474 &self.silk_dec.l_out[..decoded_samples],
1475 decoded_samples as i32,
1476 );
1477 for i in 0..out_len {
1478 self.w_silk_out[i * 2] = self.w_pcm_resampled[i] as f32 / 32768.0;
1479 }
1480 self.silk_resampler_r.process(
1481 &mut self.w_pcm_resampled[..out_len],
1482 &self.silk_dec.r_out[..decoded_samples],
1483 decoded_samples as i32,
1484 );
1485 for i in 0..out_len {
1486 self.w_silk_out[i * 2 + 1] =
1487 self.w_pcm_resampled[i] as f32 / 32768.0;
1488 }
1489 } else {
1490 self.silk_resampler.process(
1491 &mut self.w_pcm_resampled[..out_len],
1492 &self.w_pcm_i16[1..1 + decoded_samples],
1493 decoded_samples as i32,
1494 );
1495 for i in 0..out_len {
1496 let v = self.w_pcm_resampled[i] as f32 / 32768.0;
1497 for ch in 0..self.channels {
1498 self.w_silk_out[i * self.channels + ch] = v;
1499 }
1500 }
1501 // Mono packet, stereo output: keep the right-channel
1502 // resampler continuous (libopus dec_API.c:351-355).
1503 if self.channels == 2 {
1504 self.silk_resampler_r.process(
1505 &mut self.w_pcm_resampled[..out_len],
1506 &self.w_pcm_i16[1..1 + decoded_samples],
1507 decoded_samples as i32,
1508 );
1509 for i in 0..out_len {
1510 self.w_silk_out[i * 2 + 1] =
1511 self.w_pcm_resampled[i] as f32 / 32768.0;
1512 }
1513 }
1514 }
1515 }
1516
1517 // --- Opus redundancy layer, hybrid form (opus_decoder.c) ---
1518 // redundancy = bit(12); if set: celt_to_silk = bit(1),
1519 // redundancy_bytes = uint(256)+2 taken from the END of the
1520 // packet — the MAIN CELT layer still decodes, but with the
1521 // range coder's storage shrunk by those bytes (this changes
1522 // its raw-bit region and tell budget).
1523 let plen = payload.len();
1524 let mut redundancy = false;
1525 let mut celt_to_silk = false;
1526 let mut red_bytes = 0usize;
1527 let mut effective_len = plen;
1528 #[cfg(feature = "probe")]
1529 {
1530 self.probe_silk_bits = rc.tell();
1531 self.probe_total_bits = (plen as i32) * 8;
1532 }
1533 if rc.tell() + 37 <= (plen as i32) * 8 {
1534 redundancy = rc.decode_bit_logp(12);
1535 if redundancy {
1536 celt_to_silk = rc.decode_bit_logp(1);
1537 red_bytes = rc.dec_uint(256) as usize + 2;
1538 if red_bytes <= effective_len {
1539 effective_len -= red_bytes;
1540 } else {
1541 red_bytes = 0;
1542 redundancy = false;
1543 }
1544 if redundancy && (effective_len as i32) * 8 < rc.tell() {
1545 effective_len = plen;
1546 red_bytes = 0;
1547 redundancy = false;
1548 }
1549 if redundancy {
1550 rc.storage -= red_bytes as u32;
1551 }
1552 }
1553 }
1554 let f5 = (self.sampling_rate / 200) as usize;
1555 let f2_5 = f5 / 2;
1556 let red_end_band = celt_endband_for_bandwidth(bandwidth);
1557 let mut red_buf = [0.0f32; 480];
1558 let mut redundant_rng = 0u32;
1559 let do_red = redundancy && self.sampling_rate == 48000;
1560 // As in the SILK-only arm: a redundant frame replaces the
1561 // mode-switch cross-fade (opus_decoder.c:532), and the
1562 // concealment must run before the redundant frame or the
1563 // CELT reset below disturbs the state it reads.
1564 let fade_transition = transition && fi == 0 && !redundancy;
1565 if fade_transition {
1566 self.fill_transition(sub_frame_size, prev_celt_end_band)?;
1567 }
1568 // CELT->SILK: redundant frame decodes BEFORE the main CELT,
1569 // continuing the prior CELT state (fade-out of previous CELT).
1570 if do_red && celt_to_silk {
1571 redundant_rng = self.decode_redundant_celt(
1572 &payload[plen - red_bytes..],
1573 false,
1574 packet_channels,
1575 red_end_band,
1576 &mut red_buf[..f5 * self.channels],
1577 );
1578 }
1579
1580 // Main CELT high band. libopus opus_decoder.c:515 — reset CELT
1581 // on a mode change unless primed by prior SILK->CELT redundancy.
1582 if fi == 0
1583 && let Some(pm) = self.prev_mode
1584 && pm != OpusMode::Hybrid
1585 && !self.prev_redundancy
1586 {
1587 self.celt_dec.reset();
1588 }
1589 self.celt_dec.set_stream_channels(packet_channels);
1590 let total_bits = (effective_len * 8) as i32;
1591 {
1592 let (celt_dec, celt_out) = (&mut self.celt_dec, &mut self.w_celt_out);
1593 celt_dec.decode_from_range_coder_with_band_range(
1594 &mut rc,
1595 total_bits,
1596 sub_frame_size,
1597 &mut celt_out[..silk_out_len],
1598 17,
1599 celt_end_band,
1600 );
1601 }
1602
1603 let out_start = fi * silk_out_len;
1604 let total = silk_out_len.min(output.len() - out_start);
1605 for j in 0..total {
1606 output[out_start + j] = self.w_silk_out[j] + self.w_celt_out[j];
1607 }
1608
1609 // SILK->CELT: reset + decode the redundant frame AFTER the main
1610 // decode; it primes the CELT state for the upcoming CELT mode.
1611 if do_red && !celt_to_silk {
1612 redundant_rng = self.decode_redundant_celt(
1613 &payload[plen - red_bytes..],
1614 true,
1615 packet_channels,
1616 red_end_band,
1617 &mut red_buf[..f5 * self.channels],
1618 );
1619 }
1620 if do_red {
1621 let window = celt::modes::default_mode().window;
1622 let region = &mut output[out_start..out_start + silk_out_len];
1623 if celt_to_silk {
1624 redundancy_fade_start(region, &red_buf, f2_5, self.channels, window);
1625 } else {
1626 redundancy_fade_end(
1627 region,
1628 sub_frame_size,
1629 &red_buf,
1630 f2_5,
1631 self.channels,
1632 window,
1633 );
1634 }
1635 }
1636 if fade_transition {
1637 self.apply_transition(
1638 &mut output[out_start..out_start + silk_out_len],
1639 sub_frame_size,
1640 );
1641 }
1642 self.prev_redundancy = redundancy && !celt_to_silk;
1643 self.last_range = rc.rng ^ redundant_rng;
1644 }
1645 self.prev_mode = Some(OpusMode::Hybrid);
1646 Ok(frame_size)
1647 }
1648 }
1649 }
1650}
1651
1652impl OpusDecoder {
1653 #[inline(always)]
1654 fn celt_end_band_from_toc(&self, toc: u8) -> usize {
1655 let mode = celt::modes::default_mode();
1656 let top = mode.eff_ebands;
1657 if mode_from_toc(toc) == OpusMode::CeltOnly && toc >= 0x80 {
1658 const FROM_OPUS_TABLE: [u8; 16] = [
1659 0x80, 0x88, 0x90, 0x98, 0x40, 0x48, 0x50, 0x58, 0x20, 0x28, 0x30, 0x38, 0x00, 0x08,
1660 0x10, 0x18,
1661 ];
1662 let idx = ((toc >> 3) - 16) as usize;
1663 let data0 = FROM_OPUS_TABLE[idx] | (toc & 0x7);
1664 let trim = (data0 >> 5) as usize;
1665 return top.saturating_sub(2 * trim).max(1);
1666 }
1667 // Hybrid: libopus maps the packet bandwidth to a CELT end band
1668 // (opus_decoder.c: SWB -> 19, FB -> 21). Decoding SWB hybrid with 21
1669 // reads two bands the encoder never coded -> range desync every packet.
1670 if mode_from_toc(toc) == OpusMode::Hybrid
1671 && bandwidth_from_toc(toc) == Bandwidth::Superwideband
1672 {
1673 return 19.min(top);
1674 }
1675 top
1676 }
1677
1678 /// Decode a redundant CELT frame (opus_decoder.c "5 ms redundant frame"):
1679 /// start band 0, end band from the packet bandwidth, 5 ms, its own range
1680 /// decoder. Returns the redundant final range; PLANAR output in `buf`
1681 /// (F5 samples per state channel). Only valid at 48 kHz output.
1682 fn decode_redundant_celt(
1683 &mut self,
1684 red: &[u8],
1685 reset_first: bool,
1686 packet_channels: usize,
1687 end_band: usize,
1688 buf: &mut [f32],
1689 ) -> u32 {
1690 if reset_first {
1691 self.celt_dec.reset();
1692 }
1693 self.celt_dec.set_stream_channels(packet_channels);
1694 let f5 = (self.sampling_rate / 200) as usize;
1695 let mut rrc = RangeCoder::new_decoder(red);
1696 let total_bits = (red.len() * 8) as i32;
1697 self.celt_dec
1698 .decode_from_range_coder_with_band_range(&mut rrc, total_bits, f5, buf, 0, end_band);
1699 rrc.rng
1700 }
1701}
1702
1703/// First CELT band the hybrid layer codes; below it the SILK layer owns the
1704/// spectrum (libopus `start_band = 17`).
1705const HYBRID_START_BAND: usize = 17;
1706
1707/// libopus opus_decoder.c bandwidth -> CELT end band for the packet.
1708/// smooth_fade cross-fades (w = window[i]^2, 48 kHz inc=1) applied to the
1709/// interleaved output region of one frame. `red` is interleaved too.
1710/// celt_to_silk: redundant frame occupies the START of the frame — first 2.5 ms
1711/// copied verbatim, next 2.5 ms fades redundant -> main.
1712///
1713/// Indexing invariant: `out.len() >= f5 * channels` (writes reach sample
1714/// f5-1 = 2*f2_5-1). A malformed multi-frame packet used to violate this (a
1715/// hostile frame count made the per-frame region tinier than F5, fuzzer-found
1716/// OOB panics here); decode() now rejects such packets up front exactly as C
1717/// libopus does (opus_decode_native's count*packet_frame_size > frame_size ->
1718/// OPUS_BUFFER_TOO_SMALL, and the 120 ms cap of opus_packet_parse_impl), so a
1719/// redundant frame always has >= 10 ms of frame to fade into, as in C.
1720fn redundancy_fade_start(
1721 out: &mut [f32],
1722 red: &[f32],
1723 f2_5: usize,
1724 channels: usize,
1725 window: &[f32],
1726) {
1727 out[..f2_5 * channels].copy_from_slice(&red[..f2_5 * channels]);
1728 for i in 0..f2_5 {
1729 let w = window[i] * window[i];
1730 for c in 0..channels {
1731 let idx = (f2_5 + i) * channels + c;
1732 out[idx] = (1.0 - w) * red[idx] + w * out[idx];
1733 }
1734 }
1735}
1736
1737/// SILK->CELT: redundant frame occupies the END of the frame — the last 2.5 ms
1738/// fades main -> redundant (second half of the redundant frame).
1739///
1740/// Indexing invariant: `frame_samples >= f2_5` and `out.len() >=
1741/// frame_samples * channels` (the index `frame_samples - f2_5 + i` would
1742/// otherwise underflow). A malformed multi-frame packet used to violate this
1743/// (fuzzer-found subtract-with-overflow panic here); decode() now rejects such
1744/// packets up front exactly as C libopus does (opus_decode_native's
1745/// count*packet_frame_size > frame_size -> OPUS_BUFFER_TOO_SMALL, plus the
1746/// 120 ms cap of opus_packet_parse_impl), so redundancy only ever runs on
1747/// frames of >= 10 ms, as in C.
1748fn redundancy_fade_end(
1749 out: &mut [f32],
1750 frame_samples: usize,
1751 red: &[f32],
1752 f2_5: usize,
1753 channels: usize,
1754 window: &[f32],
1755) {
1756 for i in 0..f2_5 {
1757 let w = window[i] * window[i];
1758 for c in 0..channels {
1759 let idx = (frame_samples - f2_5 + i) * channels + c;
1760 out[idx] = (1.0 - w) * out[idx] + w * red[(f2_5 + i) * channels + c];
1761 }
1762 }
1763}