rodiogaga/decoder/
vorbis.rs

1use std::io::{Read, Seek, SeekFrom};
2use std::time::Duration;
3use std::vec;
4
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::IntoIter<i16>,
16}
17
18impl<R> VorbisDecoder<R>
19where
20    R: Read + Seek,
21{
22    /// Attempts to decode the data as ogg/vorbis.
23    pub fn new(mut data: R) -> Result<VorbisDecoder<R>, R> {
24        if !is_vorbis(data.by_ref()) {
25            return Err(data);
26        }
27
28        let stream_reader = OggStreamReader::new(data).unwrap();
29        Ok(Self::from_stream_reader(stream_reader))
30    }
31    pub fn from_stream_reader(mut stream_reader: OggStreamReader<R>) -> Self {
32        let mut data = match stream_reader.read_dec_packet_itl() {
33            Ok(Some(d)) => d,
34            _ => Vec::new(),
35        };
36
37        // The first packet is always empty, therefore
38        // we need to read the second frame to get some data
39        if let Ok(Some(mut d)) = stream_reader.read_dec_packet_itl() {
40            data.append(&mut d);
41        }
42
43        VorbisDecoder {
44            stream_reader,
45            current_data: data.into_iter(),
46        }
47    }
48    pub fn into_inner(self) -> OggStreamReader<R> {
49        self.stream_reader
50    }
51}
52
53impl<R> Source for VorbisDecoder<R>
54where
55    R: Read + Seek,
56{
57    #[inline]
58    fn current_frame_len(&self) -> Option<usize> {
59        Some(self.current_data.len())
60    }
61
62    #[inline]
63    fn channels(&self) -> u16 {
64        self.stream_reader.ident_hdr.audio_channels as u16
65    }
66
67    #[inline]
68    fn sample_rate(&self) -> u32 {
69        self.stream_reader.ident_hdr.audio_sample_rate
70    }
71
72    #[inline]
73    fn total_duration(&self) -> Option<Duration> {
74        None
75    }
76}
77
78impl<R> Iterator for VorbisDecoder<R>
79where
80    R: Read + Seek,
81{
82    type Item = i16;
83
84    #[inline]
85    fn next(&mut self) -> Option<i16> {
86        if let Some(sample) = self.current_data.next() {
87            if self.current_data.len() == 0 {
88                if let Ok(Some(data)) = self.stream_reader.read_dec_packet_itl() {
89                    self.current_data = data.into_iter();
90                }
91            }
92            Some(sample)
93        } else {
94            if let Ok(Some(data)) = self.stream_reader.read_dec_packet_itl() {
95                self.current_data = data.into_iter();
96            }
97            self.current_data.next()
98        }
99    }
100
101    #[inline]
102    fn size_hint(&self) -> (usize, Option<usize>) {
103        (self.current_data.size_hint().0, None)
104    }
105}
106
107/// Returns true if the stream contains Vorbis data, then resets it to where it was.
108fn is_vorbis<R>(mut data: R) -> bool
109where
110    R: Read + Seek,
111{
112    let stream_pos = data.seek(SeekFrom::Current(0)).unwrap();
113
114    if OggStreamReader::new(data.by_ref()).is_err() {
115        data.seek(SeekFrom::Start(stream_pos)).unwrap();
116        return false;
117    }
118
119    data.seek(SeekFrom::Start(stream_pos)).unwrap();
120    true
121}