rodio/decoder/
vorbis.rs

1use std::io::{Read, Seek, SeekFrom};
2use std::time::Duration;
3
4use crate::source::SeekError;
5use crate::Source;
6
7use lewton::inside_ogg::OggStreamReader;
8
9/// Decoder for an OGG file that contains Vorbis sound format.
10pub struct VorbisDecoder<R>
11where
12    R: Read + Seek,
13{
14    stream_reader: OggStreamReader<R>,
15    current_data: Vec<i16>,
16    next: usize,
17}
18
19impl<R> VorbisDecoder<R>
20where
21    R: Read + Seek,
22{
23    /// Attempts to decode the data as ogg/vorbis.
24    pub fn new(mut data: R) -> Result<VorbisDecoder<R>, R> {
25        if !is_vorbis(data.by_ref()) {
26            return Err(data);
27        }
28
29        let stream_reader = OggStreamReader::new(data).unwrap();
30        Ok(Self::from_stream_reader(stream_reader))
31    }
32    pub fn from_stream_reader(mut stream_reader: OggStreamReader<R>) -> Self {
33        let mut data = match stream_reader.read_dec_packet_itl() {
34            Ok(Some(d)) => d,
35            _ => Vec::new(),
36        };
37
38        // The first packet is always empty, therefore
39        // we need to read the second frame to get some data
40        if let Ok(Some(mut d)) = stream_reader.read_dec_packet_itl() {
41            data.append(&mut d);
42        }
43
44        VorbisDecoder {
45            stream_reader,
46            current_data: data,
47            next: 0,
48        }
49    }
50    pub fn into_inner(self) -> OggStreamReader<R> {
51        self.stream_reader
52    }
53}
54
55impl<R> Source for VorbisDecoder<R>
56where
57    R: Read + Seek,
58{
59    #[inline]
60    fn current_frame_len(&self) -> Option<usize> {
61        Some(self.current_data.len())
62    }
63
64    #[inline]
65    fn channels(&self) -> u16 {
66        self.stream_reader.ident_hdr.audio_channels as u16
67    }
68
69    #[inline]
70    fn sample_rate(&self) -> u32 {
71        self.stream_reader.ident_hdr.audio_sample_rate
72    }
73
74    #[inline]
75    fn total_duration(&self) -> Option<Duration> {
76        None
77    }
78
79    /// seek is broken, https://github.com/RustAudio/lewton/issues/73.
80    // We could work around it by:
81    //  - using unsafe to create an instance of Self
82    //  - use mem::swap to turn the &mut self into a mut self
83    //  - take out the underlying Read+Seek
84    //  - make a new self and seek
85    //
86    // If this issue is fixed use the implementation in
87    // commit: 3bafe32388b4eb7a48c6701e6c65044dc8c555e6
88    #[inline]
89    fn try_seek(&mut self, _: Duration) -> Result<(), SeekError> {
90        Err(SeekError::NotSupported {
91            underlying_source: std::any::type_name::<Self>(),
92        })
93    }
94}
95
96impl<R> Iterator for VorbisDecoder<R>
97where
98    R: Read + Seek,
99{
100    type Item = i16;
101
102    #[inline]
103    fn next(&mut self) -> Option<i16> {
104        if let Some(sample) = self.current_data.get(self.next).copied() {
105            self.next += 1;
106            if self.current_data.is_empty() {
107                if let Ok(Some(data)) = self.stream_reader.read_dec_packet_itl() {
108                    self.current_data = data;
109                    self.next = 0;
110                }
111            }
112            Some(sample)
113        } else {
114            if let Ok(Some(data)) = self.stream_reader.read_dec_packet_itl() {
115                self.current_data = data;
116                self.next = 0;
117            }
118            let sample = self.current_data.get(self.next).copied();
119            self.next += 1;
120            sample
121        }
122    }
123
124    #[inline]
125    fn size_hint(&self) -> (usize, Option<usize>) {
126        (self.current_data.len(), None)
127    }
128}
129
130/// Returns true if the stream contains Vorbis data, then resets it to where it was.
131fn is_vorbis<R>(mut data: R) -> bool
132where
133    R: Read + Seek,
134{
135    let stream_pos = data.stream_position().unwrap();
136
137    if OggStreamReader::new(data.by_ref()).is_err() {
138        data.seek(SeekFrom::Start(stream_pos)).unwrap();
139        return false;
140    }
141
142    data.seek(SeekFrom::Start(stream_pos)).unwrap();
143    true
144}