use std::fs;
use symphonia::{
core::{
audio::{GenericAudioBuffer, GenericAudioBufferRef},
codecs::audio::{AudioDecoder, AudioDecoderOptions},
errors::Error as SymphoniaError,
formats::{FormatOptions, FormatReader, TrackType},
io::{MediaSourceStream, MediaSourceStreamOptions},
},
default::formats::{FlacReader, MpaReader, OggReader, WavReader},
};
use thiserror::Error;
use crate::{
errors::ContainerError,
media_container::{ContainerFormat, MediaContainer, Stream},
};
#[derive(Debug, Error)]
pub enum DecodingError {
#[error("{0}")]
Io(#[from] std::io::Error),
#[error("{0}")]
Symphonia(#[from] SymphoniaError),
#[error("{0}")]
Container(#[from] ContainerError),
#[error("Player attempted to play an unsupported container: '{0:?}'")]
UnsupportedContainer(ContainerFormat),
}
pub struct RawDecoder {
pub stream: Stream,
pub format_reader: Box<dyn FormatReader>,
pub decoder: Box<dyn AudioDecoder>,
}
impl RawDecoder {
pub fn from_container(
container: &MediaContainer,
buffer_len: usize,
) -> Result<Self, DecodingError> {
let file = fs::File::open(container.path())?;
let options = MediaSourceStreamOptions { buffer_len };
let mss = MediaSourceStream::new(Box::new(file), options);
let fmt_opts = FormatOptions::default();
let format_reader: Box<dyn FormatReader> = match container.format() {
ContainerFormat::Flac => Box::new(FlacReader::try_new(mss, fmt_opts)?),
ContainerFormat::Mpa => Box::new(MpaReader::try_new(mss, fmt_opts)?),
ContainerFormat::Ogg => Box::new(OggReader::try_new(mss, fmt_opts)?),
ContainerFormat::Wav => Box::new(WavReader::try_new(mss, fmt_opts)?),
other => return Err(DecodingError::UnsupportedContainer(*other)),
};
let track = format_reader
.default_track(TrackType::Audio)
.expect("Playable file does not have any supported codecs");
let dec_opts: AudioDecoderOptions = Default::default();
let params = track
.codec_params
.as_ref()
.expect("Track is not playable")
.audio()
.unwrap();
let decoder = symphonia::default::get_codecs().make_audio_decoder(params, &dec_opts)?;
Ok(Self {
stream: Stream::try_from(track)?,
format_reader,
decoder,
})
}
pub fn decode_next_packet(&mut self) -> Result<Option<GenericAudioBuffer>, DecodingError> {
loop {
let packet = match self.format_reader.next_packet() {
Ok(Some(packet)) => packet,
Err(SymphoniaError::ResetRequired) => {
self.decoder.reset();
continue;
}
Ok(None) => return Ok(None),
Err(err) => return Err(DecodingError::Symphonia(err)),
};
while !self.format_reader.metadata().is_latest() {
self.format_reader.metadata().pop();
}
if packet.track_id() != self.stream.id {
continue;
}
let decoded = match self.decoder.decode(&packet) {
Ok(decoded) => decoded,
Err(SymphoniaError::DecodeError(_)) => continue,
Err(SymphoniaError::IoError(_)) => continue,
Err(err) => return Err(DecodingError::Symphonia(err)),
};
let audio_buf = match decoded {
GenericAudioBufferRef::U8(audio_buffer) => {
GenericAudioBuffer::U8(audio_buffer.clone())
}
GenericAudioBufferRef::U16(audio_buffer) => {
GenericAudioBuffer::U16(audio_buffer.clone())
}
GenericAudioBufferRef::U24(audio_buffer) => {
GenericAudioBuffer::U24(audio_buffer.clone())
}
GenericAudioBufferRef::U32(audio_buffer) => {
GenericAudioBuffer::U32(audio_buffer.clone())
}
GenericAudioBufferRef::S8(audio_buffer) => {
GenericAudioBuffer::S8(audio_buffer.clone())
}
GenericAudioBufferRef::S16(audio_buffer) => {
GenericAudioBuffer::S16(audio_buffer.clone())
}
GenericAudioBufferRef::S24(audio_buffer) => {
GenericAudioBuffer::S24(audio_buffer.clone())
}
GenericAudioBufferRef::S32(audio_buffer) => {
GenericAudioBuffer::S32(audio_buffer.clone())
}
GenericAudioBufferRef::F32(audio_buffer) => {
GenericAudioBuffer::F32(audio_buffer.clone())
}
GenericAudioBufferRef::F64(audio_buffer) => {
GenericAudioBuffer::F64(audio_buffer.clone())
}
};
return Ok(Some(audio_buf));
}
}
}