1#![cfg(feature = "std")]
2use std::io::Cursor;
14
15use lewton::VorbisError;
16use lewton::audio::AudioReadError;
17use lewton::inside_ogg::OggStreamReader;
18
19use crate::error::Error;
20use crate::guard::guarded;
21use crate::pcm::{Limits, PcmFormat};
22use crate::source::{Source, room};
23
24const FORMAT: &str = "Ogg Vorbis";
25const MAX_PAGE_BYTES: usize = 65_307;
27const FLAGS_AT: usize = 5;
29const GRANULE_AT: usize = 6;
30const SERIAL_AT: usize = 14;
31const LAST_PAGE: u8 = 4;
33
34fn last_page(bytes: &[u8]) -> Option<(u64, u32)> {
37 let tail = &bytes[bytes.len().saturating_sub(MAX_PAGE_BYTES)..];
38 let start = tail.windows(4).rposition(|magic| magic == b"OggS")?;
39 let page = &tail[start..];
40 if page.get(FLAGS_AT)? & LAST_PAGE == 0 {
41 return None;
42 }
43 let granule = page.get(GRANULE_AT..GRANULE_AT + 8)?;
44 let serial = page.get(SERIAL_AT..SERIAL_AT + 4)?;
45 Some((
46 u64::from_le_bytes(granule.try_into().ok()?),
47 u32::from_le_bytes(serial.try_into().ok()?),
48 ))
49}
50
51pub struct VorbisSource<B: AsRef<[u8]>> {
55 reader: OggStreamReader<Cursor<B>>,
56 format: PcmFormat,
57 max_frames: u64,
58 decoded: u64,
60 end: Option<u64>,
62 at: Option<u64>,
65 packet: Vec<i16>,
67 sent: usize,
68 ended: bool,
69 broken: bool,
71}
72
73fn malformed(error: &VorbisError) -> Error {
74 Error::Malformed {
75 format: FORMAT,
76 reason: format!("{error:?}"),
77 }
78}
79
80impl<B: AsRef<[u8]>> VorbisSource<B> {
81 pub fn new(bytes: B, limits: &Limits) -> Result<Self, Error> {
84 guarded(FORMAT, || {
85 let last = last_page(bytes.as_ref());
86 let reader = OggStreamReader::new(Cursor::new(bytes)).map_err(|e| malformed(&e))?;
87 let format = PcmFormat::new(
88 reader.ident_hdr.audio_sample_rate,
89 u32::from(reader.ident_hdr.audio_channels),
90 limits,
91 )?;
92 let serial = reader.stream_serial();
93 let end = last
94 .filter(|(_, last)| *last == serial)
95 .map(|(granule, _)| granule);
96 Ok(Self {
97 reader,
98 format,
99 max_frames: limits.max_frames,
100 decoded: 0,
101 end,
102 at: Some(0),
103 packet: Vec::new(),
104 sent: 0,
105 ended: false,
106 broken: false,
107 })
108 })
109 }
110
111 pub fn comments(&self) -> &[(String, String)] {
113 &self.reader.comment_hdr.comment_list
114 }
115
116 pub fn comment(&self, name: &str) -> Option<&str> {
119 self.comments()
120 .iter()
121 .find(|(key, _)| key.eq_ignore_ascii_case(name))
122 .map(|(_, value)| value.as_str())
123 }
124
125 pub fn vendor(&self) -> &str {
127 &self.reader.comment_hdr.vendor
128 }
129
130 pub fn end_granule(&self) -> Option<u64> {
133 self.end
134 }
135
136 pub fn position(&self) -> Option<u64> {
139 let channels = usize::from(self.format.channels.count());
140 let waiting = ((self.packet.len() - self.sent) / channels) as u64;
141 self.at.map(|at| at.saturating_sub(waiting))
142 }
143
144 pub fn seek_page(&mut self, frame: u64) -> Result<(), Error> {
149 self.check_broken()?;
150 let reader = &mut self.reader;
151 let sought = guarded(FORMAT, || {
152 reader.seek_absgp_pg(frame).map_err(|e| malformed(&e))
153 });
154 self.broken = sought.is_err();
155 sought?;
156 self.packet.clear();
157 self.sent = 0;
158 self.ended = false;
159 self.at = None;
160 Ok(())
161 }
162
163 fn check_broken(&self) -> Result<(), Error> {
164 if self.broken {
165 return Err(Error::Malformed {
166 format: FORMAT,
167 reason: "it failed earlier, and the decoder can't go on from there".to_owned(),
168 });
169 }
170 Ok(())
171 }
172
173 fn next_packet(&mut self) -> Result<(), Error> {
175 let reader = &mut self.reader;
176 let packet = guarded(FORMAT, || match reader.read_dec_packet_itl() {
177 Err(VorbisError::BadAudio(AudioReadError::AudioIsHeader)) => Ok(Some(Vec::new())),
179 other => other.map_err(|e| malformed(&e)),
180 });
181 self.broken = packet.is_err();
182 let Some(mut samples) = packet? else {
183 self.ended = true;
184 return Ok(());
185 };
186 let channels = u64::from(self.format.channels.count());
187 let count = samples.len() as u64;
188 if !count.is_multiple_of(channels) {
189 self.broken = true;
191 return Err(Error::PartialFrame {
192 samples: count,
193 channels: self.format.channels.count(),
194 });
195 }
196 let frames = count / channels;
197 self.decoded += frames;
198 let at = self
200 .at
201 .map_or(self.reader.get_last_absgp(), |at| Some(at + frames));
202 let extra = at
206 .zip(self.end)
207 .map_or(0, |(at, end)| at.saturating_sub(end))
208 .min(frames);
209 samples.truncate(usize::try_from((frames - extra) * channels).unwrap_or(0));
210 self.at = at.map(|at| at - extra);
211 if self.decoded > self.max_frames {
212 self.broken = true;
213 return Err(Error::TooLong {
214 frames: self.decoded,
215 limit: self.max_frames,
216 });
217 }
218 self.packet = samples;
219 self.sent = 0;
220 Ok(())
221 }
222}
223
224impl<B: AsRef<[u8]>> Source for VorbisSource<B> {
225 fn format(&self) -> PcmFormat {
226 self.format
227 }
228
229 fn total_frames(&self) -> Option<u64> {
231 None
232 }
233
234 fn read(&mut self, out: &mut [i16]) -> Result<usize, Error> {
235 let room = room(self.format, out)?;
236 self.check_broken()?;
237 let channels = usize::from(self.format.channels.count());
238 let wanted = room * channels;
239 let mut rest = &mut out[..wanted];
240 while !rest.is_empty() {
241 let left = &self.packet[self.sent..];
242 if left.is_empty() {
243 if self.ended {
244 break;
245 }
246 self.next_packet()?;
247 continue;
248 }
249 let count = rest.len().min(left.len());
250 let (filled, after) = core::mem::take(&mut rest).split_at_mut(count);
251 filled.copy_from_slice(&left[..count]);
252 rest = after;
253 self.sent += count;
254 }
255 Ok((wanted - rest.len()) / channels)
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 fn page(flags: u8, granule: u64, serial: u32) -> Vec<u8> {
265 let mut out = b"OggS\0".to_vec();
266 out.push(flags);
267 out.extend_from_slice(&granule.to_le_bytes());
268 out.extend_from_slice(&serial.to_le_bytes());
269 out.extend_from_slice(&[0; 9]);
270 out
271 }
272
273 #[test]
274 fn the_last_page_is_read_from_its_own_fields() {
275 let mut bytes = page(0, 1, 7);
276 bytes.extend_from_slice(&page(LAST_PAGE, 22_050, 9));
277 assert_eq!(last_page(&bytes), Some((22_050, 9)));
278 }
279
280 #[test]
281 fn a_last_page_without_its_flag_or_cut_short_says_nothing() {
282 assert_eq!(last_page(&page(0, 22_050, 9)), None);
283 assert_eq!(last_page(b""), None);
284 assert_eq!(last_page(b"no page here"), None);
285 let whole = page(LAST_PAGE, 22_050, 9);
286 for cut in 4..18 {
287 assert_eq!(last_page(&whole[..cut]), None, "{cut}");
288 }
289 }
290}