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_ambisonics_encoder_get_size,
8 opus_projection_ambisonics_encoder_init, opus_projection_decode, opus_projection_decode_float,
9 opus_projection_decoder_create, opus_projection_decoder_destroy,
10 opus_projection_decoder_get_size, opus_projection_decoder_init, opus_projection_encode,
11 opus_projection_encode_float, opus_projection_encoder_ctl, opus_projection_encoder_destroy,
12};
13use crate::constants::{is_frame_size_2_5ms_aligned, max_frame_samples_for};
14use crate::error::{Error, Result};
15use crate::types::{Application, Bitrate, SampleRate};
16use crate::{AlignedBuffer, Ownership, RawHandle};
17use std::marker::PhantomData;
18use std::num::{NonZeroU8, NonZeroUsize};
19use std::ops::Deref;
20use std::ptr::NonNull;
21
22fn validate_channels(channels: u8) -> Result<()> {
23 NonZeroU8::new(channels).ok_or(Error::BadArg)?;
24 Ok(())
25}
26
27fn validate_projection_mapping_family(mapping_family: i32) -> Result<()> {
28 if mapping_family == 3 {
29 Ok(())
30 } else {
31 Err(Error::BadArg)
32 }
33}
34
35fn validate_stream_counts(streams: u8, coupled_streams: u8) -> Result<()> {
36 let streams = NonZeroU8::new(streams).ok_or(Error::BadArg)?;
37 if coupled_streams > streams.get() {
38 return Err(Error::BadArg);
39 }
40 if usize::from(streams.get()) + usize::from(coupled_streams) > u8::MAX as usize {
41 return Err(Error::BadArg);
42 }
43 Ok(())
44}
45
46pub struct ProjectionEncoder {
48 raw: RawHandle<OpusProjectionEncoder>,
49 sample_rate: SampleRate,
50 channels: u8,
51 streams: u8,
52 coupled_streams: u8,
53}
54
55unsafe impl Send for ProjectionEncoder {}
56
57pub struct ProjectionEncoderRef<'a> {
71 inner: ProjectionEncoder,
72 _marker: PhantomData<&'a mut OpusProjectionEncoder>,
73}
74
75unsafe impl Send for ProjectionEncoderRef<'_> {}
76
77impl ProjectionEncoder {
78 fn from_raw(
79 ptr: NonNull<OpusProjectionEncoder>,
80 sample_rate: SampleRate,
81 channels: u8,
82 streams: u8,
83 coupled_streams: u8,
84 ownership: Ownership,
85 ) -> Self {
86 Self {
87 raw: RawHandle::new(ptr, ownership, opus_projection_encoder_destroy),
88 sample_rate,
89 channels,
90 streams,
91 coupled_streams,
92 }
93 }
94
95 pub fn size(channels: u8, mapping_family: i32) -> Result<usize> {
100 validate_channels(channels)?;
101 validate_projection_mapping_family(mapping_family)?;
102 let raw = unsafe {
103 opus_projection_ambisonics_encoder_get_size(i32::from(channels), mapping_family)
104 };
105 if raw <= 0 {
106 return Err(Error::BadArg);
107 }
108 usize::try_from(raw).map_err(|_| Error::InternalError)
109 }
110
111 pub unsafe fn init_in_place(
120 ptr: *mut OpusProjectionEncoder,
121 sample_rate: SampleRate,
122 channels: u8,
123 mapping_family: i32,
124 application: Application,
125 ) -> Result<(u8, u8)> {
126 if ptr.is_null() || channels == 0 {
127 return Err(Error::BadArg);
128 }
129 if !crate::opus_ptr_is_aligned(ptr.cast()) {
130 return Err(Error::BadArg);
131 }
132 Self::size(channels, mapping_family)?;
133 let mut streams = 0i32;
134 let mut coupled = 0i32;
135 let r = unsafe {
136 opus_projection_ambisonics_encoder_init(
137 ptr,
138 sample_rate as i32,
139 i32::from(channels),
140 mapping_family,
141 std::ptr::addr_of_mut!(streams),
142 std::ptr::addr_of_mut!(coupled),
143 application as i32,
144 )
145 };
146 if r != 0 {
147 return Err(Error::from_code(r));
148 }
149 Ok((
150 u8::try_from(streams).map_err(|_| Error::BadArg)?,
151 u8::try_from(coupled).map_err(|_| Error::BadArg)?,
152 ))
153 }
154
155 pub fn new(
164 sample_rate: SampleRate,
165 channels: u8,
166 mapping_family: i32,
167 application: Application,
168 ) -> Result<Self> {
169 Self::size(channels, mapping_family)?;
170 let mut err = 0i32;
171 let mut streams = 0i32;
172 let mut coupled = 0i32;
173 let enc = unsafe {
174 opus_projection_ambisonics_encoder_create(
175 sample_rate as i32,
176 i32::from(channels),
177 mapping_family,
178 &raw mut streams,
179 &raw mut coupled,
180 application as i32,
181 &raw mut err,
182 )
183 };
184 if err != 0 {
185 return Err(Error::from_code(err));
186 }
187 let enc = NonNull::new(enc).ok_or(Error::AllocFail)?;
188 let streams_u8 = u8::try_from(streams).map_err(|_| Error::BadArg)?;
189 let coupled_u8 = u8::try_from(coupled).map_err(|_| Error::BadArg)?;
190 Ok(Self::from_raw(
191 enc,
192 sample_rate,
193 channels,
194 streams_u8,
195 coupled_u8,
196 Ownership::Owned,
197 ))
198 }
199
200 fn validate_frame_size(&self, frame_size_per_ch: usize) -> Result<i32> {
201 let frame_size = NonZeroUsize::new(frame_size_per_ch).ok_or(Error::BadArg)?;
202 if frame_size.get() > max_frame_samples_for(self.sample_rate) {
203 return Err(Error::BadArg);
204 }
205 i32::try_from(frame_size.get()).map_err(|_| Error::BadArg)
206 }
207
208 fn ensure_pcm_layout(&self, len: usize, frame_size_per_ch: usize) -> Result<()> {
209 let expected = frame_size_per_ch
210 .checked_mul(self.channels as usize)
211 .ok_or(Error::BadArg)?;
212 if len != expected {
213 return Err(Error::BadArg);
214 }
215 Ok(())
216 }
217
218 pub fn encode(
225 &mut self,
226 pcm: &[i16],
227 frame_size_per_ch: usize,
228 out: &mut [u8],
229 ) -> Result<usize> {
230 if out.is_empty() || out.len() > i32::MAX as usize {
231 return Err(Error::BadArg);
232 }
233 self.ensure_pcm_layout(pcm.len(), frame_size_per_ch)?;
234 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
235 let out_len = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
236 let n = unsafe {
237 opus_projection_encode(
238 self.raw.as_ptr(),
239 pcm.as_ptr(),
240 frame_size,
241 out.as_mut_ptr(),
242 out_len,
243 )
244 };
245 if n < 0 {
246 return Err(Error::from_code(n));
247 }
248 usize::try_from(n).map_err(|_| Error::InternalError)
249 }
250
251 pub fn encode_float(
258 &mut self,
259 pcm: &[f32],
260 frame_size_per_ch: usize,
261 out: &mut [u8],
262 ) -> Result<usize> {
263 if out.is_empty() || out.len() > i32::MAX as usize {
264 return Err(Error::BadArg);
265 }
266 self.ensure_pcm_layout(pcm.len(), frame_size_per_ch)?;
267 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
268 let out_len = i32::try_from(out.len()).map_err(|_| Error::BadArg)?;
269 let n = unsafe {
270 opus_projection_encode_float(
271 self.raw.as_ptr(),
272 pcm.as_ptr(),
273 frame_size,
274 out.as_mut_ptr(),
275 out_len,
276 )
277 };
278 if n < 0 {
279 return Err(Error::from_code(n));
280 }
281 usize::try_from(n).map_err(|_| Error::InternalError)
282 }
283
284 pub fn set_bitrate(&mut self, bitrate: Bitrate) -> Result<()> {
289 self.simple_ctl(OPUS_SET_BITRATE_REQUEST as i32, bitrate.value())
290 }
291
292 pub fn bitrate(&mut self) -> Result<Bitrate> {
297 let v = self.get_int_ctl(OPUS_GET_BITRATE_REQUEST as i32)?;
298 Ok(match v {
299 x if x == crate::bindings::OPUS_AUTO => Bitrate::Auto,
300 x if x == OPUS_BITRATE_MAX => Bitrate::Max,
301 other => Bitrate::Custom(other),
302 })
303 }
304
305 pub fn demixing_matrix_size(&mut self) -> Result<i32> {
310 self.get_int_ctl(OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST as i32)
311 }
312
313 pub fn demixing_matrix_gain(&mut self) -> Result<i32> {
318 self.get_int_ctl(OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST as i32)
319 }
320
321 pub fn write_demixing_matrix(&mut self, out: &mut [u8]) -> Result<usize> {
328 let size = self.demixing_matrix_size()?;
329 self.write_demixing_matrix_with_size(out, size)
330 }
331
332 fn write_demixing_matrix_with_size(&mut self, out: &mut [u8], size: i32) -> Result<usize> {
333 if size <= 0 {
334 return Err(Error::InternalError);
335 }
336 let needed = usize::try_from(size).map_err(|_| Error::InternalError)?;
337 if out.len() < needed {
338 return Err(Error::BufferTooSmall);
339 }
340 let r = unsafe {
341 opus_projection_encoder_ctl(
342 self.raw.as_ptr(),
343 OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST as i32,
344 out.as_mut_ptr(),
345 size,
346 )
347 };
348 if r != 0 {
349 return Err(Error::from_code(r));
350 }
351 Ok(needed)
352 }
353
354 pub fn demixing_matrix_bytes(&mut self) -> Result<Vec<u8>> {
360 let size = self.demixing_matrix_size()?;
361 let len = usize::try_from(size).map_err(|_| Error::InternalError)?;
362 let mut buf = vec![0u8; len];
363 self.write_demixing_matrix_with_size(&mut buf, size)?;
364 Ok(buf)
365 }
366
367 #[must_use]
369 pub const fn streams(&self) -> u8 {
370 self.streams
371 }
372
373 #[must_use]
375 pub const fn coupled_streams(&self) -> u8 {
376 self.coupled_streams
377 }
378
379 #[must_use]
381 pub const fn channels(&self) -> u8 {
382 self.channels
383 }
384
385 #[must_use]
387 pub const fn sample_rate(&self) -> SampleRate {
388 self.sample_rate
389 }
390
391 fn simple_ctl(&mut self, req: i32, val: i32) -> Result<()> {
392 let r = unsafe { opus_projection_encoder_ctl(self.raw.as_ptr(), req, val) };
393 if r != 0 {
394 return Err(Error::from_code(r));
395 }
396 Ok(())
397 }
398
399 fn get_int_ctl(&mut self, req: i32) -> Result<i32> {
400 let mut v = 0i32;
401 let r = unsafe { opus_projection_encoder_ctl(self.raw.as_ptr(), req, &mut v) };
402 if r != 0 {
403 return Err(Error::from_code(r));
404 }
405 Ok(v)
406 }
407}
408
409impl<'a> ProjectionEncoderRef<'a> {
410 #[must_use]
429 pub unsafe fn from_raw(
430 ptr: *mut OpusProjectionEncoder,
431 sample_rate: SampleRate,
432 channels: u8,
433 streams: u8,
434 coupled_streams: u8,
435 ) -> Self {
436 assert!(
437 validate_channels(channels).is_ok(),
438 "ProjectionEncoderRef::from_raw called with zero channels"
439 );
440 assert!(
441 validate_stream_counts(streams, coupled_streams).is_ok(),
442 "ProjectionEncoderRef::from_raw called with invalid stream counts"
443 );
444 let encoder = ProjectionEncoder::from_raw(
445 crate::checked_non_null(ptr, "ProjectionEncoderRef::from_raw"),
446 sample_rate,
447 channels,
448 streams,
449 coupled_streams,
450 Ownership::Borrowed,
451 );
452 Self {
453 inner: encoder,
454 _marker: PhantomData,
455 }
456 }
457
458 pub fn init_in(
463 buf: &'a mut AlignedBuffer,
464 sample_rate: SampleRate,
465 channels: u8,
466 mapping_family: i32,
467 application: Application,
468 ) -> Result<Self> {
469 let required = ProjectionEncoder::size(channels, mapping_family)?;
470 if buf.capacity_bytes() < required {
471 return Err(Error::BadArg);
472 }
473 let ptr = buf.as_mut_ptr::<OpusProjectionEncoder>();
474 let (streams, coupled) = unsafe {
475 ProjectionEncoder::init_in_place(
476 ptr,
477 sample_rate,
478 channels,
479 mapping_family,
480 application,
481 )?
482 };
483 Ok(unsafe { Self::from_raw(ptr, sample_rate, channels, streams, coupled) })
484 }
485
486 delegate_ref_mut_methods! {
487 fn encode(pcm: &[i16], frame_size_per_ch: usize, out: &mut [u8]) -> Result<usize>;
488 fn encode_float(pcm: &[f32], frame_size_per_ch: usize, out: &mut [u8]) -> Result<usize>;
489 fn set_bitrate(bitrate: Bitrate) -> Result<()>;
490 fn bitrate() -> Result<Bitrate>;
491 fn demixing_matrix_size() -> Result<i32>;
492 fn demixing_matrix_gain() -> Result<i32>;
493 fn write_demixing_matrix(out: &mut [u8]) -> Result<usize>;
494 fn demixing_matrix_bytes() -> Result<Vec<u8>>;
495 }
496}
497
498impl Deref for ProjectionEncoderRef<'_> {
499 type Target = ProjectionEncoder;
500
501 fn deref(&self) -> &Self::Target {
502 &self.inner
503 }
504}
505
506pub struct ProjectionDecoder {
508 raw: RawHandle<OpusProjectionDecoder>,
509 sample_rate: SampleRate,
510 channels: u8,
511 streams: u8,
512 coupled_streams: u8,
513}
514
515unsafe impl Send for ProjectionDecoder {}
516
517pub struct ProjectionDecoderRef<'a> {
531 inner: ProjectionDecoder,
532 _marker: PhantomData<&'a mut OpusProjectionDecoder>,
533}
534
535unsafe impl Send for ProjectionDecoderRef<'_> {}
536
537impl ProjectionDecoder {
538 fn from_raw(
539 ptr: NonNull<OpusProjectionDecoder>,
540 sample_rate: SampleRate,
541 channels: u8,
542 streams: u8,
543 coupled_streams: u8,
544 ownership: Ownership,
545 ) -> Self {
546 Self {
547 raw: RawHandle::new(ptr, ownership, opus_projection_decoder_destroy),
548 sample_rate,
549 channels,
550 streams,
551 coupled_streams,
552 }
553 }
554
555 pub fn size(channels: u8, streams: u8, coupled_streams: u8) -> Result<usize> {
560 validate_channels(channels)?;
561 validate_stream_counts(streams, coupled_streams)?;
562 let raw = unsafe {
563 opus_projection_decoder_get_size(
564 i32::from(channels),
565 i32::from(streams),
566 i32::from(coupled_streams),
567 )
568 };
569 if raw <= 0 {
570 return Err(Error::BadArg);
571 }
572 usize::try_from(raw).map_err(|_| Error::InternalError)
573 }
574
575 pub unsafe fn init_in_place(
584 ptr: *mut OpusProjectionDecoder,
585 sample_rate: SampleRate,
586 channels: u8,
587 streams: u8,
588 coupled_streams: u8,
589 demixing_matrix: &[u8],
590 ) -> Result<()> {
591 if ptr.is_null() || demixing_matrix.is_empty() {
592 return Err(Error::BadArg);
593 }
594 if !crate::opus_ptr_is_aligned(ptr.cast()) {
595 return Err(Error::BadArg);
596 }
597 Self::size(channels, streams, coupled_streams)?;
598 let matrix_len = i32::try_from(demixing_matrix.len()).map_err(|_| Error::BadArg)?;
599 let mut demixing_matrix = demixing_matrix.to_vec();
600 let r = unsafe {
605 opus_projection_decoder_init(
606 ptr,
607 sample_rate as i32,
608 i32::from(channels),
609 i32::from(streams),
610 i32::from(coupled_streams),
611 demixing_matrix.as_mut_ptr(),
612 matrix_len,
613 )
614 };
615 if r != 0 {
616 return Err(Error::from_code(r));
617 }
618 Ok(())
619 }
620
621 pub fn new(
627 sample_rate: SampleRate,
628 channels: u8,
629 streams: u8,
630 coupled_streams: u8,
631 demixing_matrix: &[u8],
632 ) -> Result<Self> {
633 if demixing_matrix.is_empty() {
634 return Err(Error::BadArg);
635 }
636 Self::size(channels, streams, coupled_streams)?;
637 let matrix_len = i32::try_from(demixing_matrix.len()).map_err(|_| Error::BadArg)?;
638 let mut demixing_matrix = demixing_matrix.to_vec();
639 let mut err = 0i32;
640 let dec = unsafe {
643 opus_projection_decoder_create(
644 sample_rate as i32,
645 i32::from(channels),
646 i32::from(streams),
647 i32::from(coupled_streams),
648 demixing_matrix.as_mut_ptr(),
649 matrix_len,
650 &raw mut err,
651 )
652 };
653 if err != 0 {
654 return Err(Error::from_code(err));
655 }
656 let dec = NonNull::new(dec).ok_or(Error::AllocFail)?;
657 Ok(Self::from_raw(
658 dec,
659 sample_rate,
660 channels,
661 streams,
662 coupled_streams,
663 Ownership::Owned,
664 ))
665 }
666
667 fn validate_frame_size(&self, frame_size_per_ch: usize) -> Result<i32> {
668 let frame_size = NonZeroUsize::new(frame_size_per_ch).ok_or(Error::BadArg)?;
669 if frame_size.get() > max_frame_samples_for(self.sample_rate) {
670 return Err(Error::BadArg);
671 }
672 i32::try_from(frame_size.get()).map_err(|_| Error::BadArg)
673 }
674
675 fn ensure_output_layout(&self, len: usize, frame_size_per_ch: usize) -> Result<()> {
676 let expected = frame_size_per_ch
677 .checked_mul(self.channels as usize)
678 .ok_or(Error::BadArg)?;
679 if len != expected {
680 return Err(Error::BadArg);
681 }
682 Ok(())
683 }
684
685 pub fn decode(
692 &mut self,
693 packet: &[u8],
694 out: &mut [i16],
695 frame_size_per_ch: usize,
696 fec: bool,
697 ) -> Result<usize> {
698 self.ensure_output_layout(out.len(), frame_size_per_ch)?;
699 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
700 if (packet.is_empty() || fec)
702 && !is_frame_size_2_5ms_aligned(frame_size_per_ch, self.sample_rate)
703 {
704 return Err(Error::BadArg);
705 }
706 let packet_len = if packet.is_empty() {
707 0
708 } else {
709 i32::try_from(packet.len()).map_err(|_| Error::BadArg)?
710 };
711 let n = unsafe {
712 opus_projection_decode(
713 self.raw.as_ptr(),
714 if packet.is_empty() {
715 std::ptr::null()
716 } else {
717 packet.as_ptr()
718 },
719 packet_len,
720 out.as_mut_ptr(),
721 frame_size,
722 i32::from(fec),
723 )
724 };
725 if n < 0 {
726 return Err(Error::from_code(n));
727 }
728 usize::try_from(n).map_err(|_| Error::InternalError)
729 }
730
731 pub fn decode_float(
738 &mut self,
739 packet: &[u8],
740 out: &mut [f32],
741 frame_size_per_ch: usize,
742 fec: bool,
743 ) -> Result<usize> {
744 self.ensure_output_layout(out.len(), frame_size_per_ch)?;
745 let frame_size = self.validate_frame_size(frame_size_per_ch)?;
746 if (packet.is_empty() || fec)
748 && !is_frame_size_2_5ms_aligned(frame_size_per_ch, self.sample_rate)
749 {
750 return Err(Error::BadArg);
751 }
752 let packet_len = if packet.is_empty() {
753 0
754 } else {
755 i32::try_from(packet.len()).map_err(|_| Error::BadArg)?
756 };
757 let n = unsafe {
758 opus_projection_decode_float(
759 self.raw.as_ptr(),
760 if packet.is_empty() {
761 std::ptr::null()
762 } else {
763 packet.as_ptr()
764 },
765 packet_len,
766 out.as_mut_ptr(),
767 frame_size,
768 i32::from(fec),
769 )
770 };
771 if n < 0 {
772 return Err(Error::from_code(n));
773 }
774 usize::try_from(n).map_err(|_| Error::InternalError)
775 }
776
777 #[must_use]
779 pub const fn channels(&self) -> u8 {
780 self.channels
781 }
782
783 #[must_use]
785 pub const fn streams(&self) -> u8 {
786 self.streams
787 }
788
789 #[must_use]
791 pub const fn coupled_streams(&self) -> u8 {
792 self.coupled_streams
793 }
794
795 #[must_use]
797 pub const fn sample_rate(&self) -> SampleRate {
798 self.sample_rate
799 }
800}
801
802impl<'a> ProjectionDecoderRef<'a> {
803 #[must_use]
822 pub unsafe fn from_raw(
823 ptr: *mut OpusProjectionDecoder,
824 sample_rate: SampleRate,
825 channels: u8,
826 streams: u8,
827 coupled_streams: u8,
828 ) -> Self {
829 assert!(
830 validate_channels(channels).is_ok(),
831 "ProjectionDecoderRef::from_raw called with zero channels"
832 );
833 assert!(
834 validate_stream_counts(streams, coupled_streams).is_ok(),
835 "ProjectionDecoderRef::from_raw called with invalid stream counts"
836 );
837 let decoder = ProjectionDecoder::from_raw(
838 crate::checked_non_null(ptr, "ProjectionDecoderRef::from_raw"),
839 sample_rate,
840 channels,
841 streams,
842 coupled_streams,
843 Ownership::Borrowed,
844 );
845 Self {
846 inner: decoder,
847 _marker: PhantomData,
848 }
849 }
850
851 pub fn init_in(
856 buf: &'a mut AlignedBuffer,
857 sample_rate: SampleRate,
858 channels: u8,
859 streams: u8,
860 coupled_streams: u8,
861 demixing_matrix: &[u8],
862 ) -> Result<Self> {
863 let required = ProjectionDecoder::size(channels, streams, coupled_streams)?;
864 if buf.capacity_bytes() < required {
865 return Err(Error::BadArg);
866 }
867 let ptr = buf.as_mut_ptr::<OpusProjectionDecoder>();
868 unsafe {
869 ProjectionDecoder::init_in_place(
870 ptr,
871 sample_rate,
872 channels,
873 streams,
874 coupled_streams,
875 demixing_matrix,
876 )?;
877 }
878 Ok(unsafe { Self::from_raw(ptr, sample_rate, channels, streams, coupled_streams) })
879 }
880
881 delegate_ref_mut_methods! {
882 fn decode(packet: &[u8], out: &mut [i16], frame_size_per_ch: usize, fec: bool) -> Result<usize>;
883 fn decode_float(packet: &[u8], out: &mut [f32], frame_size_per_ch: usize, fec: bool) -> Result<usize>;
884 }
885}
886
887impl Deref for ProjectionDecoderRef<'_> {
888 type Target = ProjectionDecoder;
889
890 fn deref(&self) -> &Self::Target {
891 &self.inner
892 }
893}