use std::error::Error;
use std::fmt;
#[allow(unused_imports)]
use std::io::{Read, Seek, SeekFrom};
use std::mem;
use std::str::FromStr;
use std::time::Duration;
use crate::source::SeekError;
use crate::Source;
#[cfg(feature = "symphonia")]
use self::read_seek_source::ReadSeekSource;
#[cfg(feature = "symphonia")]
use ::symphonia::core::io::{MediaSource, MediaSourceStream};
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
mod flac;
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
mod mp3;
#[cfg(feature = "symphonia")]
mod read_seek_source;
#[cfg(feature = "symphonia")]
pub mod symphonia;
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
mod vorbis;
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
mod wav;
pub struct Decoder<R>(DecoderImpl<R>)
where
R: Read + Seek;
pub struct LoopedDecoder<R>(DecoderImpl<R>)
where
R: Read + Seek;
#[allow(clippy::large_enum_variant)]
enum DecoderImpl<R>
where
R: Read + Seek,
{
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
Wav(wav::WavDecoder<R>),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
Vorbis(vorbis::VorbisDecoder<R>),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
Flac(flac::FlacDecoder<R>),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
Mp3(mp3::Mp3Decoder<R>),
#[cfg(feature = "symphonia")]
Symphonia(symphonia::SymphoniaDecoder),
None(::std::marker::PhantomData<R>),
}
impl<R: Read + Seek> DecoderImpl<R> {
#[inline]
fn next(&mut self) -> Option<i16> {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.next(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.next(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.next(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.next(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.next(),
DecoderImpl::None(_) => None,
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.size_hint(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.size_hint(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.size_hint(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.size_hint(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.size_hint(),
DecoderImpl::None(_) => (0, None),
}
}
#[inline]
fn current_frame_len(&self) -> Option<usize> {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.current_frame_len(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.current_frame_len(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.current_frame_len(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.current_frame_len(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.current_frame_len(),
DecoderImpl::None(_) => Some(0),
}
}
#[inline]
fn channels(&self) -> u16 {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.channels(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.channels(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.channels(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.channels(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.channels(),
DecoderImpl::None(_) => 0,
}
}
#[inline]
fn sample_rate(&self) -> u32 {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.sample_rate(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.sample_rate(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.sample_rate(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.sample_rate(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.sample_rate(),
DecoderImpl::None(_) => 1,
}
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.total_duration(),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.total_duration(),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.total_duration(),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.total_duration(),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.total_duration(),
DecoderImpl::None(_) => Some(Duration::default()),
}
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
match self {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => source.try_seek(pos),
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => source.try_seek(pos),
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => source.try_seek(pos),
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => source.try_seek(pos),
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => source.try_seek(pos),
DecoderImpl::None(_) => Err(SeekError::NotSupported {
underlying_source: "DecoderImpl::None",
}),
}
}
}
impl<R> Decoder<R>
where
R: Read + Seek + Send + Sync + 'static,
{
#[allow(unused_variables)]
pub fn new(data: R) -> Result<Decoder<R>, DecoderError> {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
let data = match wav::WavDecoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Ok(Decoder(DecoderImpl::Wav(decoder)));
}
};
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
let data = match flac::FlacDecoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Ok(Decoder(DecoderImpl::Flac(decoder)));
}
};
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
let data = match vorbis::VorbisDecoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Ok(Decoder(DecoderImpl::Vorbis(decoder)));
}
};
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
let data = match mp3::Mp3Decoder::new(data) {
Err(data) => data,
Ok(decoder) => {
return Ok(Decoder(DecoderImpl::Mp3(decoder)));
}
};
#[cfg(feature = "symphonia")]
{
let mss = MediaSourceStream::new(
Box::new(ReadSeekSource::new(data)) as Box<dyn MediaSource>,
Default::default(),
);
match symphonia::SymphoniaDecoder::new(mss, None) {
Err(e) => Err(e),
Ok(decoder) => Ok(Decoder(DecoderImpl::Symphonia(decoder))),
}
}
#[cfg(not(feature = "symphonia"))]
Err(DecoderError::UnrecognizedFormat)
}
pub fn new_looped(data: R) -> Result<LoopedDecoder<R>, DecoderError> {
Self::new(data).map(LoopedDecoder::new)
}
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
pub fn new_wav(data: R) -> Result<Decoder<R>, DecoderError> {
match wav::WavDecoder::new(data) {
Err(_) => Err(DecoderError::UnrecognizedFormat),
Ok(decoder) => Ok(Decoder(DecoderImpl::Wav(decoder))),
}
}
#[cfg(feature = "symphonia-wav")]
pub fn new_wav(data: R) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, "wav")
}
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
pub fn new_flac(data: R) -> Result<Decoder<R>, DecoderError> {
match flac::FlacDecoder::new(data) {
Err(_) => Err(DecoderError::UnrecognizedFormat),
Ok(decoder) => Ok(Decoder(DecoderImpl::Flac(decoder))),
}
}
#[cfg(feature = "symphonia-flac")]
pub fn new_flac(data: R) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, "flac")
}
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
pub fn new_vorbis(data: R) -> Result<Decoder<R>, DecoderError> {
match vorbis::VorbisDecoder::new(data) {
Err(_) => Err(DecoderError::UnrecognizedFormat),
Ok(decoder) => Ok(Decoder(DecoderImpl::Vorbis(decoder))),
}
}
#[cfg(feature = "symphonia-vorbis")]
pub fn new_vorbis(data: R) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, "ogg")
}
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
pub fn new_mp3(data: R) -> Result<Decoder<R>, DecoderError> {
match mp3::Mp3Decoder::new(data) {
Err(_) => Err(DecoderError::UnrecognizedFormat),
Ok(decoder) => Ok(Decoder(DecoderImpl::Mp3(decoder))),
}
}
#[cfg(feature = "symphonia-mp3")]
pub fn new_mp3(data: R) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, "mp3")
}
#[cfg(feature = "symphonia-aac")]
pub fn new_aac(data: R) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, "aac")
}
#[cfg(feature = "symphonia-isomp4")]
pub fn new_mp4(data: R, hint: Mp4Type) -> Result<Decoder<R>, DecoderError> {
Decoder::new_symphonia(data, &hint.to_string())
}
#[cfg(feature = "symphonia")]
fn new_symphonia(data: R, hint: &str) -> Result<Decoder<R>, DecoderError> {
let mss = MediaSourceStream::new(
Box::new(ReadSeekSource::new(data)) as Box<dyn MediaSource>,
Default::default(),
);
match symphonia::SymphoniaDecoder::new(mss, Some(hint)) {
Err(e) => Err(e),
Ok(decoder) => Ok(Decoder(DecoderImpl::Symphonia(decoder))),
}
}
}
#[allow(missing_docs)] #[derive(Debug)]
pub enum Mp4Type {
Mp4,
M4a,
M4p,
M4b,
M4r,
M4v,
Mov,
}
impl FromStr for Mp4Type {
type Err = String;
fn from_str(input: &str) -> Result<Mp4Type, Self::Err> {
match &input.to_lowercase()[..] {
"mp4" => Ok(Mp4Type::Mp4),
"m4a" => Ok(Mp4Type::M4a),
"m4p" => Ok(Mp4Type::M4p),
"m4b" => Ok(Mp4Type::M4b),
"m4r" => Ok(Mp4Type::M4r),
"m4v" => Ok(Mp4Type::M4v),
"mov" => Ok(Mp4Type::Mov),
_ => Err(format!("{input} is not a valid mp4 extension")),
}
}
}
impl fmt::Display for Mp4Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let text = match self {
Mp4Type::Mp4 => "mp4",
Mp4Type::M4a => "m4a",
Mp4Type::M4p => "m4p",
Mp4Type::M4b => "m4b",
Mp4Type::M4r => "m4r",
Mp4Type::M4v => "m4v",
Mp4Type::Mov => "mov",
};
write!(f, "{text}")
}
}
impl<R> LoopedDecoder<R>
where
R: Read + Seek,
{
fn new(decoder: Decoder<R>) -> LoopedDecoder<R> {
Self(decoder.0)
}
}
impl<R> Iterator for Decoder<R>
where
R: Read + Seek,
{
type Item = i16;
#[inline]
fn next(&mut self) -> Option<i16> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<R> Source for Decoder<R>
where
R: Read + Seek,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.0.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.0.channels()
}
fn sample_rate(&self) -> u32 {
self.0.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
self.0.total_duration()
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.0.try_seek(pos)
}
}
impl<R> Iterator for LoopedDecoder<R>
where
R: Read + Seek,
{
type Item = i16;
#[inline]
fn next(&mut self) -> Option<i16> {
if let Some(sample) = self.0.next() {
Some(sample)
} else {
let decoder = mem::replace(&mut self.0, DecoderImpl::None(Default::default()));
let (decoder, sample) = match decoder {
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
DecoderImpl::Wav(source) => {
let mut reader = source.into_inner();
reader.seek(SeekFrom::Start(0)).ok()?;
let mut source = wav::WavDecoder::new(reader).ok()?;
let sample = source.next();
(DecoderImpl::Wav(source), sample)
}
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
DecoderImpl::Vorbis(source) => {
use lewton::inside_ogg::OggStreamReader;
let mut reader = source.into_inner().into_inner();
reader.seek_bytes(SeekFrom::Start(0)).ok()?;
let mut source = vorbis::VorbisDecoder::from_stream_reader(
OggStreamReader::from_ogg_reader(reader).ok()?,
);
let sample = source.next();
(DecoderImpl::Vorbis(source), sample)
}
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
DecoderImpl::Flac(source) => {
let mut reader = source.into_inner();
reader.seek(SeekFrom::Start(0)).ok()?;
let mut source = flac::FlacDecoder::new(reader).ok()?;
let sample = source.next();
(DecoderImpl::Flac(source), sample)
}
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
DecoderImpl::Mp3(source) => {
let mut reader = source.into_inner();
reader.seek(SeekFrom::Start(0)).ok()?;
let mut source = mp3::Mp3Decoder::new(reader).ok()?;
let sample = source.next();
(DecoderImpl::Mp3(source), sample)
}
#[cfg(feature = "symphonia")]
DecoderImpl::Symphonia(source) => {
let mut reader = source.into_inner();
reader.seek(SeekFrom::Start(0)).ok()?;
let mut source = symphonia::SymphoniaDecoder::new(reader, None).ok()?;
let sample = source.next();
(DecoderImpl::Symphonia(source), sample)
}
none @ DecoderImpl::None(_) => (none, None),
};
self.0 = decoder;
sample
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<R> Source for LoopedDecoder<R>
where
R: Read + Seek,
{
#[inline]
fn current_frame_len(&self) -> Option<usize> {
self.0.current_frame_len()
}
#[inline]
fn channels(&self) -> u16 {
self.0.channels()
}
#[inline]
fn sample_rate(&self) -> u32 {
self.0.sample_rate()
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
self.0.try_seek(pos)
}
}
#[derive(Debug, Clone)]
pub enum DecoderError {
UnrecognizedFormat,
#[cfg(feature = "symphonia")]
IoError(String),
#[cfg(feature = "symphonia")]
DecodeError(&'static str),
#[cfg(feature = "symphonia")]
LimitError(&'static str),
#[cfg(feature = "symphonia")]
ResetRequired,
#[cfg(feature = "symphonia")]
NoStreams,
}
impl fmt::Display for DecoderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let text = match self {
DecoderError::UnrecognizedFormat => "Unrecognized format",
#[cfg(feature = "symphonia")]
DecoderError::IoError(msg) => &msg[..],
#[cfg(feature = "symphonia")]
DecoderError::DecodeError(msg) => msg,
#[cfg(feature = "symphonia")]
DecoderError::LimitError(msg) => msg,
#[cfg(feature = "symphonia")]
DecoderError::ResetRequired => "Reset required",
#[cfg(feature = "symphonia")]
DecoderError::NoStreams => "No streams",
};
write!(f, "{text}")
}
}
impl Error for DecoderError {}