lavende_core/audio/
codec.rs1pub mod opus_decoder {
2 use crate::audio::constants::MAX_OPUS_FRAME_SIZE;
3 use audiopus::{
4 Channels, MutSignals, SampleRate, coder::Decoder as OpusDecoder, packet::Packet,
5 };
6 use symphonia::core::{
7 audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef, Layout, Signal, SignalSpec},
8 codecs::{
9 CODEC_TYPE_OPUS, CodecDescriptor, CodecParameters, Decoder, DecoderOptions,
10 FinalizeResult,
11 },
12 errors::{Error, Result},
13 formats::Packet as SymphPacket,
14 units::Duration,
15 };
16 pub struct OpusCodecDecoder {
17 params: CodecParameters,
18 channels: usize,
19 decoder: OpusDecoder,
20 buf: AudioBuffer<i16>,
21 pcm: Vec<i16>,
22 }
23 unsafe impl Sync for OpusCodecDecoder {}
24 #[inline]
25 fn opus_channels(n: usize) -> Channels {
26 if n == 1 {
27 Channels::Mono
28 } else {
29 Channels::Stereo
30 }
31 }
32 #[inline]
33 fn opus_layout(n: usize) -> Layout {
34 if n == 1 { Layout::Mono } else { Layout::Stereo }
35 }
36 impl Decoder for OpusCodecDecoder {
37 fn try_new(params: &CodecParameters, _options: &DecoderOptions) -> Result<Self> {
38 if params.codec != CODEC_TYPE_OPUS {
39 return Err(Error::Unsupported("not an opus stream"));
40 }
41 let sample_rate = params.sample_rate.unwrap_or(48000);
42 let channels = params.channels.map(|c| c.count()).unwrap_or(2).clamp(1, 2);
43 let opus_rate = match sample_rate {
44 8000 => SampleRate::Hz8000,
45 12000 => SampleRate::Hz12000,
46 16000 => SampleRate::Hz16000,
47 24000 => SampleRate::Hz24000,
48 _ => SampleRate::Hz48000,
49 };
50 let decoder = OpusDecoder::new(opus_rate, opus_channels(channels))
51 .map_err(|e| Error::IoError(std::io::Error::other(e)))?;
52 let spec = SignalSpec::new_with_layout(sample_rate, opus_layout(channels));
53 let buf = AudioBuffer::<i16>::new(MAX_OPUS_FRAME_SIZE as Duration, spec);
54 let pcm = vec![0i16; MAX_OPUS_FRAME_SIZE * channels];
55 Ok(Self {
56 params: params.clone(),
57 channels,
58 decoder,
59 buf,
60 pcm,
61 })
62 }
63 fn supported_codecs() -> &'static [CodecDescriptor] {
64 &[CodecDescriptor {
65 codec: CODEC_TYPE_OPUS,
66 short_name: "opus",
67 long_name: "Opus (via audiopus)",
68 inst_func: |params, opts| Ok(Box::new(OpusCodecDecoder::try_new(params, opts)?)),
69 }]
70 }
71 fn reset(&mut self) {
72 match OpusDecoder::new(SampleRate::Hz48000, opus_channels(self.channels)) {
73 Ok(dec) => self.decoder = dec,
74 Err(e) => tracing::warn!("opus decoder reset failed: {e}"),
75 }
76 }
77 fn codec_params(&self) -> &CodecParameters {
78 &self.params
79 }
80 fn decode(&mut self, packet: &SymphPacket) -> Result<AudioBufferRef<'_>> {
81 let n = self
82 .decoder
83 .decode(
84 Packet::try_from(packet.data.as_ref()).ok(),
85 MutSignals::try_from(self.pcm.as_mut_slice())
86 .map_err(|e| Error::IoError(std::io::Error::other(e)))?,
87 false,
88 )
89 .map_err(|e| Error::IoError(std::io::Error::other(e)))?;
90 self.buf.clear();
91 self.buf.render_reserved(Some(n));
92 let ch = self.channels;
93 if ch == 1 {
94 let plane = self.buf.chan_mut(0);
95 plane.copy_from_slice(&self.pcm[..n]);
96 } else {
97 let left = self.buf.chan_mut(0);
98 for (i, chunk) in self.pcm[..n * 2].chunks_exact(2).enumerate() {
99 left[i] = chunk[0];
100 }
101 let right = self.buf.chan_mut(1);
102 for (i, chunk) in self.pcm[..n * 2].chunks_exact(2).enumerate() {
103 right[i] = chunk[1];
104 }
105 }
106 Ok(self.buf.as_audio_buffer_ref())
107 }
108 fn finalize(&mut self) -> FinalizeResult {
109 FinalizeResult::default()
110 }
111 fn last_decoded(&self) -> AudioBufferRef<'_> {
112 self.buf.as_audio_buffer_ref()
113 }
114 }
115}
116pub mod opus_encoder {
117 use audiopus::{Application, Channels, SampleRate, coder::Encoder as OpusEncoder};
118 pub struct OpusCodecEncoder {
119 encoder: OpusEncoder,
120 }
121 impl OpusCodecEncoder {
122 pub fn new(quality: u8) -> Result<Self, audiopus::Error> {
123 let mut encoder =
124 OpusEncoder::new(SampleRate::Hz48000, Channels::Stereo, Application::Audio)?;
125 encoder.set_complexity(quality)?;
126 Ok(Self { encoder })
127 }
128 pub fn encode(&mut self, pcm: &[i16], out: &mut [u8]) -> Result<usize, audiopus::Error> {
129 self.encoder.encode(pcm, out)
130 }
131 }
132}
133pub use opus_decoder::OpusCodecDecoder;
134use symphonia::core::codecs::CodecRegistry;
135pub fn register_codecs(registry: &mut CodecRegistry) {
136 registry.register_all::<OpusCodecDecoder>();
137}