Skip to main content

adts_reader/
lib.rs

1//! A Rust parser for the [Audio Data Transport Stream](https://wiki.multimedia.cx/index.php/ADTS)
2//! framing format often used to carry encoded AAC audio data.
3//!
4//! [`AdtsHeader`](struct.AdtsHeader.html) is the primary type provided by this crate.
5//!
6//! Given a buffer containing some number of ADTS frames, the first frame may be inspected by
7//! constructing a header instance with,
8//!
9//! ```rust
10//! use adts_reader::AdtsHeader;
11//! # let buf: Vec<u8> = vec!(0xff, 0xf0, 0, 0, 1, 0x20, 0, 0, 0);
12//! // let buf = ...;
13//! match AdtsHeader::from_bytes(&buf) {
14//!     Ok(header) => println!("length (headers+payload) is {}", header.frame_length()),
15//!     Err(e) => panic!("failed to read header: {:?}", e),
16//! }
17//! ```
18//!
19//! # Unsupported
20//!
21//!  - Resynchronising `AdtsParser` after encountering bitstream error (we could search for
22//!    sync-word)
23//!  - Copyright identifiers (I don't have any example bitstreams to try)
24//!  - CRC handling (probably needs to be implemented as part of AAC bitstream parsing)
25
26#![forbid(unsafe_code)]
27#![deny(rust_2018_idioms, future_incompatible)]
28
29// TODO: might be better to implement AdtsParser as an iterator, rather then doing callbacks into a
30// trait implementation -- it looked hard to implement though!
31
32pub use mpeg4_audio_const::{
33    AudioObjectType, ChannelConfiguration, SamplingFrequencyIndex, SamplingFrequencyIndexError,
34};
35use std::fmt;
36
37#[derive(Debug)]
38pub enum AdtsHeaderError {
39    /// Indicates that the given buffer did not start with the required sequence of 12 '1'-bits
40    /// (`0xfff`).
41    BadSyncWord(u16),
42    NotEnoughData {
43        expected: usize,
44        actual: usize,
45    },
46    /// The frame_length field stored in the ADTS header is invalid as it holds a value smaller
47    /// than the size of the header fields
48    BadFrameLength {
49        minimum: usize,
50        actual: usize,
51    },
52    /// The sampling_frequency_index field holds a value that is not a valid index
53    BadSamplingFrequency(SamplingFrequencyIndexError),
54}
55
56/// Error indicating that not enough data was provided to `AdtsHeader` to be able to extract the
57/// whole ADTS payload following the header fields.
58#[derive(Debug, PartialEq)]
59pub struct PayloadError {
60    pub expected: usize,
61    pub actual: usize,
62}
63
64#[derive(Debug, PartialEq)]
65pub enum MpegVersion {
66    Mpeg2,
67    Mpeg4,
68}
69
70#[derive(Debug, PartialEq)]
71pub enum ProtectionIndicator {
72    CrcPresent,
73    CrcAbsent,
74}
75
76#[derive(Debug, PartialEq)]
77pub enum Originality {
78    Original,
79    Copy,
80}
81
82#[derive(Debug, PartialEq, Clone, Copy)]
83pub enum BufferFullness {
84    /// Variable bitrate; buffer fullness is not applicable (raw value 0x7FF)
85    Vbr,
86    /// Constant bitrate with the given buffer fullness value
87    Cbr(u16),
88}
89
90#[derive(Debug, PartialEq)]
91pub enum CopyrightIdentificationStart {
92    Start,
93    Other,
94}
95
96/// Extract information for a single ADTS frame from the start of the given byte buffer .
97pub struct AdtsHeader<'buf> {
98    buf: &'buf [u8],
99}
100impl<'buf> AdtsHeader<'buf> {
101    /// Construct an instance by borrowing the given byte buffer.  The given buffer may be longer
102    /// then the ADTS frame, in which case the rest of the buffer is ignored.
103    ///
104    ///
105    /// Note that this function returns `Err` if there is not enough data to parse the whole
106    /// header, but it can return `Ok` even if there is not enough data in the given buffer to hold
107    /// the whole of the payload that the header indicates should be present (however _if_ there is
108    /// not enough data to hold the payload, then [`payload()`](#method.payload) will return
109    /// `None`).
110    pub fn from_bytes(buf: &'buf [u8]) -> Result<AdtsHeader<'buf>, AdtsHeaderError> {
111        assert!(!buf.is_empty());
112        let header_len = 7;
113        Self::check_len(header_len, buf.len())?;
114        let header = AdtsHeader { buf };
115        if header.sync_word() != 0xfff {
116            return Err(AdtsHeaderError::BadSyncWord(header.sync_word()));
117        }
118        let crc_len = 2;
119        if header.protection() == ProtectionIndicator::CrcPresent {
120            Self::check_len(header_len + crc_len, buf.len())?;
121        }
122        SamplingFrequencyIndex::try_from(header.buf[2] >> 2 & 0b1111)
123            .map_err(AdtsHeaderError::BadSamplingFrequency)?;
124        if header.frame_length() < header.header_length() {
125            return Err(AdtsHeaderError::BadFrameLength {
126                actual: header.frame_length() as usize,
127                minimum: header.header_length() as usize,
128            });
129        }
130        Ok(header)
131    }
132
133    fn check_len(expected: usize, actual: usize) -> Result<(), AdtsHeaderError> {
134        if actual < expected {
135            Err(AdtsHeaderError::NotEnoughData { expected, actual })
136        } else {
137            Ok(())
138        }
139    }
140
141    fn header_length(&self) -> u16 {
142        let fixed_len = 7;
143        if self.protection() == ProtectionIndicator::CrcPresent {
144            fixed_len + 2
145        } else {
146            fixed_len
147        }
148    }
149
150    fn sync_word(&self) -> u16 {
151        u16::from(self.buf[0]) << 4 | u16::from(self.buf[1] >> 4)
152    }
153
154    pub fn mpeg_version(&self) -> MpegVersion {
155        if self.buf[1] & 0b0000_1000 != 0 {
156            MpegVersion::Mpeg2
157        } else {
158            MpegVersion::Mpeg4
159        }
160    }
161
162    pub fn protection(&self) -> ProtectionIndicator {
163        if self.buf[1] & 0b0000_0001 != 0 {
164            ProtectionIndicator::CrcAbsent
165        } else {
166            ProtectionIndicator::CrcPresent
167        }
168    }
169
170    // Indicates what type of AAC data this stream contains
171    pub fn audio_object_type(&self) -> AudioObjectType {
172        match self.buf[2] & 0b1100_0000 {
173            0b0000_0000 => AudioObjectType::AAC_MAIN,
174            0b0100_0000 => AudioObjectType::AAC_LC,
175            0b1000_0000 => AudioObjectType::AAC_SSR,
176            0b1100_0000 => AudioObjectType::AAC_LTP,
177            v => panic!("impossible value {:#b}", v),
178        }
179    }
180
181    pub fn sampling_frequency(&self) -> SamplingFrequencyIndex {
182        SamplingFrequencyIndex::new(self.buf[2] >> 2 & 0b1111)
183    }
184
185    /// either 1 or 0
186    pub fn private_bit(&self) -> u8 {
187        (self.buf[2] >> 1) & 1
188    }
189
190    pub fn channel_configuration(&self) -> ChannelConfiguration {
191        ChannelConfiguration::new(self.buf[2] << 2 & 0b0100 | self.buf[3] >> 6)
192    }
193
194    pub fn originality(&self) -> Originality {
195        if self.buf[3] & 0b0010_0000 != 0 {
196            Originality::Original
197        } else {
198            Originality::Copy
199        }
200    }
201
202    /// either 1 or 0
203    pub fn home(&self) -> u8 {
204        self.buf[3] >> 4 & 1
205    }
206
207    /// either 1 or 0
208    pub fn copyright_identification_bit(&self) -> u8 {
209        self.buf[3] >> 3 & 1
210    }
211
212    pub fn copyright_identification_start(&self) -> CopyrightIdentificationStart {
213        if self.buf[3] & 0b0000_0100 != 0 {
214            CopyrightIdentificationStart::Start
215        } else {
216            CopyrightIdentificationStart::Other
217        }
218    }
219
220    /// length of this frame, including the length of the header.
221    pub fn frame_length(&self) -> u16 {
222        u16::from(self.buf[3] & 0b11) << 11
223            | u16::from(self.buf[4]) << 3
224            | u16::from(self.buf[5]) >> 5
225    }
226
227    /// Calculates the length of the frame payload from the `frame_length` header value, and the
228    /// total size of headers in this frame -- returning `None` if the `frame_length` header had a
229    /// value too small to even include the headers
230    pub fn payload_length(&self) -> Option<u16> {
231        let diff = self.frame_length() as i16 - self.header_length() as i16;
232        if diff >= 0 {
233            Some(diff as u16)
234        } else {
235            None
236        }
237    }
238
239    pub fn adts_buffer_fullness(&self) -> BufferFullness {
240        let raw = u16::from(self.buf[5] & 0b00011111) << 6 | u16::from(self.buf[6]) >> 2;
241        if raw == 0x7FF {
242            BufferFullness::Vbr
243        } else {
244            BufferFullness::Cbr(raw)
245        }
246    }
247
248    /// Gives the 16-bit cyclic redundancy check value stored in this frame header, or `None` if
249    /// the header does not supply a CRC.
250    ///
251    /// NB the implementation doesn't currently check that the CRC is correct
252    pub fn crc(&self) -> Option<u16> {
253        match self.protection() {
254            ProtectionIndicator::CrcAbsent => None,
255            ProtectionIndicator::CrcPresent => {
256                Some(u16::from(self.buf[7]) << 8 | u16::from(self.buf[8]))
257            }
258        }
259    }
260
261    /// The number of data blocks in the frame, a value between 1 and 4 inclusive.
262    ///
263    /// (Note that in the serialised ADTS data stores the _number of blocks - 1_.  This method
264    /// returns the actual number of blocks by adding one to the serialised value.)
265    ///
266    /// Most streams store a single block per ADTS frame
267    pub fn number_of_raw_data_blocks_in_frame(&self) -> u8 {
268        (self.buf[6] & 0b11) + 1
269    }
270
271    /// The payload AAC data inside this ADTS frame
272    pub fn payload(&self) -> Result<&'buf [u8], PayloadError> {
273        let len = self.frame_length() as usize;
274        if self.buf.len() < len {
275            Err(PayloadError {
276                expected: len,
277                actual: self.buf.len(),
278            })
279        } else {
280            Ok(&self.buf[self.header_length() as usize..len])
281        }
282    }
283}
284impl<'buf> fmt::Debug for AdtsHeader<'buf> {
285    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
286        f.debug_struct("AdtsHeader")
287            .field("mpeg_version", &self.mpeg_version())
288            .field("protection", &self.protection())
289            .field("audio_object_type", &self.audio_object_type())
290            .field("sampling_frequency", &self.sampling_frequency())
291            .field("private_bit", &self.private_bit())
292            .field("channel_configuration", &self.channel_configuration())
293            .field("originality", &self.originality())
294            .field("home", &self.home())
295            .field(
296                "copyright_identification_bit",
297                &self.copyright_identification_bit(),
298            )
299            .field(
300                "copyright_identification_start",
301                &self.copyright_identification_start(),
302            )
303            .field("frame_length", &self.frame_length())
304            .field("adts_buffer_fullness", &self.adts_buffer_fullness())
305            .field("crc", &self.crc())
306            .field(
307                "number_of_raw_data_blocks_in_frame",
308                &self.number_of_raw_data_blocks_in_frame(),
309            )
310            .finish()
311    }
312}
313
314#[derive(Debug, PartialEq)]
315pub enum CopyrightIdErr {
316    TooFewBits,
317    TooManyBits,
318}
319
320#[derive(Debug, PartialEq)]
321pub struct CopyrightIdentification {
322    pub copyright_identifier: u8,
323    pub copyright_number: u64,
324}
325
326#[derive(PartialEq)]
327enum AdtsState {
328    Start,
329    Incomplete,
330    Error,
331}
332
333#[derive(Debug, PartialEq)]
334pub enum AdtsParseError {
335    BadSyncWord,
336    BadFrameLength,
337    BadSamplingFrequency,
338}
339
340/// Trait to be implemented by types that wish to consume the ADTS data produced by [`AdtsParser`](struct.AdtsParser.html).
341///
342/// # Example
343///
344/// ```rust
345/// use adts_reader::*;
346///
347/// struct MyConsumer { }
348/// impl AdtsConsumer for MyConsumer {
349///     fn new_config(&mut self, mpeg_version: MpegVersion, protection: ProtectionIndicator, aot: AudioObjectType, freq: SamplingFrequencyIndex, private_bit: u8, channels: ChannelConfiguration, originality: Originality, home: u8) {
350///         println!("Configuration {:?} {:?} {:?}", aot, freq, channels);
351///     }
352///     fn payload(&mut self, buffer_fullness: BufferFullness, number_of_blocks: u8, buf: &[u8]) {
353///         println!(" - frame of {} bytes", buf.len());
354///     }
355///     fn error(&mut self, err: AdtsParseError) {
356///         println!(" - oops: {:?}", err);
357///     }
358/// }
359///
360/// let consumer = MyConsumer { };
361/// let parser = AdtsParser::new(consumer);
362/// ```
363pub trait AdtsConsumer {
364    /// Called when a new configuration is found within the ADTS bitstream
365    ///
366    /// An ADTS bitstream should have the same configuration throughout, so this would usually just
367    /// be called once at the beginning of the stream.  The audio configuration header values do
368    /// however appear in every frame (so that the bitstream format can support seeking, not that
369    /// this implementation helps there) and so it would be possible for a malformed bitstream to
370    /// signal a configuration change part way through.
371    fn new_config(
372        &mut self,
373        mpeg_version: MpegVersion,
374        protection: ProtectionIndicator,
375        aot: AudioObjectType,
376        freq: SamplingFrequencyIndex,
377        private_bit: u8,
378        channels: ChannelConfiguration,
379        originality: Originality,
380        home: u8,
381    );
382
383    /// called with the ADTS frame payload, and frame-specific header values
384    fn payload(&mut self, buffer_fullness: BufferFullness, number_of_blocks: u8, buf: &[u8]);
385
386    /// called if AdtsParser encounters an error in the ADTS bitstream.
387    fn error(&mut self, err: AdtsParseError);
388}
389
390/// Find ADTS frames within provided buffers of data, announcing audio configuration as it is
391/// discovered (normally just once at the start, but possibly changing during the stream if the
392/// stream is malformed).
393///
394/// Does not currently try to handle re-synchronise with the ADTS bitstream on encountering bad
395/// data.
396pub struct AdtsParser<C>
397where
398    C: AdtsConsumer,
399{
400    pub consumer: C,
401    current_config: [u8; 4],
402    state: AdtsState,
403    incomplete_frame: Vec<u8>,
404    desired_data_len: Option<usize>,
405}
406impl<C> AdtsParser<C>
407where
408    C: AdtsConsumer,
409{
410    pub fn new(consumer: C) -> AdtsParser<C> {
411        AdtsParser {
412            consumer,
413            current_config: [0; 4],
414            state: AdtsState::Start,
415            incomplete_frame: vec![],
416            desired_data_len: None,
417        }
418    }
419
420    fn is_new_config(&self, header_data: &[u8]) -> bool {
421        self.current_config[0..3] != header_data[0..3]
422            || self.current_config[3] != header_data[3] & 0b1111_0000
423    }
424
425    fn remember(&mut self, remaining_data: &[u8], desired_data_len: usize) {
426        self.state = AdtsState::Incomplete;
427        self.incomplete_frame.clear();
428        self.incomplete_frame.extend_from_slice(remaining_data);
429        self.desired_data_len = Some(desired_data_len);
430    }
431
432    /// Initialize or re-initialize parser state.  Call this function before processing a group of
433    /// ADTS frames to ensure that any error state due to processing an earlier group of ADTS
434    /// frames is cleared.
435    pub fn start(&mut self) {
436        if self.state == AdtsState::Incomplete {
437            self.incomplete_frame.clear();
438            self.desired_data_len = None;
439            eprintln!("ADTS: incomplete data buffer dropped by call to start()");
440        }
441        self.state = AdtsState::Start;
442    }
443
444    /// Extracts information about each ADTS frame in the given buffer, which is passed to the
445    /// `AdtsConsumer` implementation supplied at construction time.
446    ///
447    /// If the given buffer ends part-way through an ADTS frame, the remaining unconsumed data
448    /// will be buffered inside this AdtsParser instance, and the rest of the ADTS frame may be
449    /// passed in another buffer in the next call to this method.
450    pub fn push(&mut self, adts_buf: &[u8]) {
451        let mut buf = adts_buf;
452        match self.state {
453            AdtsState::Error => return, // TODO: resync to recover from bitstream errors
454            AdtsState::Incomplete => {
455                // on last call to push(), the end of the adts_buf held the start of an ADTS
456                // frame, and we copied that data into incomplete_buffer, so now lets try to add
457                // enough initial bytes from the adts_buf given to this call to get a complete
458                // frame
459                loop {
460                    let bytes_needed_to_complete_frame =
461                        self.desired_data_len.unwrap() - self.incomplete_frame.len();
462                    if buf.len() < bytes_needed_to_complete_frame {
463                        self.incomplete_frame.extend_from_slice(buf);
464                        return;
465                    }
466                    self.incomplete_frame
467                        .extend_from_slice(&buf[..bytes_needed_to_complete_frame]);
468                    buf = &buf[bytes_needed_to_complete_frame..];
469                    let mut still_more = false; // TODO: this is horrible
470                    match AdtsHeader::from_bytes(&self.incomplete_frame[..]) {
471                        Ok(header) => {
472                            if (header.frame_length() as usize) > self.incomplete_frame.len() {
473                                self.desired_data_len = Some(header.frame_length() as usize);
474                                still_more = true;
475                            } else {
476                                if self.is_new_config(&self.incomplete_frame[..]) {
477                                    Self::push_config(
478                                        &mut self.current_config,
479                                        &mut self.consumer,
480                                        &header,
481                                        &self.incomplete_frame[..],
482                                    );
483                                }
484                                Self::push_payload(&mut self.consumer, header);
485                                self.state = AdtsState::Start;
486                            }
487                        }
488                        Err(e) => match e {
489                            AdtsHeaderError::BadSyncWord { .. } => {
490                                self.state = AdtsState::Error;
491                                self.consumer.error(AdtsParseError::BadSyncWord);
492                                return;
493                            }
494                            AdtsHeaderError::BadFrameLength { .. } => {
495                                self.state = AdtsState::Error;
496                                self.consumer.error(AdtsParseError::BadFrameLength);
497                                return;
498                            }
499                            AdtsHeaderError::BadSamplingFrequency(_) => {
500                                self.state = AdtsState::Error;
501                                self.consumer.error(AdtsParseError::BadSamplingFrequency);
502                                return;
503                            }
504                            AdtsHeaderError::NotEnoughData { expected, .. } => {
505                                self.desired_data_len = Some(expected);
506                                still_more = true;
507                            }
508                        },
509                    }
510                    if !still_more {
511                        break;
512                    }
513                }
514            }
515            AdtsState::Start => (),
516        };
517        let mut pos = 0;
518        while pos < buf.len() {
519            let remaining_data = &buf[pos..];
520            let h = match AdtsHeader::from_bytes(remaining_data) {
521                Ok(header) => header,
522                Err(e) => {
523                    self.state = AdtsState::Error;
524                    match e {
525                        AdtsHeaderError::BadSyncWord { .. } => {
526                            self.consumer.error(AdtsParseError::BadSyncWord)
527                        }
528                        AdtsHeaderError::BadFrameLength { .. } => {
529                            self.consumer.error(AdtsParseError::BadFrameLength);
530                            return;
531                        }
532                        AdtsHeaderError::NotEnoughData { expected, .. } => {
533                            self.remember(remaining_data, expected);
534                            return;
535                        }
536                        AdtsHeaderError::BadSamplingFrequency(_) => {
537                            self.consumer.error(AdtsParseError::BadSamplingFrequency);
538                        }
539                    }
540                    return;
541                }
542            };
543            let new_pos = pos + h.frame_length() as usize;
544            if new_pos > buf.len() {
545                self.remember(remaining_data, h.frame_length() as usize);
546                return;
547            }
548            if self.is_new_config(remaining_data) {
549                Self::push_config(
550                    &mut self.current_config,
551                    &mut self.consumer,
552                    &h,
553                    remaining_data,
554                );
555            }
556            Self::push_payload(&mut self.consumer, h);
557            self.state = AdtsState::Start;
558            pos = new_pos;
559        }
560    }
561
562    fn push_config(
563        current_config: &mut [u8; 4],
564        consumer: &mut C,
565        h: &AdtsHeader<'_>,
566        frame_buffer: &[u8],
567    ) {
568        current_config[0..3].copy_from_slice(&frame_buffer[0..3]);
569        current_config[3] = frame_buffer[3] & 0b1111_0000;
570        consumer.new_config(
571            h.mpeg_version(),
572            h.protection(),
573            h.audio_object_type(),
574            h.sampling_frequency(),
575            h.private_bit(),
576            h.channel_configuration(),
577            h.originality(),
578            h.home(),
579        );
580    }
581
582    fn push_payload(consumer: &mut C, h: AdtsHeader<'_>) {
583        match h.payload() {
584            Ok(payload) => {
585                consumer.payload(
586                    h.adts_buffer_fullness(),
587                    h.number_of_raw_data_blocks_in_frame(),
588                    payload,
589                );
590            }
591            Err(PayloadError { expected, actual }) => {
592                // since we checked we had enough data for the whole frame above, this must be
593                // a bug,
594                panic!(
595                    "Unexpected payload size mismatch: expected {}, actual size {}",
596                    expected, actual
597                );
598            }
599        }
600    }
601}
602
603#[cfg(test)]
604mod tests {
605    use super::*;
606    use bitstream_io::{BigEndian, BitWrite, BitWriter, BE};
607    use std::io;
608
609    fn make_test_data<F>(builder: F) -> Vec<u8>
610    where
611        F: Fn(BitWriter<&mut Vec<u8>, BE>) -> Result<(), io::Error>,
612    {
613        let mut data: Vec<u8> = Vec::new();
614        builder(BitWriter::endian(&mut data, BigEndian)).unwrap();
615        data
616    }
617
618    fn write_frame(w: &mut BitWriter<&mut Vec<u8>, BE>) -> Result<(), io::Error> {
619        w.write(12, 0xfff)?; // sync_word
620        w.write(1, 0)?; // mpeg_version
621        w.write(2, 0)?; // layer
622        w.write(1, 1)?; // protection_absent
623        w.write(2, 0)?; // object_type
624        w.write(4, 0b0011)?; // sampling_frequency_index
625        w.write(1, 1)?; // private_bit
626        w.write(3, 2)?; // channel_configuration
627        w.write(1, 1)?; // original_copy
628        w.write(1, 0)?; // home
629        w.write(1, 0)?; // copyright_identification_bit
630        w.write(1, 1)?; // copyright_identification_start
631        w.write(13, 8)?; // frame_length
632        w.write(11, 123)?; // adts_buffer_fullness
633        w.write(2, 0)?; // number_of_raw_data_blocks_in_frame
634        w.write(8, 0b10000001) // 1 byte of payload data
635    }
636
637    #[test]
638    fn no_crc() {
639        let header_data = make_test_data(|mut w| write_frame(&mut w));
640        let header = AdtsHeader::from_bytes(&header_data[..]).unwrap();
641        assert_eq!(header.mpeg_version(), MpegVersion::Mpeg4);
642        assert_eq!(header.protection(), ProtectionIndicator::CrcAbsent);
643        assert_eq!(header.audio_object_type(), AudioObjectType::AAC_MAIN);
644        assert_eq!(
645            header.sampling_frequency(),
646            SamplingFrequencyIndex::FREQ_48000
647        );
648        assert_eq!(header.sampling_frequency().freq(), Some(48000));
649        assert_eq!(header.private_bit(), 1);
650        assert_eq!(header.channel_configuration(), ChannelConfiguration::STEREO);
651        assert_eq!(header.originality(), Originality::Original);
652        assert_eq!(header.home(), 0);
653        assert_eq!(header.copyright_identification_bit(), 0);
654        assert_eq!(
655            header.copyright_identification_start(),
656            CopyrightIdentificationStart::Start
657        );
658        assert_eq!(header.frame_length(), 8);
659        assert_eq!(header.payload_length(), Some(8 - 7));
660        assert_eq!(header.adts_buffer_fullness(), BufferFullness::Cbr(123));
661        assert_eq!(header.number_of_raw_data_blocks_in_frame(), 1);
662        assert_eq!(header.payload(), Ok(&[0b10000001][..]));
663    }
664
665    #[test]
666    fn large_buffer_fullness() {
667        let header_data = make_test_data(|mut w| {
668            w.write(12, 0xfff)?; // sync_word
669            w.write(1, 0)?; // mpeg_version
670            w.write(2, 0)?; // layer
671            w.write(1, 1)?; // protection_absent
672            w.write(2, 0)?; // object_type
673            w.write(4, 0b0011)?; // sampling_frequency_index
674            w.write(1, 0)?; // private_bit
675            w.write(3, 1)?; // channel_configuration
676            w.write(1, 0)?; // original_copy
677            w.write(1, 0)?; // home
678            w.write(1, 0)?; // copyright_identification_bit
679            w.write(1, 0)?; // copyright_identification_start
680            w.write(13, 8)?; // frame_length
681            w.write(11, 0x7FF)?; // adts_buffer_fullness (max 11-bit value = 2047)
682            w.write(2, 0)?; // number_of_raw_data_blocks_in_frame
683            w.write(8, 0x00) // 1 byte of payload data
684        });
685        let header = AdtsHeader::from_bytes(&header_data[..]).unwrap();
686        assert_eq!(header.adts_buffer_fullness(), BufferFullness::Vbr);
687    }
688
689    struct MockConsumer {
690        seq: usize,
691        payload_seq: usize,
692        payload_size: Option<usize>,
693    }
694    impl MockConsumer {
695        pub fn new() -> MockConsumer {
696            MockConsumer {
697                seq: 0,
698                payload_seq: 0,
699                payload_size: None,
700            }
701        }
702        pub fn assert_seq(&mut self, expected: usize) {
703            assert_eq!(expected, self.seq);
704            self.seq += 1;
705        }
706    }
707    impl AdtsConsumer for MockConsumer {
708        // TODO: assertions are terribly brittle
709        fn new_config(
710            &mut self,
711            mpeg_version: MpegVersion,
712            _protection: ProtectionIndicator,
713            _aot: AudioObjectType,
714            _freq: SamplingFrequencyIndex,
715            _private_bit: u8,
716            _channels: ChannelConfiguration,
717            _originality: Originality,
718            _home: u8,
719        ) {
720            self.assert_seq(0);
721            assert_eq!(mpeg_version, MpegVersion::Mpeg4);
722        }
723        fn payload(&mut self, _buffer_fullness: BufferFullness, _number_of_blocks: u8, buf: &[u8]) {
724            self.payload_seq += 1;
725            let new_payload_seq = self.payload_seq;
726            self.assert_seq(new_payload_seq);
727            self.payload_size = Some(buf.len());
728        }
729        fn error(&mut self, err: AdtsParseError) {
730            panic!("no errors expected in bitstream: {:?}", err);
731        }
732    }
733
734    #[test]
735    fn parser() {
736        let header_data = make_test_data(|mut w| {
737            write_frame(&mut w)?;
738            write_frame(&mut w)
739        });
740        for split in 0..header_data.len() {
741            let mut parser = AdtsParser::new(MockConsumer::new());
742            let (head, tail) = header_data.split_at(split);
743            parser.push(head);
744            parser.push(tail);
745            assert_eq!(2, parser.consumer.payload_seq);
746            assert_eq!(Some(1), parser.consumer.payload_size);
747        }
748    }
749
750    struct CountingConsumer {
751        payload_count: usize,
752    }
753    impl AdtsConsumer for CountingConsumer {
754        fn new_config(
755            &mut self,
756            _: MpegVersion,
757            _: ProtectionIndicator,
758            _: AudioObjectType,
759            _: SamplingFrequencyIndex,
760            _: u8,
761            _: ChannelConfiguration,
762            _: Originality,
763            _: u8,
764        ) {
765        }
766        fn payload(&mut self, _: BufferFullness, _: u8, _: &[u8]) {
767            self.payload_count += 1;
768        }
769        fn error(&mut self, err: AdtsParseError) {
770            panic!("no errors expected: {:?}", err);
771        }
772    }
773
774    #[test]
775    fn crc_frame_split_across_pushes() {
776        // A CRC-protected frame has a 9-byte header (7 fixed + 2 CRC).
777        // Split so the Incomplete path gets exactly 7 bytes first (triggering
778        // NotEnoughData for the CRC bytes), then runs out of input before
779        // accumulating the remaining 2 CRC bytes.  Bug #5 would set state to
780        // Error here, causing the third push() to silently drop data.
781        let frame_data = make_test_data(|mut w| {
782            w.write(12, 0xfff)?; // sync_word
783            w.write(1, 0)?; // mpeg_version
784            w.write(2, 0)?; // layer
785            w.write(1, 0)?; // protection_absent = 0 → CRC present
786            w.write(2, 0)?; // object_type
787            w.write(4, 0b0011)?; // sampling_frequency_index
788            w.write(1, 0)?; // private_bit
789            w.write(3, 2)?; // channel_configuration
790            w.write(1, 0)?; // original_copy
791            w.write(1, 0)?; // home
792            w.write(1, 0)?; // copyright_identification_bit
793            w.write(1, 0)?; // copyright_identification_start
794            w.write(13, 10)?; // frame_length (9 header + 1 payload)
795            w.write(11, 100)?; // adts_buffer_fullness
796            w.write(2, 0)?; // number_of_raw_data_blocks_in_frame
797            w.write(16, 0)?; // CRC
798            w.write(8, 0xAB) // 1 byte of payload
799        });
800
801        // Push 1: 5 bytes → not enough for header (need 7), enters Incomplete
802        // Push 2: 2 bytes → completes 7, but CRC needs 9 → NotEnoughData in
803        //         Incomplete loop; no more input bytes → returns
804        // Push 3: remaining bytes → should still work (not Error state)
805        let mut parser = AdtsParser::new(CountingConsumer { payload_count: 0 });
806        parser.push(&frame_data[..5]);
807        parser.push(&frame_data[5..7]);
808        assert_eq!(0, parser.consumer.payload_count, "no payload yet");
809        parser.push(&frame_data[7..]);
810        assert_eq!(
811            1, parser.consumer.payload_count,
812            "payload should have been delivered"
813        );
814    }
815
816    #[test]
817    fn too_short() {
818        let header_data = make_test_data(|mut w| write_frame(&mut w));
819        let mut parser = AdtsParser::new(MockConsumer::new());
820        parser.push(&header_data[..5]);
821        parser.push(&header_data[5..7]);
822    }
823
824    #[test]
825    fn bad_sampling_frequency() {
826        // sampling_frequency_index = 0xf (escape value) should produce an error, not panic
827        let header_data = make_test_data(|mut w| {
828            w.write(12, 0xfff)?; // sync_word
829            w.write(1, 0)?; // mpeg_version
830            w.write(2, 0)?; // layer
831            w.write(1, 1)?; // protection_absent
832            w.write(2, 0)?; // object_type
833            w.write(4, 0b1111)?; // sampling_frequency_index = 0xf (invalid)
834            w.write(1, 0)?; // private_bit
835            w.write(3, 1)?; // channel_configuration
836            w.write(1, 0)?; // original_copy
837            w.write(1, 0)?; // home
838            w.write(1, 0)?; // copyright_identification_bit
839            w.write(1, 0)?; // copyright_identification_start
840            w.write(13, 8)?; // frame_length
841            w.write(11, 0)?; // adts_buffer_fullness
842            w.write(2, 0)?; // number_of_raw_data_blocks_in_frame
843            w.write(8, 0x00) // 1 byte of payload
844        });
845        assert!(matches!(
846            AdtsHeader::from_bytes(&header_data),
847            Err(AdtsHeaderError::BadSamplingFrequency(_))
848        ));
849    }
850}