javelin_codec/aac/
config.rs

1use bytes::Buf;
2use crate::{Error, Result};
3
4
5/// See [MPEG-4 Audio Object Types][audio_object_types]
6///
7/// [audio_object_types]: https://en.wikipedia.org/wiki/MPEG-4_Part_3#MPEG-4_Audio_Object_Types
8#[allow(clippy::enum_variant_names, dead_code)]
9#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
10pub enum AudioObjectType {
11    AacMain = 1,
12    AacLowComplexity = 2,
13    AacScalableSampleRate = 3,
14    AacLongTermPrediction = 4
15}
16
17impl AudioObjectType {
18    pub fn try_from_u8(value: u8) -> Result<Self> {
19        let val = match  value {
20            1 => AudioObjectType::AacMain,
21            2 => AudioObjectType::AacLowComplexity,
22            3 => AudioObjectType::AacScalableSampleRate,
23            4 => AudioObjectType::AacLongTermPrediction,
24            _ => return Err(Error::from("Unsupported audio object type")),
25        };
26
27        Ok(val)
28    }
29}
30
31
32/// Bits | Description
33/// ---- | -----------
34/// 5    | Audio object type
35/// 4    | Sampling frequency index
36/// 4    | Channel configuration
37/// 1    | Frame length flag
38/// 1    | Depends on core coder
39/// 1    | Extension flag
40///
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct AudioSpecificConfiguration {
43    pub object_type: AudioObjectType,
44    pub sampling_frequency_index: u8,
45    pub channel_configuration: u8,
46    pub frame_length_flag: bool,
47    pub depends_on_core_coder: bool,
48    pub extension_flag: bool,
49}
50
51impl AudioSpecificConfiguration {
52    pub fn try_from_buf<B>(buf: &mut B) -> Result<Self>
53        where B: Buf
54    {
55        let x = buf.get_u8();
56        let y = buf.get_u8();
57
58        let object_type = AudioObjectType::try_from_u8((x & 0xF8) >> 3)?;
59        let sampling_frequency_index = ((x & 0x07) << 1) | (y >> 7);
60        let channel_configuration = (y >> 3) & 0x0F;
61
62        let frame_length_flag = (y & 0x04) == 0x04;
63        let depends_on_core_coder = (y & 0x02) == 0x02;
64        let extension_flag = (y & 0x01) == 0x01;
65
66        Ok(Self {
67            object_type,
68            sampling_frequency_index,
69            channel_configuration,
70            frame_length_flag,
71            depends_on_core_coder,
72            extension_flag,
73        })
74    }
75}
76
77
78#[cfg(test)]
79mod tests {
80    use bytes::{Bytes, IntoBuf};
81    use super::*;
82
83    #[test]
84    fn can_parse_sequence_header() {
85        let expected = AudioSpecificConfiguration {
86            object_type: AudioObjectType::AacLowComplexity,
87            sampling_frequency_index: 4,
88            channel_configuration: 2,
89            frame_length_flag: false,
90            depends_on_core_coder: false,
91            extension_flag: false,
92        };
93
94        let raw = Bytes::from_static(&[
95            0b0001_0010, 0b0001_0000,
96            0b0101_0110, 0b1110_0101, 0b0000_0000
97        ]);
98
99        let actual = AudioSpecificConfiguration::try_from_buf(&mut raw.clone().into_buf()).unwrap();
100
101        assert_eq!(expected, actual);
102    }
103}