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 Self::new(48000, 2)
71 }
72}
73
74impl Drop for OpusDecoder {
75 fn drop(&mut self) {
76 unsafe {
77 opus_decoder_destroy(self.decoder.as_ptr());
78 }
79 }
80}
81
82unsafe impl Send for OpusDecoder {}
83unsafe impl Sync for OpusDecoder {}
84
85impl Decoder for OpusDecoder {
86 fn decode(&mut self, data: &[u8]) -> PcmBuf {
87 let channels = usize::from(self.channels);
88 if channels == 0 {
89 return Vec::new();
90 }
91
92 let max_samples = 11520;
94 let mut output = vec![0i16; max_samples];
95 let frame_size = (max_samples / channels) as c_int;
96
97 let data_ptr = if data.is_empty() {
98 std::ptr::null()
99 } else {
100 data.as_ptr()
101 };
102
103 let len = unsafe {
104 opus_decode(
105 self.decoder.as_ptr(),
106 data_ptr.cast(),
107 data.len() as c_int,
108 output.as_mut_ptr().cast(),
109 frame_size,
110 0,
111 )
112 };
113
114 if len < 0 {
115 return Vec::new();
116 }
117
118 let total_samples = (len as usize) * channels;
119 output.truncate(total_samples);
120
121 if channels == 2 {
122 output = output
123 .chunks_exact(2)
124 .map(|chunk| ((chunk[0] as i32 + chunk[1] as i32) / 2) as i16)
125 .collect();
126 }
127
128 output
129 }
130
131 fn sample_rate(&self) -> u32 {
132 self.sample_rate
133 }
134
135 fn channels(&self) -> u16 {
136 self.channels
137 }
138}
139
140pub struct OpusEncoder {
142 encoder: NonNull<OpusEncoderRaw>,
143 sample_rate: u32,
144 channels: u16,
145}
146
147impl OpusEncoder {
148 pub fn new(sample_rate: u32, channels: u16) -> Self {
150 let channel_count: c_int = if channels == 1 { 1 } else { 2 };
151 let mut error: c_int = 0;
152 let ptr = unsafe {
153 opus_encoder_create(
154 sample_rate as c_int,
155 channel_count,
156 OPUS_APPLICATION_VOIP,
157 &mut error as *mut c_int,
158 )
159 };
160
161 if error != OPUS_OK {
162 unsafe {
163 if !ptr.is_null() {
164 opus_encoder_destroy(ptr);
165 }
166 }
167 panic!(
168 "Failed to create Opus encoder: {}",
169 opus_error_message(error)
170 );
171 }
172
173 let encoder = NonNull::new(ptr).unwrap_or_else(|| {
174 panic!("Failed to create Opus encoder: null pointer returned");
175 });
176
177 Self {
178 encoder,
179 sample_rate,
180 channels: if channel_count == 1 { 1 } else { 2 },
181 }
182 }
183
184 pub fn new_default() -> Self {
186 Self::new(48000, 2)
187 }
188
189 fn encode_raw(&mut self, samples: &[Sample]) -> Vec<u8> {
190 let channels = usize::from(self.channels);
191 if samples.is_empty() || channels == 0 || samples.len() % channels != 0 {
192 return Vec::new();
193 }
194
195 let frame_size = (samples.len() / channels) as c_int;
196 let mut output = vec![0u8; samples.len()];
197 let len = unsafe {
198 opus_encode(
199 self.encoder.as_ptr(),
200 samples.as_ptr().cast(),
201 frame_size,
202 output.as_mut_ptr(),
203 output.len() as c_int,
204 )
205 };
206
207 if len < 0 {
208 Vec::new()
209 } else {
210 output.truncate(len as usize);
211 output
212 }
213 }
214}
215
216impl Drop for OpusEncoder {
217 fn drop(&mut self) {
218 unsafe {
219 opus_encoder_destroy(self.encoder.as_ptr());
220 }
221 }
222}
223
224unsafe impl Send for OpusEncoder {}
225unsafe impl Sync for OpusEncoder {}
226
227impl Encoder for OpusEncoder {
228 fn encode(&mut self, samples: &[Sample]) -> Vec<u8> {
229 if self.channels == 2 {
230 let mut stereo_samples = Vec::with_capacity(samples.len() * 2);
231 for &sample in samples {
232 stereo_samples.push(sample);
233 stereo_samples.push(sample);
234 }
235 return self.encode_raw(&stereo_samples);
236 }
237
238 self.encode_raw(samples)
239 }
240
241 fn sample_rate(&self) -> u32 {
242 self.sample_rate
243 }
244
245 fn channels(&self) -> u16 {
246 self.channels
247 }
248}