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
25pub struct OpusDecoder {
27 decoder: NonNull<OpusDecoderRaw>,
28 sample_rate: u32,
29 channels: u16,
30}
31
32impl OpusDecoder {
33 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 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 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
144pub struct OpusEncoder {
146 encoder: NonNull<OpusEncoderRaw>,
147 sample_rate: u32,
148 channels: u16,
149}
150
151impl OpusEncoder {
152 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 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}