1use crate::bindings::{
4 OPUS_BITRATE_MAX, OPUS_GET_BITRATE_REQUEST, OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST,
5 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST,
6 OPUS_SET_BITRATE_REQUEST, OpusProjectionDecoder, OpusProjectionEncoder,
7 opus_projection_ambisonics_encoder_create, opus_projection_decode,
8 opus_projection_decode_float, opus_projection_decoder_create, opus_projection_decoder_destroy,
9 opus_projection_encode, opus_projection_encode_float, opus_projection_encoder_ctl,
10 opus_projection_encoder_destroy,
11};
12use crate::constants::max_frame_samples_for;
13use crate::error::{Error, Result};
14use crate::types::{Application, Bitrate, SampleRate};
15
16pub struct ProjectionEncoder {
18 raw: *mut OpusProjectionEncoder,
19 sample_rate: SampleRate,
20 channels: u8,
21 streams: u8,
22 coupled_streams: u8,
23}
24
25unsafe impl Send for ProjectionEncoder {}
26unsafe impl Sync for ProjectionEncoder {}
27
28impl ProjectionEncoder {
29 pub fn new(
38 sample_rate: SampleRate,
39 channels: u8,
40 mapping_family: i32,
41 application: Application,
42 ) -> Result<Self> {
43 let mut err = 0i32;
44 let mut streams = 0i32;
45 let mut coupled = 0i32;
46 let enc = unsafe {
47 opus_projection_ambisonics_encoder_create(
48 sample_rate as i32,
49 i32::from(channels),
50 mapping_family,
51 &raw mut streams,
52 &raw mut coupled,
53 application as i32,
54 &raw mut err,
55 )
56 };
57 if err != 0 {
58 return Err(Error::from_code(err));
59 }
60 if enc.is_null() {
61 return Err(Error::AllocFail);
62 }
63 Ok(Self {
64 raw: enc,
65 sample_rate,
66 channels,
67 streams: u8::try_from(streams).map_err(|_| Error::BadArg)?,
68 coupled_streams: u8::try_from(coupled).map_err(|_| Error::BadArg)?,
69 })
70 }
71
72 fn validate_frame_size(&self, frame_size_per_ch: usize) -> Result<i32> {
73 if frame_size_per_ch == 0 || frame_size_per_ch > max_frame_samples_for(self.sample_rate) {
74 return Err(Error::BadArg);
75 }
76 i32::try_from(frame_size_per_ch).map_err(|_| Error::BadArg)
77 }
78
79 fn ensure_pcm_layout(&self, len: usize, frame_size_per_ch: usize) -> Result<()> {
80 if len != frame_size_per_ch * self.channels as usize {
81 return Err(Error::BadArg);
82 }
83 Ok(())
84 }
85
86 pub fn encode(
93 &mut self,
94 pcm: &[i16],
95 frame_size_per_ch: usize,
96 out: &mut [u8],
97 ) -> Result<usize> {
98 if self.raw.is_null() {
99 return Err(Error::InvalidState);
100 }
101 if out.is_empty() || out.len() > i32::MAX as usize {
102 return Err(Error::BadArg);
103 }
104 self.ensure_pcm_layout(pcm.len(), frame_size_per_ch)?;
105 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
106 let out_len = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
107 let n = unsafe {
108 opus_projection_encode(
109 self.raw,
110 pcm.as_ptr(),
111 frame_size,
112 out.as_mut_ptr(),
113 out_len,
114 )
115 };
116 if n < 0 {
117 return Err(Error::from_code(n));
118 }
119 usize::try_from(n).map_err(|_| Error::InternalError)
120 }
121
122 pub fn encode_float(
129 &mut self,
130 pcm: &[f32],
131 frame_size_per_ch: usize,
132 out: &mut [u8],
133 ) -> Result<usize> {
134 if self.raw.is_null() {
135 return Err(Error::InvalidState);
136 }
137 if out.is_empty() || out.len() > i32::MAX as usize {
138 return Err(Error::BadArg);
139 }
140 self.ensure_pcm_layout(pcm.len(), frame_size_per_ch)?;
141 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
142 let out_len = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
143 let n = unsafe {
144 opus_projection_encode_float(
145 self.raw,
146 pcm.as_ptr(),
147 frame_size,
148 out.as_mut_ptr(),
149 out_len,
150 )
151 };
152 if n < 0 {
153 return Err(Error::from_code(n));
154 }
155 usize::try_from(n).map_err(|_| Error::InternalError)
156 }
157
158 pub fn set_bitrate(&mut self, bitrate: Bitrate) -> Result<()> {
163 self.simple_ctl(OPUS_SET_BITRATE_REQUEST as i32, bitrate.value())
164 }
165
166 pub fn bitrate(&mut self) -> Result<Bitrate> {
171 let v = self.get_int_ctl(OPUS_GET_BITRATE_REQUEST as i32)?;
172 Ok(match v {
173 x if x == crate::bindings::OPUS_AUTO => Bitrate::Auto,
174 x if x == OPUS_BITRATE_MAX => Bitrate::Max,
175 other => Bitrate::Custom(other),
176 })
177 }
178
179 pub fn demixing_matrix_size(&mut self) -> Result<i32> {
184 self.get_int_ctl(OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST as i32)
185 }
186
187 pub fn demixing_matrix_gain(&mut self) -> Result<i32> {
192 self.get_int_ctl(OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST as i32)
193 }
194
195 pub fn write_demixing_matrix(&mut self, out: &mut [u8]) -> Result<usize> {
202 let size = self.demixing_matrix_size()?;
203 if size <= 0 {
204 return Err(Error::InternalError);
205 }
206 let needed = usize::try_from(size).map_err(|_| Error::InternalError)?;
207 if out.len() < needed {
208 return Err(Error::BufferTooSmall);
209 }
210 let r = unsafe {
211 opus_projection_encoder_ctl(
212 self.raw,
213 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST as i32,
214 out.as_mut_ptr(),
215 size,
216 )
217 };
218 if r != 0 {
219 return Err(Error::from_code(r));
220 }
221 Ok(needed)
222 }
223
224 pub fn demixing_matrix_bytes(&mut self) -> Result<Vec<u8>> {
230 let size = self.demixing_matrix_size()?;
231 let len = usize::try_from(size).map_err(|_| Error::InternalError)?;
232 let mut buf = vec![0u8; len];
233 self.write_demixing_matrix(&mut buf)?;
234 Ok(buf)
235 }
236
237 #[must_use]
239 pub const fn streams(&self) -> u8 {
240 self.streams
241 }
242
243 #[must_use]
245 pub const fn coupled_streams(&self) -> u8 {
246 self.coupled_streams
247 }
248
249 #[must_use]
251 pub const fn channels(&self) -> u8 {
252 self.channels
253 }
254
255 #[must_use]
257 pub const fn sample_rate(&self) -> SampleRate {
258 self.sample_rate
259 }
260
261 fn simple_ctl(&mut self, req: i32, val: i32) -> Result<()> {
262 if self.raw.is_null() {
263 return Err(Error::InvalidState);
264 }
265 let r = unsafe { opus_projection_encoder_ctl(self.raw, req, val) };
266 if r != 0 {
267 return Err(Error::from_code(r));
268 }
269 Ok(())
270 }
271
272 fn get_int_ctl(&mut self, req: i32) -> Result<i32> {
273 if self.raw.is_null() {
274 return Err(Error::InvalidState);
275 }
276 let mut v = 0i32;
277 let r = unsafe { opus_projection_encoder_ctl(self.raw, req, &mut v) };
278 if r != 0 {
279 return Err(Error::from_code(r));
280 }
281 Ok(v)
282 }
283}
284
285impl Drop for ProjectionEncoder {
286 fn drop(&mut self) {
287 if !self.raw.is_null() {
288 unsafe { opus_projection_encoder_destroy(self.raw) };
289 }
290 }
291}
292
293pub struct ProjectionDecoder {
295 raw: *mut OpusProjectionDecoder,
296 sample_rate: SampleRate,
297 channels: u8,
298 streams: u8,
299 coupled_streams: u8,
300}
301
302unsafe impl Send for ProjectionDecoder {}
303unsafe impl Sync for ProjectionDecoder {}
304
305impl ProjectionDecoder {
306 pub fn new(
312 sample_rate: SampleRate,
313 channels: u8,
314 streams: u8,
315 coupled_streams: u8,
316 demixing_matrix: &[u8],
317 ) -> Result<Self> {
318 if demixing_matrix.is_empty() {
319 return Err(Error::BadArg);
320 }
321 let matrix_len = i32::try_from(demixing_matrix.len()).map_err(|_| Error::BadArg)?;
322 let mut err = 0i32;
323 let dec = unsafe {
324 opus_projection_decoder_create(
325 sample_rate as i32,
326 i32::from(channels),
327 i32::from(streams),
328 i32::from(coupled_streams),
329 demixing_matrix.as_ptr().cast_mut(),
330 matrix_len,
331 &raw mut err,
332 )
333 };
334 if err != 0 {
335 return Err(Error::from_code(err));
336 }
337 if dec.is_null() {
338 return Err(Error::AllocFail);
339 }
340 Ok(Self {
341 raw: dec,
342 sample_rate,
343 channels,
344 streams,
345 coupled_streams,
346 })
347 }
348
349 fn validate_frame_size(&self, frame_size_per_ch: usize) -> Result<i32> {
350 if frame_size_per_ch == 0 || frame_size_per_ch > max_frame_samples_for(self.sample_rate) {
351 return Err(Error::BadArg);
352 }
353 i32::try_from(frame_size_per_ch).map_err(|_| Error::BadArg)
354 }
355
356 fn ensure_output_layout(&self, len: usize, frame_size_per_ch: usize) -> Result<()> {
357 if len != frame_size_per_ch * self.channels as usize {
358 return Err(Error::BadArg);
359 }
360 Ok(())
361 }
362
363 pub fn decode(
370 &mut self,
371 packet: &[u8],
372 out: &mut [i16],
373 frame_size_per_ch: usize,
374 fec: bool,
375 ) -> Result<usize> {
376 if self.raw.is_null() {
377 return Err(Error::InvalidState);
378 }
379 self.ensure_output_layout(out.len(), frame_size_per_ch)?;
380 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
381 let packet_len = if packet.is_empty() {
382 0
383 } else {
384 i32::try_from(packet.len()).map_err(|_| Error::BadArg)?
385 };
386 let n = unsafe {
387 opus_projection_decode(
388 self.raw,
389 if packet.is_empty() {
390 std::ptr::null()
391 } else {
392 packet.as_ptr()
393 },
394 packet_len,
395 out.as_mut_ptr(),
396 frame_size,
397 i32::from(fec),
398 )
399 };
400 if n < 0 {
401 return Err(Error::from_code(n));
402 }
403 usize::try_from(n).map_err(|_| Error::InternalError)
404 }
405
406 pub fn decode_float(
413 &mut self,
414 packet: &[u8],
415 out: &mut [f32],
416 frame_size_per_ch: usize,
417 fec: bool,
418 ) -> Result<usize> {
419 if self.raw.is_null() {
420 return Err(Error::InvalidState);
421 }
422 self.ensure_output_layout(out.len(), frame_size_per_ch)?;
423 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
424 let packet_len = if packet.is_empty() {
425 0
426 } else {
427 i32::try_from(packet.len()).map_err(|_| Error::BadArg)?
428 };
429 let n = unsafe {
430 opus_projection_decode_float(
431 self.raw,
432 if packet.is_empty() {
433 std::ptr::null()
434 } else {
435 packet.as_ptr()
436 },
437 packet_len,
438 out.as_mut_ptr(),
439 frame_size,
440 i32::from(fec),
441 )
442 };
443 if n < 0 {
444 return Err(Error::from_code(n));
445 }
446 usize::try_from(n).map_err(|_| Error::InternalError)
447 }
448
449 #[must_use]
451 pub const fn channels(&self) -> u8 {
452 self.channels
453 }
454
455 #[must_use]
457 pub const fn streams(&self) -> u8 {
458 self.streams
459 }
460
461 #[must_use]
463 pub const fn coupled_streams(&self) -> u8 {
464 self.coupled_streams
465 }
466
467 #[must_use]
469 pub const fn sample_rate(&self) -> SampleRate {
470 self.sample_rate
471 }
472}
473
474impl Drop for ProjectionDecoder {
475 fn drop(&mut self) {
476 if !self.raw.is_null() {
477 unsafe { opus_projection_decoder_destroy(self.raw) };
478 }
479 }
480}