geng_rodio/decoder/
mod.rs

1//! Decodes samples from an audio file.
2
3use std::error::Error;
4use std::fmt;
5#[allow(unused_imports)]
6use std::io::{Read, Seek, SeekFrom};
7use std::marker::Sync;
8use std::mem;
9use std::str::FromStr;
10use std::time::Duration;
11
12use crate::Source;
13
14#[cfg(feature = "symphonia")]
15use self::read_seek_source::ReadSeekSource;
16#[cfg(feature = "symphonia")]
17use ::symphonia::core::io::{MediaSource, MediaSourceStream};
18
19#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
20mod flac;
21#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
22mod mp3;
23#[cfg(feature = "symphonia")]
24mod read_seek_source;
25#[cfg(feature = "symphonia")]
26mod symphonia;
27#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
28mod vorbis;
29#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
30mod wav;
31
32/// Source of audio samples from decoding a file.
33///
34/// Supports MP3, WAV, Vorbis and Flac.
35pub struct Decoder<R>(DecoderImpl<R>)
36where
37    R: Read + Seek;
38
39pub struct LoopedDecoder<R>(DecoderImpl<R>)
40where
41    R: Read + Seek;
42
43enum DecoderImpl<R>
44where
45    R: Read + Seek,
46{
47    #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
48    Wav(wav::WavDecoder<R>),
49    #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
50    Vorbis(vorbis::VorbisDecoder<R>),
51    #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
52    Flac(flac::FlacDecoder<R>),
53    #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
54    Mp3(mp3::Mp3Decoder<R>),
55    #[cfg(feature = "symphonia")]
56    Symphonia(symphonia::SymphoniaDecoder),
57    None(::std::marker::PhantomData<R>),
58}
59
60impl<R> Decoder<R>
61where
62    R: Read + Seek + Send + Sync + 'static,
63{
64    /// Builds a new decoder.
65    ///
66    /// Attempts to automatically detect the format of the source of data.
67    #[allow(unused_variables)]
68    pub fn new(data: R) -> Result<Decoder<R>, DecoderError> {
69        #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
70        let data = match wav::WavDecoder::new(data) {
71            Err(data) => data,
72            Ok(decoder) => {
73                return Ok(Decoder(DecoderImpl::Wav(decoder)));
74            }
75        };
76
77        #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
78        let data = match flac::FlacDecoder::new(data) {
79            Err(data) => data,
80            Ok(decoder) => {
81                return Ok(Decoder(DecoderImpl::Flac(decoder)));
82            }
83        };
84
85        #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
86        let data = match vorbis::VorbisDecoder::new(data) {
87            Err(data) => data,
88            Ok(decoder) => {
89                return Ok(Decoder(DecoderImpl::Vorbis(decoder)));
90            }
91        };
92
93        #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
94        let data = match mp3::Mp3Decoder::new(data) {
95            Err(data) => data,
96            Ok(decoder) => {
97                return Ok(Decoder(DecoderImpl::Mp3(decoder)));
98            }
99        };
100
101        #[cfg(feature = "symphonia")]
102        {
103            let mss = MediaSourceStream::new(
104                Box::new(ReadSeekSource::new(data)) as Box<dyn MediaSource>,
105                Default::default(),
106            );
107
108            match symphonia::SymphoniaDecoder::new(mss, None) {
109                Err(e) => Err(e),
110                Ok(decoder) => {
111                    return Ok(Decoder(DecoderImpl::Symphonia(decoder)));
112                }
113            }
114        }
115        #[cfg(not(feature = "symphonia"))]
116        Err(DecoderError::UnrecognizedFormat)
117    }
118    pub fn new_looped(data: R) -> Result<LoopedDecoder<R>, DecoderError> {
119        Self::new(data).map(LoopedDecoder::new)
120    }
121
122    /// Builds a new decoder from wav data.
123    #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
124    pub fn new_wav(data: R) -> Result<Decoder<R>, DecoderError> {
125        match wav::WavDecoder::new(data) {
126            Err(_) => Err(DecoderError::UnrecognizedFormat),
127            Ok(decoder) => Ok(Decoder(DecoderImpl::Wav(decoder))),
128        }
129    }
130
131    /// Builds a new decoder from wav data.
132    #[cfg(feature = "symphonia-wav")]
133    pub fn new_wav(data: R) -> Result<Decoder<R>, DecoderError> {
134        Decoder::new_symphonia(data, "wav")
135    }
136
137    /// Builds a new decoder from flac data.
138    #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
139    pub fn new_flac(data: R) -> Result<Decoder<R>, DecoderError> {
140        match flac::FlacDecoder::new(data) {
141            Err(_) => Err(DecoderError::UnrecognizedFormat),
142            Ok(decoder) => Ok(Decoder(DecoderImpl::Flac(decoder))),
143        }
144    }
145
146    /// Builds a new decoder from flac data.
147    #[cfg(feature = "symphonia-flac")]
148    pub fn new_flac(data: R) -> Result<Decoder<R>, DecoderError> {
149        Decoder::new_symphonia(data, "flac")
150    }
151
152    /// Builds a new decoder from vorbis data.
153    #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
154    pub fn new_vorbis(data: R) -> Result<Decoder<R>, DecoderError> {
155        match vorbis::VorbisDecoder::new(data) {
156            Err(_) => Err(DecoderError::UnrecognizedFormat),
157            Ok(decoder) => Ok(Decoder(DecoderImpl::Vorbis(decoder))),
158        }
159    }
160
161    /// Builds a new decoder from mp3 data.
162    #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
163    pub fn new_mp3(data: R) -> Result<Decoder<R>, DecoderError> {
164        match mp3::Mp3Decoder::new(data) {
165            Err(_) => Err(DecoderError::UnrecognizedFormat),
166            Ok(decoder) => Ok(Decoder(DecoderImpl::Mp3(decoder))),
167        }
168    }
169
170    /// Builds a new decoder from mp3 data.
171    #[cfg(feature = "symphonia-mp3")]
172    pub fn new_mp3(data: R) -> Result<Decoder<R>, DecoderError> {
173        Decoder::new_symphonia(data, "mp3")
174    }
175
176    /// Builds a new decoder from aac data.
177    #[cfg(feature = "symphonia-aac")]
178    pub fn new_aac(data: R) -> Result<Decoder<R>, DecoderError> {
179        Decoder::new_symphonia(data, "aac")
180    }
181
182    /// Builds a new decoder from mp4 data.
183    #[cfg(feature = "symphonia-isomp4")]
184    pub fn new_mp4(data: R, hint: Mp4Type) -> Result<Decoder<R>, DecoderError> {
185        Decoder::new_symphonia(data, &hint.to_string())
186    }
187
188    #[cfg(feature = "symphonia")]
189    fn new_symphonia(data: R, hint: &str) -> Result<Decoder<R>, DecoderError> {
190        let mss = MediaSourceStream::new(
191            Box::new(ReadSeekSource::new(data)) as Box<dyn MediaSource>,
192            Default::default(),
193        );
194
195        match symphonia::SymphoniaDecoder::new(mss, Some(hint)) {
196            Err(e) => Err(e),
197            Ok(decoder) => {
198                return Ok(Decoder(DecoderImpl::Symphonia(decoder)));
199            }
200        }
201    }
202}
203
204#[derive(Debug)]
205pub enum Mp4Type {
206    Mp4,
207    M4a,
208    M4p,
209    M4b,
210    M4r,
211    M4v,
212    Mov,
213}
214
215impl FromStr for Mp4Type {
216    type Err = String;
217
218    fn from_str(input: &str) -> Result<Mp4Type, Self::Err> {
219        match &input.to_lowercase()[..] {
220            "mp4" => Ok(Mp4Type::Mp4),
221            "m4a" => Ok(Mp4Type::M4a),
222            "m4p" => Ok(Mp4Type::M4p),
223            "m4b" => Ok(Mp4Type::M4b),
224            "m4r" => Ok(Mp4Type::M4r),
225            "m4v" => Ok(Mp4Type::M4v),
226            "mov" => Ok(Mp4Type::Mov),
227            _ => Err(format!("{} is not a valid mp4 extension", input)),
228        }
229    }
230}
231
232impl fmt::Display for Mp4Type {
233    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234        let text = match self {
235            Mp4Type::Mp4 => "mp4",
236            Mp4Type::M4a => "m4a",
237            Mp4Type::M4p => "m4p",
238            Mp4Type::M4b => "m4b",
239            Mp4Type::M4r => "m4r",
240            Mp4Type::M4v => "m4v",
241            Mp4Type::Mov => "mov",
242        };
243        write!(f, "{}", text)
244    }
245}
246
247impl<R> LoopedDecoder<R>
248where
249    R: Read + Seek,
250{
251    fn new(decoder: Decoder<R>) -> LoopedDecoder<R> {
252        Self(decoder.0)
253    }
254}
255
256impl<R> Iterator for Decoder<R>
257where
258    R: Read + Seek,
259{
260    type Item = i16;
261
262    #[inline]
263    fn next(&mut self) -> Option<i16> {
264        match &mut self.0 {
265            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
266            DecoderImpl::Wav(source) => source.next(),
267            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
268            DecoderImpl::Vorbis(source) => source.next(),
269            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
270            DecoderImpl::Flac(source) => source.next(),
271            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
272            DecoderImpl::Mp3(source) => source.next(),
273            #[cfg(feature = "symphonia")]
274            DecoderImpl::Symphonia(source) => source.next(),
275            DecoderImpl::None(_) => None,
276        }
277    }
278
279    #[inline]
280    fn size_hint(&self) -> (usize, Option<usize>) {
281        match &self.0 {
282            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
283            DecoderImpl::Wav(source) => source.size_hint(),
284            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
285            DecoderImpl::Vorbis(source) => source.size_hint(),
286            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
287            DecoderImpl::Flac(source) => source.size_hint(),
288            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
289            DecoderImpl::Mp3(source) => source.size_hint(),
290            #[cfg(feature = "symphonia")]
291            DecoderImpl::Symphonia(source) => source.size_hint(),
292            DecoderImpl::None(_) => (0, None),
293        }
294    }
295}
296
297impl<R> Source for Decoder<R>
298where
299    R: Read + Seek,
300{
301    #[inline]
302    fn current_frame_len(&self) -> Option<usize> {
303        match &self.0 {
304            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
305            DecoderImpl::Wav(source) => source.current_frame_len(),
306            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
307            DecoderImpl::Vorbis(source) => source.current_frame_len(),
308            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
309            DecoderImpl::Flac(source) => source.current_frame_len(),
310            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
311            DecoderImpl::Mp3(source) => source.current_frame_len(),
312            #[cfg(feature = "symphonia")]
313            DecoderImpl::Symphonia(source) => source.current_frame_len(),
314            DecoderImpl::None(_) => Some(0),
315        }
316    }
317
318    #[inline]
319    fn channels(&self) -> u16 {
320        match &self.0 {
321            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
322            DecoderImpl::Wav(source) => source.channels(),
323            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
324            DecoderImpl::Vorbis(source) => source.channels(),
325            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
326            DecoderImpl::Flac(source) => source.channels(),
327            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
328            DecoderImpl::Mp3(source) => source.channels(),
329            #[cfg(feature = "symphonia")]
330            DecoderImpl::Symphonia(source) => source.channels(),
331            DecoderImpl::None(_) => 0,
332        }
333    }
334
335    #[inline]
336    fn sample_rate(&self) -> u32 {
337        match &self.0 {
338            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
339            DecoderImpl::Wav(source) => source.sample_rate(),
340            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
341            DecoderImpl::Vorbis(source) => source.sample_rate(),
342            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
343            DecoderImpl::Flac(source) => source.sample_rate(),
344            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
345            DecoderImpl::Mp3(source) => source.sample_rate(),
346            #[cfg(feature = "symphonia")]
347            DecoderImpl::Symphonia(source) => source.sample_rate(),
348            DecoderImpl::None(_) => 1,
349        }
350    }
351
352    #[inline]
353    fn total_duration(&self) -> Option<Duration> {
354        match &self.0 {
355            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
356            DecoderImpl::Wav(source) => source.total_duration(),
357            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
358            DecoderImpl::Vorbis(source) => source.total_duration(),
359            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
360            DecoderImpl::Flac(source) => source.total_duration(),
361            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
362            DecoderImpl::Mp3(source) => source.total_duration(),
363            #[cfg(feature = "symphonia")]
364            DecoderImpl::Symphonia(source) => source.total_duration(),
365            DecoderImpl::None(_) => Some(Duration::default()),
366        }
367    }
368}
369
370impl<R> Iterator for LoopedDecoder<R>
371where
372    R: Read + Seek,
373{
374    type Item = i16;
375
376    #[inline]
377    fn next(&mut self) -> Option<i16> {
378        if let Some(sample) = match &mut self.0 {
379            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
380            DecoderImpl::Wav(source) => source.next(),
381            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
382            DecoderImpl::Vorbis(source) => source.next(),
383            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
384            DecoderImpl::Flac(source) => source.next(),
385            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
386            DecoderImpl::Mp3(source) => source.next(),
387            #[cfg(feature = "symphonia")]
388            DecoderImpl::Symphonia(source) => source.next(),
389            DecoderImpl::None(_) => None,
390        } {
391            Some(sample)
392        } else {
393            let decoder = mem::replace(&mut self.0, DecoderImpl::None(Default::default()));
394            let (decoder, sample) = match decoder {
395                #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
396                DecoderImpl::Wav(source) => {
397                    let mut reader = source.into_inner();
398                    reader.seek(SeekFrom::Start(0)).ok()?;
399                    let mut source = wav::WavDecoder::new(reader).ok()?;
400                    let sample = source.next();
401                    (DecoderImpl::Wav(source), sample)
402                }
403                #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
404                DecoderImpl::Vorbis(source) => {
405                    use lewton::inside_ogg::OggStreamReader;
406                    let mut reader = source.into_inner().into_inner();
407                    reader.seek_bytes(SeekFrom::Start(0)).ok()?;
408                    let mut source = vorbis::VorbisDecoder::from_stream_reader(
409                        OggStreamReader::from_ogg_reader(reader).ok()?,
410                    );
411                    let sample = source.next();
412                    (DecoderImpl::Vorbis(source), sample)
413                }
414                #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
415                DecoderImpl::Flac(source) => {
416                    let mut reader = source.into_inner();
417                    reader.seek(SeekFrom::Start(0)).ok()?;
418                    let mut source = flac::FlacDecoder::new(reader).ok()?;
419                    let sample = source.next();
420                    (DecoderImpl::Flac(source), sample)
421                }
422                #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
423                DecoderImpl::Mp3(source) => {
424                    let mut reader = source.into_inner();
425                    reader.seek(SeekFrom::Start(0)).ok()?;
426                    let mut source = mp3::Mp3Decoder::new(reader).ok()?;
427                    let sample = source.next();
428                    (DecoderImpl::Mp3(source), sample)
429                }
430                #[cfg(feature = "symphonia")]
431                DecoderImpl::Symphonia(source) => {
432                    let mut reader = Box::new(source).into_inner();
433                    reader.seek(SeekFrom::Start(0)).ok()?;
434                    let mut source = symphonia::SymphoniaDecoder::new(reader, None).ok()?;
435                    let sample = source.next();
436                    (DecoderImpl::Symphonia(source), sample)
437                }
438                none @ DecoderImpl::None(_) => (none, None),
439            };
440            self.0 = decoder;
441            sample
442        }
443    }
444
445    #[inline]
446    fn size_hint(&self) -> (usize, Option<usize>) {
447        match &self.0 {
448            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
449            DecoderImpl::Wav(source) => (source.size_hint().0, None),
450            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
451            DecoderImpl::Vorbis(source) => (source.size_hint().0, None),
452            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
453            DecoderImpl::Flac(source) => (source.size_hint().0, None),
454            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
455            DecoderImpl::Mp3(source) => (source.size_hint().0, None),
456            #[cfg(feature = "symphonia")]
457            DecoderImpl::Symphonia(source) => (source.size_hint().0, None),
458            DecoderImpl::None(_) => (0, None),
459        }
460    }
461}
462
463impl<R> Source for LoopedDecoder<R>
464where
465    R: Read + Seek,
466{
467    #[inline]
468    fn current_frame_len(&self) -> Option<usize> {
469        match &self.0 {
470            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
471            DecoderImpl::Wav(source) => source.current_frame_len(),
472            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
473            DecoderImpl::Vorbis(source) => source.current_frame_len(),
474            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
475            DecoderImpl::Flac(source) => source.current_frame_len(),
476            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
477            DecoderImpl::Mp3(source) => source.current_frame_len(),
478            #[cfg(feature = "symphonia")]
479            DecoderImpl::Symphonia(source) => source.current_frame_len(),
480            DecoderImpl::None(_) => Some(0),
481        }
482    }
483
484    #[inline]
485    fn channels(&self) -> u16 {
486        match &self.0 {
487            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
488            DecoderImpl::Wav(source) => source.channels(),
489            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
490            DecoderImpl::Vorbis(source) => source.channels(),
491            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
492            DecoderImpl::Flac(source) => source.channels(),
493            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
494            DecoderImpl::Mp3(source) => source.channels(),
495            #[cfg(feature = "symphonia")]
496            DecoderImpl::Symphonia(source) => source.channels(),
497            DecoderImpl::None(_) => 0,
498        }
499    }
500
501    #[inline]
502    fn sample_rate(&self) -> u32 {
503        match &self.0 {
504            #[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
505            DecoderImpl::Wav(source) => source.sample_rate(),
506            #[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
507            DecoderImpl::Vorbis(source) => source.sample_rate(),
508            #[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
509            DecoderImpl::Flac(source) => source.sample_rate(),
510            #[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
511            DecoderImpl::Mp3(source) => source.sample_rate(),
512            #[cfg(feature = "symphonia")]
513            DecoderImpl::Symphonia(source) => source.sample_rate(),
514            DecoderImpl::None(_) => 1,
515        }
516    }
517
518    #[inline]
519    fn total_duration(&self) -> Option<Duration> {
520        None
521    }
522}
523
524/// Error that can happen when creating a decoder.
525#[derive(Debug, Clone)]
526pub enum DecoderError {
527    /// The format of the data has not been recognized.
528    UnrecognizedFormat,
529
530    /// An IO error occurred while reading, writing, or seeking the stream.
531    #[cfg(feature = "symphonia")]
532    IoError(String),
533
534    /// The stream contained malformed data and could not be decoded or demuxed.
535    #[cfg(feature = "symphonia")]
536    DecodeError(&'static str),
537
538    /// A default or user-defined limit was reached while decoding or demuxing the stream. Limits
539    /// are used to prevent denial-of-service attacks from malicious streams.
540    #[cfg(feature = "symphonia")]
541    LimitError(&'static str),
542
543    /// The demuxer or decoder needs to be reset before continuing.
544    #[cfg(feature = "symphonia")]
545    ResetRequired,
546
547    /// No streams were found by the decoder
548    #[cfg(feature = "symphonia")]
549    NoStreams,
550}
551
552impl fmt::Display for DecoderError {
553    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
554        let text = match self {
555            DecoderError::UnrecognizedFormat => "Unrecognized format",
556            #[cfg(feature = "symphonia")]
557            DecoderError::IoError(msg) => &msg[..],
558            #[cfg(feature = "symphonia")]
559            DecoderError::DecodeError(msg) => msg,
560            #[cfg(feature = "symphonia")]
561            DecoderError::LimitError(msg) => msg,
562            #[cfg(feature = "symphonia")]
563            DecoderError::ResetRequired => "Reset required",
564            #[cfg(feature = "symphonia")]
565            DecoderError::NoStreams => "No streams",
566        };
567        write!(f, "{}", text)
568    }
569}
570
571impl Error for DecoderError {}