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