audio_codec/
opus.rs

1use super::{Decoder, Encoder, PcmBuf, Sample};
2
3use opusic_sys::{
4    OPUS_APPLICATION_VOIP, OPUS_OK, OpusDecoder as OpusDecoderRaw, OpusEncoder as OpusEncoderRaw,
5    opus_decode, opus_decoder_create, opus_decoder_destroy, opus_encode, opus_encoder_create,
6    opus_encoder_destroy, opus_strerror,
7};
8use std::{ffi::CStr, os::raw::c_int, ptr::NonNull};
9
10fn opus_error_message(code: c_int) -> String {
11    if code == OPUS_OK {
12        return "ok".to_string();
13    }
14
15    unsafe {
16        let ptr = opus_strerror(code);
17        if ptr.is_null() {
18            format!("error code {code}")
19        } else {
20            CStr::from_ptr(ptr).to_string_lossy().into_owned()
21        }
22    }
23}
24
25/// Opus audio decoder backed by opusic-sys
26pub struct OpusDecoder {
27    decoder: NonNull<OpusDecoderRaw>,
28    sample_rate: u32,
29    channels: u16,
30}
31
32impl OpusDecoder {
33    /// Create a new Opus decoder instance
34    pub fn new(sample_rate: u32, channels: u16) -> Self {
35        let channel_count: c_int = if channels == 1 { 1 } else { 2 };
36        let mut error: c_int = 0;
37        let ptr = unsafe {
38            opus_decoder_create(
39                sample_rate as c_int,
40                channel_count,
41                &mut error as *mut c_int,
42            )
43        };
44
45        if error != OPUS_OK {
46            unsafe {
47                if !ptr.is_null() {
48                    opus_decoder_destroy(ptr);
49                }
50            }
51            panic!(
52                "Failed to create Opus decoder: {}",
53                opus_error_message(error)
54            );
55        }
56
57        let decoder = NonNull::new(ptr).unwrap_or_else(|| {
58            panic!("Failed to create Opus decoder: null pointer returned");
59        });
60
61        Self {
62            decoder,
63            sample_rate,
64            channels: if channel_count == 1 { 1 } else { 2 },
65        }
66    }
67
68    /// Create a default Opus decoder (48kHz, stereo)
69    pub fn new_default() -> Self {
70        #[cfg(feature = "opus_mono")]
71        {
72            return Self::new(48000, 1);
73        }
74        Self::new(48000, 2)
75    }
76}
77
78impl Drop for OpusDecoder {
79    fn drop(&mut self) {
80        unsafe {
81            opus_decoder_destroy(self.decoder.as_ptr());
82        }
83    }
84}
85
86unsafe impl Send for OpusDecoder {}
87unsafe impl Sync for OpusDecoder {}
88
89impl Decoder for OpusDecoder {
90    fn decode(&mut self, data: &[u8]) -> PcmBuf {
91        let channels = usize::from(self.channels);
92        if channels == 0 {
93            return Vec::new();
94        }
95
96        // Allow up to 120ms of audio as before: 48kHz * 0.12s * 2 channels = 11520 samples
97        let max_samples = 11520;
98        let mut output = vec![0i16; max_samples];
99        let frame_size = (max_samples / channels) as c_int;
100
101        let data_ptr = if data.is_empty() {
102            std::ptr::null()
103        } else {
104            data.as_ptr()
105        };
106
107        let len = unsafe {
108            opus_decode(
109                self.decoder.as_ptr(),
110                data_ptr.cast(),
111                data.len() as c_int,
112                output.as_mut_ptr().cast(),
113                frame_size,
114                0,
115            )
116        };
117
118        if len < 0 {
119            return Vec::new();
120        }
121
122        let total_samples = (len as usize) * channels;
123        output.truncate(total_samples);
124
125        if channels == 2 {
126            output = output
127                .chunks_exact(2)
128                .map(|chunk| ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16)
129                .collect();
130        }
131
132        output
133    }
134
135    fn sample_rate(&self) -> u32 {
136        self.sample_rate
137    }
138
139    fn channels(&self) -> u16 {
140        self.channels
141    }
142}
143
144/// Opus audio encoder backed by opusic-sys
145pub struct OpusEncoder {
146    encoder: NonNull<OpusEncoderRaw>,
147    sample_rate: u32,
148    channels: u16,
149}
150
151impl OpusEncoder {
152    /// Create a new Opus encoder instance
153    pub fn new(sample_rate: u32, channels: u16) -> Self {
154        let channel_count: c_int = if channels == 1 { 1 } else { 2 };
155        let mut error: c_int = 0;
156        let ptr = unsafe {
157            opus_encoder_create(
158                sample_rate as c_int,
159                channel_count,
160                OPUS_APPLICATION_VOIP,
161                &mut error as *mut c_int,
162            )
163        };
164
165        if error != OPUS_OK {
166            unsafe {
167                if !ptr.is_null() {
168                    opus_encoder_destroy(ptr);
169                }
170            }
171            panic!(
172                "Failed to create Opus encoder: {}",
173                opus_error_message(error)
174            );
175        }
176
177        let encoder = NonNull::new(ptr).unwrap_or_else(|| {
178            panic!("Failed to create Opus encoder: null pointer returned");
179        });
180
181        Self {
182            encoder,
183            sample_rate,
184            channels: if channel_count == 1 { 1 } else { 2 },
185        }
186    }
187
188    /// Create a default Opus encoder (48kHz, stereo)
189    pub fn new_default() -> Self {
190        #[cfg(feature = "opus_mono")]
191        {
192            return Self::new(48000, 1);
193        }
194        Self::new(48000, 2)
195    }
196
197    fn encode_raw(&mut self, samples: &[Sample]) -> Vec<u8> {
198        let channels = usize::from(self.channels);
199        if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
200            return Vec::new();
201        }
202
203        let frame_size = (samples.len() / channels) as c_int;
204        let mut output = vec![0u8; samples.len()];
205        let len = unsafe {
206            opus_encode(
207                self.encoder.as_ptr(),
208                samples.as_ptr().cast(),
209                frame_size,
210                output.as_mut_ptr(),
211                output.len() as c_int,
212            )
213        };
214
215        if len < 0 {
216            Vec::new()
217        } else {
218            output.truncate(len as usize);
219            output
220        }
221    }
222}
223
224impl Drop for OpusEncoder {
225    fn drop(&mut self) {
226        unsafe {
227            opus_encoder_destroy(self.encoder.as_ptr());
228        }
229    }
230}
231
232unsafe impl Send for OpusEncoder {}
233unsafe impl Sync for OpusEncoder {}
234
235impl Encoder for OpusEncoder {
236    fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
237        if self.channels == 2 {
238            let mut stereo_samples = Vec::with_capacity(samples.len() * 2);
239            for &sample in samples {
240                stereo_samples.push(sample);
241                stereo_samples.push(sample);
242            }
243            return self.encode_raw(&stereo_samples);
244        }
245
246        self.encode_raw(samples)
247    }
248
249    fn sample_rate(&self) -> u32 {
250        self.sample_rate
251    }
252
253    fn channels(&self) -> u16 {
254        self.channels
255    }
256}