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 if data.is_empty() {
87 return Vec::new();
88 }
89 let packet_channels = if data[0] & 0x04 != 0 { 2usize } else { 1 };
90
91 let frame_size = (self.sample_rate as usize * 20) / 1000;
92 let max_samples = frame_size * packet_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 {
97 pcm = pcm
98 .chunks_exact(2)
99 .map(|chunk| ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16)
100 .collect();
101 }
102 pcm
103 }
104
105 fn sample_rate(&self) -> u32 {
106 self.sample_rate
107 }
108
109 fn channels(&self) -> u16 {
110 self.channels
111 }
112}
113
114pub struct OpusEncoder {
115 encoder: OpusEncoderRaw,
116 sample_rate: u32,
117 channels: u16,
118 w_input_f32: Vec<f32>,
119 w_packet: Vec<u8>,
120 w_stereo: Vec<i16>,
123}
124
125impl OpusEncoder {
126 pub fn new_with_application(sample_rate: u32, channels: u16, application: Application) -> Self {
127 let encoder = OpusEncoderRaw::new(sample_rate as i32, channels as usize, application)
128 .expect("Failed to create Opus encoder");
129
130 Self {
131 encoder,
132 sample_rate,
133 channels,
134 w_input_f32: Vec::new(),
135 w_packet: vec![0u8; 1275],
136 w_stereo: Vec::new(),
137 }
138 }
139
140 pub fn new(sample_rate: u32, channels: u16) -> Self {
147 let mut enc = Self::new_with_application(sample_rate, channels, Application::Voip);
148 enc.encoder.bitrate_bps = if channels == 2 { 64000 } else { 48000 };
149 enc.encoder.complexity = 5;
150 enc.encoder.use_cbr = true;
151 enc
152 }
153
154 pub fn new_default() -> Self {
156 Self::new(48000, 2)
157 }
158
159 pub fn set_bitrate(&mut self, bitrate_bps: i32) {
161 self.encoder.bitrate_bps = bitrate_bps;
162 }
163
164 pub fn set_complexity(&mut self, complexity: i32) {
166 self.encoder.complexity = complexity;
167 }
168
169 pub fn set_cbr(&mut self, cbr: bool) {
171 self.encoder.use_cbr = cbr;
172 }
173
174 pub fn encode_into(&mut self, samples: &[Sample], output: &mut [u8]) -> Option<usize> {
178 let channels = usize::from(self.channels);
179 if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
180 return None;
181 }
182
183 let frame_size = samples.len() / channels;
184
185 if self.w_input_f32.len() < samples.len() {
186 self.w_input_f32.resize(samples.len(), 0.0);
187 }
188
189 for (dst, &s) in self.w_input_f32[..samples.len()]
190 .iter_mut()
191 .zip(samples.iter())
192 {
193 *dst = s as f32 / 32768.0;
194 }
195
196 self.encoder
197 .encode(&self.w_input_f32[..samples.len()], frame_size, output)
198 .ok()
199 }
200
201 fn encode_raw(&mut self, samples: &[Sample]) -> Vec<u8> {
202 let channels = usize::from(self.channels);
203 if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
204 return Vec::new();
205 }
206
207 let frame_size = samples.len() / channels;
208
209 if self.w_input_f32.len() < samples.len() {
210 self.w_input_f32.resize(samples.len(), 0.0);
211 }
212
213 for (dst, &s) in self.w_input_f32[..samples.len()]
214 .iter_mut()
215 .zip(samples.iter())
216 {
217 *dst = s as f32 / 32768.0;
218 }
219
220 match self.encoder.encode(
221 &self.w_input_f32[..samples.len()],
222 frame_size,
223 &mut self.w_packet,
224 ) {
225 Ok(len) => {
226 let mut out = Vec::with_capacity(len);
227 out.extend_from_slice(&self.w_packet[..len]);
228 out
229 }
230 Err(_) => Vec::new(),
231 }
232 }
233}
234
235impl Encoder for OpusEncoder {
236 fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
237 if self.channels == 2 {
238 let mut stereo = std::mem::take(&mut self.w_stereo);
239 stereo.resize(samples.len() * 2, 0);
240 for (i, &sample) in samples.iter().enumerate() {
241 stereo[2 * i] = sample;
242 stereo[2 * i + 1] = sample;
243 }
244 let out = self.encode_raw(&stereo);
245 self.w_stereo = stereo;
246 return out;
247 }
248 self.encode_raw(samples)
249 }
250
251 fn sample_rate(&self) -> u32 {
252 self.sample_rate
253 }
254
255 fn channels(&self) -> u16 {
256 self.channels
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 fn make_mono_pcm_20ms() -> Vec<i16> {
265 (0..960).map(|i| ((i * 100) % 32767) as i16).collect()
266 }
267
268 #[test]
269 fn test_opus_encode_decode_20ms_produces_960_mono_samples() {
270 let mut enc = OpusEncoder::new_default();
271 let pcm = make_mono_pcm_20ms();
272 let opus_pkt = enc.encode(&pcm);
273 assert!(!opus_pkt.is_empty(), "encoder should produce output");
274
275 assert!(opus_pkt[0] & 0x04 != 0, "packet should be stereo");
277
278 let mut dec = OpusDecoder::new_default();
279 let decoded = dec.decode(&opus_pkt);
280
281 assert_eq!(
283 decoded.len(),
284 960,
285 "decoder should downmix stereo→mono and output 960 samples, got {}",
286 decoded.len()
287 );
288 }
289
290 #[test]
291 fn test_opus_consecutive_frames_all_produce_960() {
292 let mut enc = OpusEncoder::new_default();
293 let pcm = make_mono_pcm_20ms();
294 let opus_pkt = enc.encode(&pcm);
295
296 let mut dec = OpusDecoder::new_default();
297 for i in 0..5 {
298 let decoded = dec.decode(&opus_pkt);
299 assert_eq!(
300 decoded.len(),
301 960,
302 "frame {} should produce 960 mono samples, got {}",
303 i,
304 decoded.len()
305 );
306 }
307 }
308
309 #[test]
310 fn test_opus_decoder_output_has_reasonable_energy() {
311 let mut enc = OpusEncoder::new_default();
312 let pcm: Vec<i16> = (0..960)
314 .map(|i| {
315 let t = i as f64 / 48000.0;
316 (16384.0 * (2.0 * std::f64::consts::PI * 440.0 * t).sin()) as i16
317 })
318 .collect();
319 let opus_pkt = enc.encode(&pcm);
320
321 let mut dec = OpusDecoder::new_default();
322 let decoded = dec.decode(&opus_pkt);
323 assert_eq!(decoded.len(), 960);
324
325 let energy: f64 =
326 decoded.iter().map(|&s| (s as f64).powi(2)).sum::<f64>() / decoded.len() as f64;
327 let rms = energy.sqrt();
328 assert!(
329 rms > 100.0 && rms < 20000.0,
330 "decoded audio RMS {} should be in reasonable range",
331 rms
332 );
333 }
334
335 #[test]
336 fn test_opus_decoder_handles_mono_packet_gracefully() {
337 let mut mono_enc = OpusEncoder::new(48000, 1);
339 let pcm = make_mono_pcm_20ms();
340 let mono_pkt = mono_enc.encode(&pcm);
341 assert!(!mono_pkt.is_empty());
342 assert!(
344 mono_pkt[0] & 0x04 == 0,
345 "mono encoder should produce mono packet"
346 );
347
348 let mut dec = OpusDecoder::new_default();
350 let decoded = dec.decode(&mono_pkt);
351 assert_eq!(
352 decoded.len(),
353 960,
354 "first mono packet should produce exactly 960 mono samples, got {}",
355 decoded.len()
356 );
357
358 let decoded2 = dec.decode(&mono_pkt);
360 assert_eq!(
361 decoded2.len(),
362 960,
363 "second mono packet should also produce 960 mono samples, got {}",
364 decoded2.len()
365 );
366 }
367
368 #[test]
369 fn test_opus_stereo_packet_downmix_produces_960() {
370 let mut enc = OpusEncoder::new_default();
371 let pcm = make_mono_pcm_20ms();
372 let stereo_pkt = enc.encode(&pcm);
373 assert!(stereo_pkt[0] & 0x04 != 0);
374
375 let mut dec = OpusDecoder::new_default();
376 let decoded = dec.decode(&stereo_pkt);
377 assert_eq!(
378 decoded.len(),
379 960,
380 "stereo packet should downmix to 960 mono samples"
381 );
382 }
383}