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