1use super::{Decoder, Encoder, PcmBuf, Sample};
2pub use opus_rs::Application as OpusApplication;
3use opus_rs::{Application, OpusDecoder as OpusDecoderRaw, OpusEncoder as OpusEncoderRaw};
4
5pub struct OpusDecoder {
6 decoder: OpusDecoderRaw,
7 sample_rate: u32,
8 channels: u16,
9 w_output_f32: Vec<f32>,
10 w_pcm_i16: Vec<i16>,
11}
12
13impl OpusDecoder {
14 pub fn new(sample_rate: u32, channels: u16) -> Self {
16 let decoder = OpusDecoderRaw::new(sample_rate as i32, channels as usize)
17 .expect("Failed to create Opus decoder");
18
19 Self {
20 decoder,
21 sample_rate,
22 channels,
23 w_output_f32: Vec::new(),
24 w_pcm_i16: Vec::new(),
25 }
26 }
27
28 pub fn new_default() -> Self {
30 Self::new(48000, 2)
31 }
32
33 pub fn decode_into(&mut self, data: &[u8], output: &mut [i16]) -> usize {
34 if data.is_empty() {
35 return 0;
36 }
37
38 let packet_channels = if data[0] & 0x04 != 0 { 2usize } else { 1 };
43 if self.channels as usize != packet_channels {
44 self.channels = packet_channels as u16;
45 self.decoder = OpusDecoderRaw::new(self.sample_rate as i32, packet_channels)
46 .expect("Failed to create Opus decoder");
47 }
48
49 let channels = usize::from(self.channels);
50 let frame_size = (self.sample_rate as usize * 20) / 1000;
51 let max_samples = frame_size * channels;
52 if self.w_output_f32.len() < max_samples {
53 self.w_output_f32.resize(max_samples, 0.0);
54 }
55
56 match self
57 .decoder
58 .decode(data, frame_size, &mut self.w_output_f32[..max_samples])
59 {
60 Ok(len) => {
61 let total_samples = len * channels;
62 if total_samples == 0 {
63 return 0;
64 }
65
66 if self.w_pcm_i16.len() < total_samples {
67 self.w_pcm_i16.resize(total_samples, 0);
68 }
69
70 for i in 0..total_samples {
71 self.w_pcm_i16[i] =
72 (self.w_output_f32[i] * 32768.0).clamp(-32768.0, 32767.0) as i16;
73 }
74
75 let n = total_samples.min(output.len());
76 output[..n].copy_from_slice(&self.w_pcm_i16[..n]);
77 n
78 }
79 Err(_) => 0,
80 }
81 }
82}
83
84impl Decoder for OpusDecoder {
85 fn decode(&mut self, data: &[u8]) -> PcmBuf {
86 let input_channels = usize::from(self.channels);
87 if input_channels == 0 || data.is_empty() {
88 return Vec::new();
89 }
90
91 let frame_size = (self.sample_rate as usize * 20) / 1000;
92 let max_samples = frame_size * input_channels;
93 let mut pcm = vec![0i16; max_samples];
94 let n = self.decode_into(data, &mut pcm);
95 pcm.truncate(n);
96 if usize::from(self.channels) == 2 {
99 pcm = pcm
100 .chunks_exact(2)
101 .map(|chunk| ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16)
102 .collect();
103 }
104 pcm
105 }
106
107 fn sample_rate(&self) -> u32 {
108 self.sample_rate
109 }
110
111 fn channels(&self) -> u16 {
112 self.channels
113 }
114}
115
116pub struct OpusEncoder {
117 encoder: OpusEncoderRaw,
118 sample_rate: u32,
119 channels: u16,
120 w_input_f32: Vec<f32>,
121 w_packet: Vec<u8>,
122}
123
124impl OpusEncoder {
125 pub fn new_with_application(sample_rate: u32, channels: u16, application: Application) -> Self {
126 let encoder = OpusEncoderRaw::new(sample_rate as i32, channels as usize, application)
127 .expect("Failed to create Opus encoder");
128
129 Self {
130 encoder,
131 sample_rate,
132 channels,
133 w_input_f32: Vec::new(),
134 w_packet: vec![0u8; 1275],
135 }
136 }
137
138 pub fn new(sample_rate: u32, channels: u16) -> Self {
145 let mut enc = Self::new_with_application(sample_rate, channels, Application::Voip);
146 enc.encoder.bitrate_bps = if channels == 2 { 64000 } else { 48000 };
147 enc.encoder.complexity = 5;
148 enc.encoder.use_cbr = true;
149 enc
150 }
151
152 pub fn new_default() -> Self {
154 Self::new(48000, 2)
155 }
156
157 pub fn set_bitrate(&mut self, bitrate_bps: i32) {
159 self.encoder.bitrate_bps = bitrate_bps;
160 }
161
162 pub fn set_complexity(&mut self, complexity: i32) {
164 self.encoder.complexity = complexity;
165 }
166
167 pub fn set_cbr(&mut self, cbr: bool) {
169 self.encoder.use_cbr = cbr;
170 }
171
172 pub fn encode_into(&mut self, samples: &[Sample], output: &mut [u8]) -> Option<usize> {
176 let channels = usize::from(self.channels);
177 if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
178 return None;
179 }
180
181 let frame_size = samples.len() / channels;
182
183 if self.w_input_f32.len() < samples.len() {
184 self.w_input_f32.resize(samples.len(), 0.0);
185 }
186
187 for (dst, &s) in self.w_input_f32[..samples.len()]
188 .iter_mut()
189 .zip(samples.iter())
190 {
191 *dst = s as f32 / 32768.0;
192 }
193
194 self.encoder
195 .encode(&self.w_input_f32[..samples.len()], frame_size, output)
196 .ok()
197 }
198
199 fn encode_raw(&mut self, samples: &[Sample]) -> Vec<u8> {
200 let channels = usize::from(self.channels);
201 if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
202 return Vec::new();
203 }
204
205 let frame_size = samples.len() / channels;
206
207 if self.w_input_f32.len() < samples.len() {
208 self.w_input_f32.resize(samples.len(), 0.0);
209 }
210
211 for (dst, &s) in self.w_input_f32[..samples.len()]
212 .iter_mut()
213 .zip(samples.iter())
214 {
215 *dst = s as f32 / 32768.0;
216 }
217
218 match self.encoder.encode(
219 &self.w_input_f32[..samples.len()],
220 frame_size,
221 &mut self.w_packet,
222 ) {
223 Ok(len) => {
224 let mut out = Vec::with_capacity(len);
225 out.extend_from_slice(&self.w_packet[..len]);
226 out
227 }
228 Err(_) => Vec::new(),
229 }
230 }
231}
232
233impl Encoder for OpusEncoder {
234 fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
235 if self.channels == 2 {
236 let mut stereo_samples = Vec::with_capacity(samples.len() * 2);
237 for &sample in samples {
238 stereo_samples.push(sample);
239 stereo_samples.push(sample);
240 }
241 return self.encode_raw(&stereo_samples);
242 }
243 self.encode_raw(samples)
244 }
245
246 fn sample_rate(&self) -> u32 {
247 self.sample_rate
248 }
249
250 fn channels(&self) -> u16 {
251 self.channels
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 fn make_mono_pcm_20ms() -> Vec<i16> {
260 (0..960).map(|i| ((i * 100) % 32767) as i16).collect()
261 }
262
263 #[test]
264 fn test_opus_encode_decode_20ms_produces_960_mono_samples() {
265 let mut enc = OpusEncoder::new_default();
266 let pcm = make_mono_pcm_20ms();
267 let opus_pkt = enc.encode(&pcm);
268 assert!(!opus_pkt.is_empty(), "encoder should produce output");
269
270 assert!(opus_pkt[0] & 0x04 != 0, "packet should be stereo");
272
273 let mut dec = OpusDecoder::new_default();
274 let decoded = dec.decode(&opus_pkt);
275
276 assert_eq!(
278 decoded.len(),
279 960,
280 "decoder should downmix stereo→mono and output 960 samples, got {}",
281 decoded.len()
282 );
283 }
284
285 #[test]
286 fn test_opus_consecutive_frames_all_produce_960() {
287 let mut enc = OpusEncoder::new_default();
288 let pcm = make_mono_pcm_20ms();
289 let opus_pkt = enc.encode(&pcm);
290
291 let mut dec = OpusDecoder::new_default();
292 for i in 0..5 {
293 let decoded = dec.decode(&opus_pkt);
294 assert_eq!(
295 decoded.len(),
296 960,
297 "frame {} should produce 960 mono samples, got {}",
298 i,
299 decoded.len()
300 );
301 }
302 }
303
304 #[test]
305 fn test_opus_decoder_output_has_reasonable_energy() {
306 let mut enc = OpusEncoder::new_default();
307 let pcm: Vec<i16> = (0..960)
309 .map(|i| {
310 let t = i as f64 / 48000.0;
311 (16384.0 * (2.0 * std::f64::consts::PI * 440.0 * t).sin()) as i16
312 })
313 .collect();
314 let opus_pkt = enc.encode(&pcm);
315
316 let mut dec = OpusDecoder::new_default();
317 let decoded = dec.decode(&opus_pkt);
318 assert_eq!(decoded.len(), 960);
319
320 let energy: f64 =
321 decoded.iter().map(|&s| (s as f64).powi(2)).sum::<f64>() / decoded.len() as f64;
322 let rms = energy.sqrt();
323 assert!(
324 rms > 100.0 && rms < 20000.0,
325 "decoded audio RMS {} should be in reasonable range",
326 rms
327 );
328 }
329
330 #[test]
331 fn test_opus_decoder_handles_mono_packet_gracefully() {
332 let mut mono_enc = OpusEncoder::new(48000, 1);
334 let pcm = make_mono_pcm_20ms();
335 let mono_pkt = mono_enc.encode(&pcm);
336 assert!(!mono_pkt.is_empty());
337 assert!(mono_pkt[0] & 0x04 == 0, "mono encoder should produce mono packet");
339
340 let mut dec = OpusDecoder::new_default();
342 let decoded = dec.decode(&mono_pkt);
343 assert_eq!(
344 decoded.len(),
345 960,
346 "first mono packet should produce exactly 960 mono samples, got {}",
347 decoded.len()
348 );
349
350 let decoded2 = dec.decode(&mono_pkt);
352 assert_eq!(
353 decoded2.len(),
354 960,
355 "second mono packet should also produce 960 mono samples, got {}",
356 decoded2.len()
357 );
358 }
359
360 #[test]
361 fn test_opus_stereo_packet_downmix_produces_960() {
362 let mut enc = OpusEncoder::new_default();
363 let pcm = make_mono_pcm_20ms();
364 let stereo_pkt = enc.encode(&pcm);
365 assert!(stereo_pkt[0] & 0x04 != 0);
366
367 let mut dec = OpusDecoder::new_default();
368 let decoded = dec.decode(&stereo_pkt);
369 assert_eq!(
370 decoded.len(),
371 960,
372 "stereo packet should downmix to 960 mono samples"
373 );
374 }
375}