1#[cfg(feature = "std")]
2use super::PcmBuf;
3use super::{CodecError, Decoder, Encoder, Sample};
4#[cfg(not(feature = "std"))]
6use alloc::boxed::Box;
7pub use opus_rs::Application as OpusApplication;
8use opus_rs::{Application, OpusDecoder as OpusDecoderRaw, OpusEncoder as OpusEncoderRaw};
9
10const OPUS_MAX_FRAME: usize = 960; const OPUS_MAX_CHANNELS: usize = 2;
13const OPUS_MAX_SAMPLES: usize = OPUS_MAX_FRAME * OPUS_MAX_CHANNELS; #[cfg(feature = "std")]
17const OPUS_MAX_PACKET: usize = 1276;
18
19pub struct OpusDecoder {
20 decoder: Box<OpusDecoderRaw>,
21 sample_rate: u32,
22 channels: u16,
23 w_output_f32: [f32; OPUS_MAX_SAMPLES],
24 w_pcm_i16: [i16; OPUS_MAX_SAMPLES],
25}
26
27impl OpusDecoder {
28 pub fn new(sample_rate: u32, channels: u16) -> Self {
30 let decoder = Box::new(
31 OpusDecoderRaw::new(sample_rate as i32, channels as usize)
32 .expect("Failed to create Opus decoder"),
33 );
34
35 Self {
36 decoder,
37 sample_rate,
38 channels,
39 w_output_f32: [0.0; OPUS_MAX_SAMPLES],
40 w_pcm_i16: [0; OPUS_MAX_SAMPLES],
41 }
42 }
43
44 pub fn new_default() -> Self {
46 Self::new(48000, 2)
47 }
48
49 pub fn decode_into_raw(&mut self, data: &[u8], output: &mut [i16]) -> usize {
52 if data.is_empty() {
53 return 0;
54 }
55
56 let packet_channels = if data[0] & 0x04 != 0 { 2usize } else { 1 };
61 if self.channels as usize != packet_channels {
62 self.channels = packet_channels as u16;
63 *self.decoder = OpusDecoderRaw::new(self.sample_rate as i32, packet_channels)
65 .expect("Failed to create Opus decoder");
66 }
67
68 let channels = usize::from(self.channels);
69 let frame_size = (self.sample_rate as usize * 20) / 1000;
70 let max_samples = frame_size * channels;
71
72 match self
73 .decoder
74 .decode(data, frame_size, &mut self.w_output_f32[..max_samples])
75 {
76 Ok(len) => {
77 let total_samples = len * channels;
78 if total_samples == 0 {
79 return 0;
80 }
81
82 for i in 0..total_samples {
83 self.w_pcm_i16[i] =
84 (self.w_output_f32[i] * 32768.0).clamp(-32768.0, 32767.0) as i16;
85 }
86
87 let n = total_samples.min(output.len());
88 output[..n].copy_from_slice(&self.w_pcm_i16[..n]);
89 n
90 }
91 Err(_) => 0,
92 }
93 }
94}
95
96impl Decoder for OpusDecoder {
97 fn decode_into(&mut self, data: &[u8], out: &mut [Sample]) -> Result<usize, CodecError> {
98 if data.is_empty() {
99 return Ok(0);
100 }
101 let n = self.decode_into_raw(data, out);
102 if n == 0 {
103 Err(CodecError::DecodeFailed)
104 } else {
105 Ok(n)
106 }
107 }
108
109 fn max_decode_samples(&self, n_bytes: usize) -> usize {
110 let frame_size = (self.sample_rate as usize * 20) / 1000;
113 let _ = n_bytes;
114 frame_size * 2
115 }
116
117 fn sample_rate(&self) -> u32 {
118 self.sample_rate
119 }
120
121 fn channels(&self) -> u16 {
122 self.channels
123 }
124
125 #[cfg(feature = "std")]
128 fn decode(&mut self, data: &[u8]) -> PcmBuf {
129 if data.is_empty() {
130 return Vec::new();
131 }
132 let packet_channels = if data[0] & 0x04 != 0 { 2usize } else { 1 };
133
134 let frame_size = (self.sample_rate as usize * 20) / 1000;
135 let max_samples = frame_size * packet_channels;
136 let mut pcm = vec![0i16; max_samples];
137 let n = self.decode_into_raw(data, &mut pcm);
138 pcm.truncate(n);
139 if usize::from(self.channels) == 2 {
140 pcm = pcm
141 .chunks_exact(2)
142 .map(|chunk| ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16)
143 .collect();
144 }
145 pcm
146 }
147}
148
149pub struct OpusEncoder {
150 encoder: Box<OpusEncoderRaw>,
151 sample_rate: u32,
152 channels: u16,
153 w_input_f32: [f32; OPUS_MAX_SAMPLES],
154}
155
156impl OpusEncoder {
157 pub fn new_with_application(sample_rate: u32, channels: u16, application: Application) -> Self {
158 let encoder = Box::new(
159 OpusEncoderRaw::new(sample_rate as i32, channels as usize, application)
160 .expect("Failed to create Opus encoder"),
161 );
162
163 Self {
164 encoder,
165 sample_rate,
166 channels,
167 w_input_f32: [0.0; OPUS_MAX_SAMPLES],
168 }
169 }
170
171 pub fn new(sample_rate: u32, channels: u16) -> Self {
178 let mut enc = Self::new_with_application(sample_rate, channels, Application::Voip);
179 enc.encoder.bitrate_bps = if channels == 2 { 64000 } else { 48000 };
180 enc.encoder.complexity = 5;
181 enc.encoder.use_cbr = true;
182 enc
183 }
184
185 pub fn new_default() -> Self {
187 Self::new(48000, 2)
188 }
189
190 pub fn set_bitrate(&mut self, bitrate_bps: i32) {
192 self.encoder.bitrate_bps = bitrate_bps;
193 }
194
195 pub fn set_complexity(&mut self, complexity: i32) {
197 self.encoder.complexity = complexity;
198 }
199
200 pub fn set_cbr(&mut self, cbr: bool) {
202 self.encoder.use_cbr = cbr;
203 }
204
205 pub fn encode_into_raw(&mut self, samples: &[Sample], output: &mut [u8]) -> Option<usize> {
210 let channels = usize::from(self.channels);
211 if samples.is_empty() || channels == 0 || !samples.len().is_multiple_of(channels) {
212 return None;
213 }
214 if samples.len() > OPUS_MAX_SAMPLES {
216 return None;
217 }
218
219 let frame_size = samples.len() / channels;
220
221 for (dst, &s) in self.w_input_f32[..samples.len()]
222 .iter_mut()
223 .zip(samples.iter())
224 {
225 *dst = s as f32 / 32768.0;
226 }
227
228 self.encoder
229 .encode(&self.w_input_f32[..samples.len()], frame_size, output)
230 .ok()
231 }
232
233 #[cfg(feature = "std")]
234 fn encode_raw(&mut self, samples: &[Sample]) -> Vec<u8> {
235 let channels = usize::from(self.channels);
236 if samples.is_empty()
237 || channels == 0
238 || !samples.len().is_multiple_of(channels)
239 || samples.len() > OPUS_MAX_SAMPLES
240 {
241 return Vec::new();
242 }
243
244 let frame_size = samples.len() / channels;
245
246 for (dst, &s) in self.w_input_f32[..samples.len()]
247 .iter_mut()
248 .zip(samples.iter())
249 {
250 *dst = s as f32 / 32768.0;
251 }
252
253 let mut packet = [0u8; OPUS_MAX_PACKET];
254 match self
255 .encoder
256 .encode(&self.w_input_f32[..samples.len()], frame_size, &mut packet)
257 {
258 Ok(len) => packet[..len].to_vec(),
259 Err(_) => Vec::new(),
260 }
261 }
262}
263
264impl Encoder for OpusEncoder {
265 fn encode_into(&mut self, samples: &[Sample], out: &mut [u8]) -> Result<usize, CodecError> {
266 if samples.is_empty() {
267 return Ok(0);
268 }
269 match self.encode_into_raw(samples, out) {
273 Some(n) => Ok(n),
274 None => Err(CodecError::EncodeFailed),
275 }
276 }
277
278 fn max_encode_bytes(&self, _n_samples: usize) -> usize {
279 1275
281 }
282
283 fn sample_rate(&self) -> u32 {
284 self.sample_rate
285 }
286
287 fn channels(&self) -> u16 {
288 self.channels
289 }
290
291 #[cfg(feature = "std")]
294 fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
295 if self.channels == 2 {
296 if samples.len() > OPUS_MAX_FRAME {
298 return Vec::new();
299 }
300 let mut stereo = [0i16; OPUS_MAX_SAMPLES];
301 for (i, &sample) in samples.iter().enumerate() {
302 stereo[2 * i] = sample;
303 stereo[2 * i + 1] = sample;
304 }
305 return self.encode_raw(&stereo[..samples.len() * 2]);
306 }
307 self.encode_raw(samples)
308 }
309}
310
311#[cfg(all(test, feature = "std"))]
316mod tests {
317 use super::*;
318
319 fn make_mono_pcm_20ms() -> Vec<i16> {
320 (0..960).map(|i| ((i * 100) % 32767) as i16).collect()
321 }
322
323 #[test]
324 fn test_opus_encode_decode_20ms_produces_960_mono_samples() {
325 let mut enc = OpusEncoder::new_default();
326 let pcm = make_mono_pcm_20ms();
327 let opus_pkt = enc.encode(&pcm);
328 assert!(!opus_pkt.is_empty(), "encoder should produce output");
329
330 assert!(opus_pkt[0] & 0x04 != 0, "packet should be stereo");
332
333 let mut dec = OpusDecoder::new_default();
334 let decoded = dec.decode(&opus_pkt);
335
336 assert_eq!(
338 decoded.len(),
339 960,
340 "decoder should downmix stereo→mono and output 960 samples, got {}",
341 decoded.len()
342 );
343 }
344
345 #[test]
346 fn test_opus_consecutive_frames_all_produce_960() {
347 let mut enc = OpusEncoder::new_default();
348 let pcm = make_mono_pcm_20ms();
349 let opus_pkt = enc.encode(&pcm);
350
351 let mut dec = OpusDecoder::new_default();
352 for i in 0..5 {
353 let decoded = dec.decode(&opus_pkt);
354 assert_eq!(
355 decoded.len(),
356 960,
357 "frame {} should produce 960 mono samples, got {}",
358 i,
359 decoded.len()
360 );
361 }
362 }
363
364 #[test]
365 fn test_opus_decoder_output_has_reasonable_energy() {
366 let mut enc = OpusEncoder::new_default();
367 let pcm: Vec<i16> = (0..960)
369 .map(|i| {
370 let t = i as f64 / 48000.0;
371 (16384.0 * (2.0 * std::f64::consts::PI * 440.0 * t).sin()) as i16
372 })
373 .collect();
374 let opus_pkt = enc.encode(&pcm);
375
376 let mut dec = OpusDecoder::new_default();
377 let decoded = dec.decode(&opus_pkt);
378 assert_eq!(decoded.len(), 960);
379
380 let energy: f64 =
381 decoded.iter().map(|&s| (s as f64).powi(2)).sum::<f64>() / decoded.len() as f64;
382 let rms = energy.sqrt();
383 assert!(
384 rms > 100.0 && rms < 20000.0,
385 "decoded audio RMS {} should be in reasonable range",
386 rms
387 );
388 }
389
390 #[test]
391 fn test_opus_decoder_handles_mono_packet_gracefully() {
392 let mut mono_enc = OpusEncoder::new(48000, 1);
394 let pcm = make_mono_pcm_20ms();
395 let mono_pkt = mono_enc.encode(&pcm);
396 assert!(!mono_pkt.is_empty());
397 assert!(
399 mono_pkt[0] & 0x04 == 0,
400 "mono encoder should produce mono packet"
401 );
402
403 let mut dec = OpusDecoder::new_default();
405 let decoded = dec.decode(&mono_pkt);
406 assert_eq!(
407 decoded.len(),
408 960,
409 "first mono packet should produce exactly 960 mono samples, got {}",
410 decoded.len()
411 );
412
413 let decoded2 = dec.decode(&mono_pkt);
415 assert_eq!(
416 decoded2.len(),
417 960,
418 "second mono packet should also produce 960 mono samples, got {}",
419 decoded2.len()
420 );
421 }
422
423 #[test]
424 fn test_opus_stereo_packet_downmix_produces_960() {
425 let mut enc = OpusEncoder::new_default();
426 let pcm = make_mono_pcm_20ms();
427 let stereo_pkt = enc.encode(&pcm);
428 assert!(stereo_pkt[0] & 0x04 != 0);
429
430 let mut dec = OpusDecoder::new_default();
431 let decoded = dec.decode(&stereo_pkt);
432 assert_eq!(
433 decoded.len(),
434 960,
435 "stereo packet should downmix to 960 mono samples"
436 );
437 }
438}
439
440#[cfg(all(test, feature = "opus"))]
443mod no_std_tests {
444 use super::*;
445 use alloc::vec;
446 use alloc::vec::Vec;
447
448 #[test]
449 fn test_opus_into_roundtrip() {
450 let mut enc = OpusEncoder::new_default();
451 let mut dec = OpusDecoder::new(48000, 1);
452 let pcm: Vec<i16> = (0..960).map(|i| ((i * 100) % 32767) as i16).collect();
453
454 let mut packet = alloc::vec![0u8; enc.max_encode_bytes(pcm.len())];
455 let n = enc
456 .encode_into(&pcm, &mut packet)
457 .expect("packet sized by max_encode_bytes");
458 packet.truncate(n);
459 assert!(!packet.is_empty(), "encoder should produce output");
460
461 let mut out = alloc::vec![0i16; dec.max_decode_samples(packet.len())];
462 let samples = dec
463 .decode_into(&packet, &mut out)
464 .expect("out sized by max_decode_samples");
465 assert_eq!(samples, 960, "20 ms at 48 kHz must decode to 960 samples");
466 let rms: f64 = out[..samples]
467 .iter()
468 .map(|&s| (s as f64) * (s as f64))
469 .sum::<f64>()
470 / samples as f64;
471 assert!(rms.sqrt() > 1000.0, "decoded signal should keep energy");
472 }
473}