use std::{
io::{BufReader, Read, Seek},
marker::PhantomData,
time::Duration,
};
#[allow(unused_imports)]
use std::io::SeekFrom;
use rodio::{
decoder::DecoderError,
source::{SeekError, Source},
ChannelCount, Sample, SampleRate,
};
pub mod builder;
pub use builder::{DecoderBuilder, Settings};
mod read_seek_source;
pub mod symphonia;
pub struct Decoder<R: Read + Seek>(DecoderImpl<R>);
pub struct LoopedDecoder<R: Read + Seek> {
inner: Option<DecoderImpl<R>>,
settings: Settings,
}
#[allow(clippy::large_enum_variant)]
enum DecoderImpl<R: Read + Seek> {
Symphonia(symphonia::SymphoniaDecoder, PhantomData<R>),
#[allow(dead_code)]
None(Unreachable, PhantomData<R>),
}
enum Unreachable {}
impl<R: Read + Seek> DecoderImpl<R> {
#[inline]
fn next(&mut self) -> Option<Sample> {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.next(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.size_hint(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn current_span_len(&self) -> Option<usize> {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.current_span_len(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn channels(&self) -> ChannelCount {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.channels(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn sample_rate(&self) -> SampleRate {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.sample_rate(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.total_duration(),
DecoderImpl::None(_, _) => unreachable!(),
}
}
#[inline]
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
match self {
DecoderImpl::Symphonia(source, PhantomData) => source.try_seek(pos),
DecoderImpl::None(_, _) => unreachable!(),
}
}
}
impl TryFrom<std::fs::File> for Decoder<BufReader<std::fs::File>> {
type Error = DecoderError;
fn try_from(file: std::fs::File) -> Result<Self, Self::Error> {
let len = file
.metadata()
.map_err(|e| Self::Error::IoError(e.to_string()))?
.len();
Self::builder()
.with_data(BufReader::new(file))
.with_byte_len(len)
.with_seekable(true)
.build()
}
}
impl<R> TryFrom<BufReader<R>> for Decoder<BufReader<R>>
where
R: Read + Seek + Send + Sync + 'static,
{
type Error = DecoderError;
fn try_from(data: BufReader<R>) -> Result<Self, Self::Error> {
Self::new(data)
}
}
impl<T> TryFrom<std::io::Cursor<T>> for Decoder<std::io::Cursor<T>>
where
T: AsRef<[u8]> + Send + Sync + 'static,
{
type Error = DecoderError;
fn try_from(data: std::io::Cursor<T>) -> Result<Self, Self::Error> {
Self::new(data)
}
}
impl<R: Read + Seek + Send + Sync + 'static> Decoder<R> {
pub fn builder() -> DecoderBuilder<R> {
DecoderBuilder::new()
}
pub fn new(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new().with_data(data).build()
}
pub fn new_looped(data: R) -> Result<LoopedDecoder<R>, DecoderError> {
DecoderBuilder::new().with_data(data).build_looped()
}
pub fn new_wav(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_hint("wav")
.build()
}
pub fn new_flac(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_hint("flac")
.build()
}
pub fn new_vorbis(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_hint("ogg")
.build()
}
pub fn new_mp3(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_hint("mp3")
.build()
}
pub fn new_aac(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_hint("aac")
.build()
}
pub fn new_mp4(data: R) -> Result<Self, DecoderError> {
DecoderBuilder::new()
.with_data(data)
.with_mime_type("audio/mp4")
.build()
}
}
impl<R> Iterator for Decoder<R>
where
R: Read + Seek,
{
type Item = Sample;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
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_span_len(&self) -> Option<usize> {
self.0.current_span_len()
}
#[inline]
fn channels(&self) -> ChannelCount {
self.0.channels()
}
fn sample_rate(&self) -> SampleRate {
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 = Sample;
fn next(&mut self) -> Option<Self::Item> {
if let Some(inner) = &mut self.inner {
if let Some(sample) = inner.next() {
return Some(sample);
}
let decoder = self.inner.take()?;
let (new_decoder, sample) = match decoder {
DecoderImpl::Symphonia(source, PhantomData) => {
let mut reader = source.into_inner();
reader.seek(SeekFrom::Start(0)).ok()?;
let mut source =
symphonia::SymphoniaDecoder::new(reader, &self.settings).ok()?;
let sample = source.next();
(DecoderImpl::Symphonia(source, PhantomData), sample)
}
};
self.inner = Some(new_decoder);
sample
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(
self.inner.as_ref().map_or(0, |inner| inner.size_hint().0),
None,
)
}
}
impl<R> Source for LoopedDecoder<R>
where
R: Read + Seek,
{
#[inline]
fn current_span_len(&self) -> Option<usize> {
self.inner.as_ref()?.current_span_len()
}
#[inline]
fn channels(&self) -> ChannelCount {
self.inner
.as_ref()
.map_or(ChannelCount::default(), |inner| inner.channels())
}
#[inline]
fn sample_rate(&self) -> SampleRate {
self.inner
.as_ref()
.map_or(SampleRate::default(), |inner| inner.sample_rate())
}
#[inline]
fn total_duration(&self) -> Option<Duration> {
None
}
fn try_seek(&mut self, pos: Duration) -> Result<(), SeekError> {
match &mut self.inner {
Some(inner) => inner.try_seek(pos),
None => Err(SeekError::Other(Box::new(DecoderError::IoError(
"Looped source ended when it failed to loop back".to_string(),
)))),
}
}
}