1#![cfg_attr(not(test), no_std)]
26#![deny(missing_docs)]
27
28mod container;
29pub mod opus;
30
31pub use container::{OggError, Packet, Packets};
32pub use opus::ChannelMapping;
33pub use states::Either;
34
35pub mod prelude {
36 pub use super::{Bitstream, ChannelMapping, Either};
48}
49
50#[derive(Debug, PartialEq)]
52#[doc(hidden)]
53#[non_exhaustive]
54pub enum ErrorValues {
55 UnexpectedSequenceNumber(u32),
56 SequenceNumberMismatch(u32, u32),
57}
58
59impl core::fmt::Display for ErrorValues {
60 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61 use ErrorValues::*;
62 match &self {
63 UnexpectedSequenceNumber(number) => f.write_fmt(format_args!(
64 "unexpected page sequence number in header: {}",
65 number
66 )),
67 SequenceNumberMismatch(previous, current) => f.write_fmt(format_args!(
68 "page sequence numbers are not sequential, previous: {}, current: {}",
69 previous, current,
70 )),
71 }
72 }
73}
74
75#[derive(Debug, PartialEq)]
77pub enum BitstreamError {
78 OggError(OggError),
80 OpusError(opus::OpusError),
82 InvalidOggStream(ErrorValues),
84 InvalidOpusStream(&'static str),
86 UnsupportedOpusVersion(u8),
88 UnsupportedStream(&'static str),
95 NotOpusStream,
101}
102
103impl core::fmt::Display for BitstreamError {
104 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105 use BitstreamError::*;
106 match self {
107 OggError(error) => error.fmt(f),
108 OpusError(error) => error.fmt(f),
109 InvalidOggStream(error) => {
110 f.write_str("invalid ogg stream: ")?;
111 error.fmt(f)
112 }
113 InvalidOpusStream(error) => f.write_str(error),
114 UnsupportedOpusVersion(version) => {
115 f.write_fmt(format_args!("unsupported Opus version: {}", version))
116 }
117 UnsupportedStream(error) => f.write_str(error),
118 NotOpusStream => f.write_str("this is not an Opus stream"),
119 }
120 }
121}
122
123impl core::error::Error for BitstreamError {
124 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
125 use BitstreamError::*;
126 match self {
127 OggError(error) => Some(error),
128 OpusError(error) => Some(error),
129 _ => None,
130 }
131 }
132}
133
134impl From<OggError> for BitstreamError {
135 fn from(error: OggError) -> BitstreamError {
136 match error {
137 OggError::UnsupportedStream(error) => Self::UnsupportedStream(error),
138 OggError::InvalidStream(error) => Self::InvalidOggStream(error),
139 _ => Self::OggError(error),
140 }
141 }
142}
143
144impl From<opus::OpusError> for BitstreamError {
145 fn from(error: opus::OpusError) -> BitstreamError {
146 match error {
147 opus::OpusError::UnsupportedStream(error) => Self::UnsupportedStream(error),
148 opus::OpusError::NotOpusStream => Self::NotOpusStream,
149 _ => Self::OpusError(error),
150 }
151 }
152}
153
154pub type Result<'data, T> = core::result::Result<T, BitstreamError>;
156
157#[derive(Debug)]
159pub struct Bitstream<'data> {
160 data: &'data [u8],
161}
162
163impl<'data> Bitstream<'data> {
164 pub const fn new(data: &'data [u8]) -> Self {
168 Self { data }
169 }
170
171 pub fn reader<'bs>(&'bs self) -> BitstreamReader<'bs, 'data, states::Beginning> {
177 BitstreamReader::<'bs, 'data, states::Beginning>::new(self)
178 }
179}
180
181pub mod states {
182 mod sealed {
185 pub trait Sealed {}
186
187 impl Sealed for super::Beginning {}
188 impl Sealed for super::InStream {}
189 impl Sealed for super::EndOfStream {}
190 }
191
192 #[derive(Debug, PartialEq)]
194 pub struct Beginning;
195 #[derive(Debug, PartialEq)]
197 pub struct InStream {
198 pub bitstream_serial_number: u32,
202 pub page_sequence_number: u32,
204 }
205 #[derive(Debug, PartialEq)]
207 pub struct EndOfStream;
208
209 pub trait ReaderState: sealed::Sealed {}
211
212 impl ReaderState for Beginning {}
213 impl ReaderState for InStream {}
214 impl ReaderState for EndOfStream {}
215
216 #[derive(Debug, PartialEq)]
218 pub enum Either<A, B> {
219 Continued(A),
221 Ended(B),
223 }
224}
225
226use states::{Beginning, EndOfStream, InStream, ReaderState};
227
228pub type EitherHeaderOrEnded<'bs, 'data> = (
230 Either<BitstreamReader<'bs, 'data, InStream>, BitstreamReader<'bs, 'data, EndOfStream>>,
231 opus::OpusHeader,
232);
233
234pub type EitherPacketsOrEnded<'bs, 'data, const BUFFER_SIZE: usize> = (
236 Either<BitstreamReader<'bs, 'data, InStream>, BitstreamReader<'bs, 'data, EndOfStream>>,
237 Packets<'data, BUFFER_SIZE>,
238);
239
240#[derive(Debug, PartialEq)]
242pub struct BitstreamReader<'bs, 'data: 'bs, S: ReaderState> {
243 bitstream: core::marker::PhantomData<&'bs Bitstream<'data>>,
244 remaining: &'data [u8],
245 marker: S,
246}
247
248impl<S: ReaderState> BitstreamReader<'_, '_, S> {
249 pub fn new<'bs, 'data>(
258 bitstream: &'bs Bitstream<'data>,
259 ) -> BitstreamReader<'bs, 'data, Beginning> {
260 BitstreamReader {
261 bitstream: core::marker::PhantomData::<_>,
262 remaining: bitstream.data,
263 marker: Beginning,
264 }
265 }
266}
267
268impl<'bs, 'data> BitstreamReader<'bs, 'data, Beginning> {
269 pub fn read_header(self) -> Result<'data, EitherHeaderOrEnded<'bs, 'data>> {
289 use BitstreamError::*;
290 let BitstreamReader {
291 bitstream,
292 remaining,
293 ..
294 } = self;
295 let (remaining, mut packets) = Packets::<30>::parse(remaining)?;
296 let bitstream_serial_number = packets.bitstream_serial_number();
297 let page_sequence_number = packets.current_page_sequence_number();
298 if page_sequence_number != 0 {
299 return Err(InvalidOggStream(ErrorValues::UnexpectedSequenceNumber(
300 page_sequence_number,
301 )));
302 }
303 if let Some(packet) = packets.next() {
304 let header = opus::OpusHeader::parse(packet.data)?;
305 if header.version > 15 {
306 return Err(UnsupportedOpusVersion(header.version));
307 }
308 if packets.next().is_some() {
309 return Err(InvalidOpusStream("unexpected segment after header"));
310 }
311 let (remaining, last_page) = container::Page::skip(remaining)?;
312 if last_page.bitstream_serial_number() != bitstream_serial_number {
313 return Err(UnsupportedStream(
314 "bitstream serial number changed unexpectedly",
315 ));
316 }
317 Ok((
318 Either::Continued(BitstreamReader {
319 bitstream,
320 remaining,
321 marker: InStream {
322 bitstream_serial_number,
323 page_sequence_number: last_page.page_sequence_number(),
324 },
325 }),
326 header,
327 ))
328 } else {
329 Err(InvalidOpusStream("missing header"))
330 }
331 }
332}
333
334impl<'bs, 'data> BitstreamReader<'bs, 'data, InStream> {
335 pub fn next_packets<const BUFFER_SIZE: usize>(
371 &self,
372 ) -> Result<'data, EitherPacketsOrEnded<'bs, 'data, BUFFER_SIZE>> {
373 use BitstreamError::*;
374 let (remaining, packets) = Packets::parse(self.remaining)?;
375 if self.marker.bitstream_serial_number != packets.bitstream_serial_number() {
376 return Err(UnsupportedStream(
377 "bitstream serial number changed unexpectedly",
378 ));
379 }
380 if packets.current_page_sequence_number() != self.marker.page_sequence_number + 1 {
381 return Err(InvalidOggStream(ErrorValues::SequenceNumberMismatch(
382 self.marker.page_sequence_number,
383 packets.current_page_sequence_number(),
384 )));
385 }
386 if !packets.end_of_stream() {
387 Ok((
388 Either::Continued(BitstreamReader {
389 bitstream: self.bitstream,
390 remaining,
391 marker: InStream {
392 bitstream_serial_number: self.marker.bitstream_serial_number,
393 page_sequence_number: packets.last_page_sequence_number(),
394 },
395 }),
396 packets,
397 ))
398 } else {
399 Ok((
400 Either::Ended(BitstreamReader {
401 bitstream: self.bitstream,
402 remaining,
403 marker: EndOfStream,
404 }),
405 packets,
406 ))
407 }
408 }
409}
410
411impl<'bs, 'data> BitstreamReader<'bs, 'data, EndOfStream> {
412 pub fn has_more(&self) -> bool {
416 !self.remaining.is_empty()
417 }
418
419 pub fn next_reader(self) -> Option<BitstreamReader<'bs, 'data, Beginning>> {
452 if self.has_more() {
453 Some(BitstreamReader {
454 bitstream: core::marker::PhantomData::<_>,
455 remaining: self.remaining,
456 marker: Beginning,
457 })
458 } else {
459 None
460 }
461 }
462}
463
464#[cfg(test)]
465mod test {
466 use super::*;
467 use core::error::Error;
468
469 #[test]
470 fn parse_mono() {
471 const DATA: &[u8] = include_bytes!("test/mono.opus");
472 let bitstream = Bitstream::new(DATA);
473 let reader = bitstream.reader();
474 let (either, header) = reader.read_header().unwrap();
475 assert_eq!(
476 header.channels,
477 opus::ChannelMapping::Family0 { channels: 1 }
478 );
479 if let Either::Continued(reader) = either {
481 let (either, mut packets) = reader.next_packets::<512>().unwrap();
482 let result = packets.next();
483 assert!(result.is_some());
484 if let Either::Ended(reader) = either {
485 assert!(!reader.has_more());
486 assert!(reader.next_reader().is_none());
487 }
488 } else {
489 panic!("Unexpected end of stream in test");
490 }
491 }
492
493 #[test]
494 fn parse_stereo() {
495 const DATA: &[u8] = include_bytes!("test/stereo.opus");
496 let bitstream = Bitstream::new(DATA);
497 let reader = bitstream.reader();
498 let (_either, header) = reader.read_header().unwrap();
499 assert_eq!(
500 header.channels,
501 opus::ChannelMapping::Family0 { channels: 2 }
502 );
503 }
504
505 #[test]
506 fn parse_vorbis() {
507 const DATA: &[u8] = include_bytes!("test/vorbis.ogg");
508 let bitstream = Bitstream::new(DATA);
509 let reader = bitstream.reader();
510 let result = reader.read_header();
511 assert_eq!(result, Err(BitstreamError::NotOpusStream));
512 let error = result.unwrap_err();
513 assert!(error.source().is_none());
514 assert_eq!(error.to_string(), "this is not an Opus stream");
515 }
516
517 #[test]
518 fn parse_invalid_stream() {
519 const DATA: &[u8] = &[0, 0, 0, 0];
520 let bitstream = Bitstream::new(DATA);
521 let reader = bitstream.reader();
522 let result = reader.read_header();
523 assert_eq!(
524 result,
525 Err(BitstreamError::OggError(OggError::NotOggStream))
526 );
527 let error = result.unwrap_err();
528 assert!(error.source().is_some());
529 assert_eq!(error.to_string(), "this is not an ogg stream");
530 }
531
532 #[test]
533 fn parse_unexpected_sequence_number() {
534 let mut data = Vec::from(include_bytes!("test/mono.opus"));
535 data[0x12] = 1;
536 let bitstream = Bitstream::new(&data);
537 let reader = bitstream.reader();
538 let result = reader.read_header();
539 assert_eq!(
540 result,
541 Err(BitstreamError::InvalidOggStream(
542 ErrorValues::UnexpectedSequenceNumber(1)
543 ))
544 );
545 let error = result.unwrap_err();
546 assert_eq!(
547 error.to_string(),
548 "invalid ogg stream: unexpected page sequence number in header: 1"
549 );
550 }
551
552 #[test]
553 fn parse_unsupported_ogg_version() {
554 let mut data = Vec::from(include_bytes!("test/mono.opus"));
555 data[4] = 2;
556 let bitstream = Bitstream::new(&data);
557 let reader = bitstream.reader();
558 let result = reader.read_header();
559 assert_eq!(
560 result,
561 Err(BitstreamError::OggError(OggError::UnsupportedVersion(2)))
562 );
563 let error = result.unwrap_err();
564 assert_eq!(error.to_string(), "unsupported ogg version: 2");
565 }
566
567 #[test]
568 fn parse_unsupported_opus_version() {
569 let mut data = Vec::from(include_bytes!("test/mono.opus"));
570 data[0x24] = 0x10;
571 let bitstream = Bitstream::new(&data);
572 let reader = bitstream.reader();
573 let result = reader.read_header();
574 assert_eq!(result, Err(BitstreamError::UnsupportedOpusVersion(16)));
575 let error = result.unwrap_err();
576 assert_eq!(error.to_string(), "unsupported Opus version: 16");
577 }
578}