use symphonia::core::audio::GenericAudioBufferRef;
use symphonia::core::audio::{AsGenericAudioBufferRef, AudioBuffer, AudioMut, AudioSpec};
use symphonia::core::codecs::audio::well_known::CODEC_ID_OPUS;
use symphonia::core::codecs::audio::{
AudioCodecParameters, AudioDecoder, AudioDecoderOptions, FinalizeResult,
};
use symphonia::core::codecs::registry::{RegisterableAudioDecoder, SupportedAudioCodec};
use symphonia::core::codecs::CodecInfo;
use symphonia::core::errors::{decode_error, unsupported_error, Result};
use symphonia::core::packet::PacketRef;
const OPUS_RATE: u32 = 48_000;
const MAX_FRAME: usize = 5760;
fn pre_skip(extra_data: Option<&[u8]>) -> usize {
match extra_data {
Some(d) if d.len() >= 12 && d.starts_with(b"OpusHead") => {
u16::from_le_bytes([d[10], d[11]]) as usize
}
_ => 0,
}
}
struct SyncDecoder(opus::Decoder);
unsafe impl Sync for SyncDecoder {}
pub struct OpusDecoder {
inner: SyncDecoder,
params: AudioCodecParameters,
buf: AudioBuffer<f32>,
scratch: Vec<f32>,
channels: usize,
skip_left: usize,
}
impl OpusDecoder {
pub fn try_new(params: &AudioCodecParameters, _opts: &AudioDecoderOptions) -> Result<Self> {
let channels = match params.channels.as_ref() {
Some(ch) => ch.count(),
None => return unsupported_error("opus: channel layout is missing"),
};
if channels == 0 || channels > 2 {
return unsupported_error("opus: only mono and stereo are supported");
}
let layout = match channels {
1 => opus::Channels::Mono,
_ => opus::Channels::Stereo,
};
let inner = SyncDecoder(opus::Decoder::new(OPUS_RATE, layout).map_err(|_| {
symphonia::core::errors::Error::Unsupported("opus: decoder setup failed")
})?);
let spec = AudioSpec::new(OPUS_RATE, params.channels.clone().unwrap());
let mut params = params.clone();
params.sample_rate = Some(OPUS_RATE);
Ok(OpusDecoder {
inner,
buf: AudioBuffer::new(spec, MAX_FRAME),
scratch: vec![0.0; MAX_FRAME * channels],
channels,
skip_left: pre_skip(params.extra_data.as_deref()),
params,
})
}
fn decode_inner(&mut self, packet: &PacketRef<'_>) -> Result<()> {
let frames = self
.inner
.0
.decode_float(packet.data, &mut self.scratch, false)
.map_err(|_| symphonia::core::errors::Error::DecodeError("opus: malformed packet"))?;
if frames > MAX_FRAME {
return decode_error("opus: frame longer than the format allows");
}
self.buf.clear();
self.buf.render_uninit(Some(frames));
let channels = self.channels;
for ch in 0..channels {
let plane = match self.buf.plane_mut(ch) {
Some(p) => p,
None => return decode_error("opus: audio buffer has too few planes"),
};
for (i, sample) in plane.iter_mut().enumerate().take(frames) {
*sample = self.scratch[i * channels + ch];
}
}
let mut trim_start = packet.trim_start.get() as usize;
if self.skip_left > 0 {
let skip = self.skip_left.min(frames);
self.skip_left -= skip;
trim_start += skip;
}
self.buf.trim(trim_start, packet.trim_end.get() as usize);
Ok(())
}
}
impl AudioDecoder for OpusDecoder {
fn reset(&mut self) {
let _ = self.inner.0.reset_state();
self.skip_left = 0;
}
fn codec_info(&self) -> &CodecInfo {
&Self::supported_codecs()
.first()
.expect("opus codec is registered")
.info
}
fn codec_params(&self) -> &AudioCodecParameters {
&self.params
}
fn decode_ref(&mut self, packet: &PacketRef<'_>) -> Result<GenericAudioBufferRef<'_>> {
match self.decode_inner(packet) {
Ok(()) => Ok(self.buf.as_generic_audio_buffer_ref()),
Err(e) => {
self.buf.clear();
Err(e)
}
}
}
fn finalize(&mut self) -> FinalizeResult {
Default::default()
}
fn last_decoded(&self) -> GenericAudioBufferRef<'_> {
self.buf.as_generic_audio_buffer_ref()
}
}
impl RegisterableAudioDecoder for OpusDecoder {
fn try_registry_new(
params: &AudioCodecParameters,
opts: &AudioDecoderOptions,
) -> Result<Box<dyn AudioDecoder>>
where
Self: Sized,
{
Ok(Box::new(OpusDecoder::try_new(params, opts)?))
}
fn supported_codecs() -> &'static [SupportedAudioCodec] {
&[SupportedAudioCodec {
id: CODEC_ID_OPUS,
info: CodecInfo {
short_name: "opus",
long_name: "Opus",
profiles: &[],
},
}]
}
}