skua_voice/input/codecs/
opus.rs1use crate::constants::*;
2use audiopus::{
3 coder::{Decoder as AudiopusDecoder, GenericCtl},
4 Channels,
5 Error as OpusError,
6 ErrorCode,
7};
8use symphonia_core::{
9 audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef, Layout, Signal, SignalSpec},
10 codecs::{
11 CodecDescriptor,
12 CodecParameters,
13 Decoder,
14 DecoderOptions,
15 FinalizeResult,
16 CODEC_TYPE_OPUS,
17 },
18 errors::{decode_error, Result as SymphResult},
19 formats::Packet,
20};
21
22pub struct OpusDecoder {
24 inner: AudiopusDecoder,
25 params: CodecParameters,
26 buf: AudioBuffer<f32>,
27 rawbuf: Vec<f32>,
28}
29
30unsafe impl Sync for OpusDecoder {}
38
39impl OpusDecoder {
40 fn decode_inner(&mut self, packet: &Packet) -> SymphResult<()> {
41 let s_ct = loop {
42 let pkt = if packet.buf().is_empty() {
43 None
44 } else if let Ok(checked_pkt) = packet.buf().try_into() {
45 Some(checked_pkt)
46 } else {
47 return decode_error("Opus packet was too large (greater than i32::MAX bytes).");
48 };
49 let out_space = (&mut self.rawbuf[..]).try_into().expect("The following logic expands this buffer safely below i32::MAX, and we throw our own error.");
50
51 match self.inner.decode_float(pkt, out_space, false) {
52 Ok(v) => break v,
53 Err(OpusError::Opus(ErrorCode::BufferTooSmall)) => {
54 let new_size = (self.rawbuf.len() * 2).min(std::i32::MAX as usize);
57 if new_size == self.rawbuf.len() {
58 return decode_error("Opus frame too big: cannot expand opus frame decode buffer any further.");
59 }
60
61 self.rawbuf.resize(new_size, 0.0);
62 self.buf = AudioBuffer::new(
63 self.rawbuf.len() as u64 / 2,
64 SignalSpec::new_with_layout(SAMPLE_RATE_RAW as u32, Layout::Stereo),
65 );
66 },
67 Err(e) => {
68 tracing::error!("Opus decode error: {:?}", e);
69 return decode_error("Opus decode error: see 'tracing' logs.");
70 },
71 }
72 };
73
74 self.buf.clear();
75 self.buf.render_reserved(Some(s_ct));
76
77 for ch in 0..2 {
79 let iter = self.rawbuf.chunks_exact(2).map(|chunk| chunk[ch]);
80 for (tgt, src) in self.buf.chan_mut(ch).iter_mut().zip(iter) {
81 *tgt = src;
82 }
83 }
84
85 Ok(())
86 }
87}
88
89impl Decoder for OpusDecoder {
90 fn try_new(params: &CodecParameters, _options: &DecoderOptions) -> SymphResult<Self> {
91 let inner = AudiopusDecoder::new(SAMPLE_RATE, Channels::Stereo).unwrap();
92
93 let mut params = params.clone();
94 params.with_sample_rate(SAMPLE_RATE_RAW as u32);
95
96 Ok(Self {
97 inner,
98 params,
99 buf: AudioBuffer::new(
100 MONO_FRAME_SIZE as u64,
101 SignalSpec::new_with_layout(SAMPLE_RATE_RAW as u32, Layout::Stereo),
102 ),
103 rawbuf: vec![0.0f32; STEREO_FRAME_SIZE],
104 })
105 }
106
107 fn supported_codecs() -> &'static [CodecDescriptor] {
108 &[symphonia_core::support_codec!(
109 CODEC_TYPE_OPUS,
110 "opus",
111 "libopus (1.3+, audiopus)"
112 )]
113 }
114
115 fn codec_params(&self) -> &CodecParameters {
116 &self.params
117 }
118
119 fn decode(&mut self, packet: &Packet) -> SymphResult<AudioBufferRef<'_>> {
120 if let Err(e) = self.decode_inner(packet) {
121 self.buf.clear();
122 Err(e)
123 } else {
124 Ok(self.buf.as_audio_buffer_ref())
125 }
126 }
127
128 fn reset(&mut self) {
129 _ = self.inner.reset_state();
130 }
131
132 fn finalize(&mut self) -> FinalizeResult {
133 FinalizeResult::default()
134 }
135
136 fn last_decoded(&self) -> AudioBufferRef<'_> {
137 self.buf.as_audio_buffer_ref()
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use crate::{
144 constants::test_data::FILE_WEBM_TARGET,
145 input::{input_tests::*, File},
146 };
147
148 #[tokio::test]
151 #[ntest::timeout(10_000)]
152 async fn webm_track_plays() {
153 track_plays_passthrough(|| File::new(FILE_WEBM_TARGET)).await;
154 }
155
156 #[tokio::test]
157 #[ntest::timeout(10_000)]
158 async fn webm_forward_seek_correct() {
159 forward_seek_correct(|| File::new(FILE_WEBM_TARGET)).await;
160 }
161
162 #[tokio::test]
163 #[ntest::timeout(10_000)]
164 async fn webm_backward_seek_correct() {
165 backward_seek_correct(|| File::new(FILE_WEBM_TARGET)).await;
166 }
167}