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