1#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
11#![deny(missing_docs)]
12#![deny(unsafe_code)]
13#![deny(unreachable_pub)]
14
15use std::io;
16
17use num_derive::FromPrimitive;
18use num_traits::FromPrimitive;
19use scuffle_bytes_util::BitReader;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[must_use]
28pub struct PartialAudioSpecificConfig {
29 pub audio_object_type: AudioObjectType,
31 pub sampling_frequency: u32,
33 pub channel_configuration: u8,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40#[must_use]
41pub enum AudioObjectType {
42 AacMain,
44 AacLowComplexity,
46 Unknown(u16),
48}
49
50impl AudioObjectType {
51 pub const fn as_u16(&self) -> u16 {
53 match self {
54 AudioObjectType::AacMain => 1,
55 AudioObjectType::AacLowComplexity => 2,
56 AudioObjectType::Unknown(value) => *value,
57 }
58 }
59
60 pub const fn from_u16(value: u16) -> Self {
62 match value {
63 1 => AudioObjectType::AacMain,
64 2 => AudioObjectType::AacLowComplexity,
65 _ => AudioObjectType::Unknown(value),
66 }
67 }
68}
69
70impl From<u16> for AudioObjectType {
71 fn from(value: u16) -> Self {
72 Self::from_u16(value)
73 }
74}
75
76impl From<AudioObjectType> for u16 {
77 fn from(value: AudioObjectType) -> Self {
78 value.as_u16()
79 }
80}
81
82#[derive(FromPrimitive, Debug, Clone, PartialEq, Copy, Eq, PartialOrd, Ord)]
90#[repr(u8)]
91#[must_use]
92pub enum SampleFrequencyIndex {
93 Freq96000 = 0x0,
95 Freq88200 = 0x1,
97 Freq64000 = 0x2,
99 Freq48000 = 0x3,
101 Freq44100 = 0x4,
103 Freq32000 = 0x5,
105 Freq24000 = 0x6,
107 Freq22050 = 0x7,
109 Freq16000 = 0x8,
111 Freq12000 = 0x9,
113 Freq11025 = 0xA,
115 Freq8000 = 0xB,
117 Freq7350 = 0xC,
119 FreqReserved = 0xD,
121 FreqReserved2 = 0xE,
123 FreqEscape = 0xF,
126}
127
128impl SampleFrequencyIndex {
129 pub const fn to_freq(&self) -> Option<u32> {
131 match self {
132 SampleFrequencyIndex::Freq96000 => Some(96000),
133 SampleFrequencyIndex::Freq88200 => Some(88200),
134 SampleFrequencyIndex::Freq64000 => Some(64000),
135 SampleFrequencyIndex::Freq48000 => Some(48000),
136 SampleFrequencyIndex::Freq44100 => Some(44100),
137 SampleFrequencyIndex::Freq32000 => Some(32000),
138 SampleFrequencyIndex::Freq24000 => Some(24000),
139 SampleFrequencyIndex::Freq22050 => Some(22050),
140 SampleFrequencyIndex::Freq16000 => Some(16000),
141 SampleFrequencyIndex::Freq12000 => Some(12000),
142 SampleFrequencyIndex::Freq11025 => Some(11025),
143 SampleFrequencyIndex::Freq8000 => Some(8000),
144 SampleFrequencyIndex::Freq7350 => Some(7350),
145 SampleFrequencyIndex::FreqReserved => None,
146 SampleFrequencyIndex::FreqReserved2 => None,
147 SampleFrequencyIndex::FreqEscape => None,
148 }
149 }
150}
151
152impl PartialAudioSpecificConfig {
153 pub fn parse(data: &[u8]) -> io::Result<Self> {
161 let mut bitreader = BitReader::new_from_slice(data);
162
163 let mut audio_object_type = bitreader.read_bits(5)? as u16;
165 if audio_object_type == 31 {
166 audio_object_type = 32 + bitreader.read_bits(6)? as u16;
167 }
168
169 let sampling_frequency_index = SampleFrequencyIndex::from_u8(bitreader.read_bits(4)? as u8)
172 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid sampling frequency index"))?;
173
174 let sampling_frequency = match sampling_frequency_index {
175 SampleFrequencyIndex::FreqEscape => bitreader.read_bits(24)? as u32,
177 _ => sampling_frequency_index
178 .to_freq()
179 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid sampling frequency index"))?,
180 };
181
182 let channel_configuration = bitreader.read_bits(4)? as u8;
184
185 Ok(Self {
186 audio_object_type: audio_object_type.into(),
187 sampling_frequency,
188 channel_configuration,
189 })
190 }
191}
192
193#[cfg(test)]
194#[cfg_attr(all(test, coverage_nightly), coverage(off))]
195mod tests {
196 use super::*;
197
198 #[test]
199 fn test_aac_config_parse() {
200 let data = [
201 0x12, 0x10, 0x56, 0xe5, 0x00, 0x2d, 0x96, 0x01, 0x80, 0x80, 0x05, 0x00, 0x00, 0x00, 0x00,
202 ];
203
204 let config = PartialAudioSpecificConfig::parse(&data).unwrap();
205 assert_eq!(config.audio_object_type, AudioObjectType::AacLowComplexity);
206 assert_eq!(config.sampling_frequency, 44100);
207 assert_eq!(config.channel_configuration, 2);
208 }
209
210 #[test]
211 fn test_idx_to_freq() {
212 let cases = [
213 (SampleFrequencyIndex::FreqEscape, None),
214 (SampleFrequencyIndex::FreqReserved2, None),
215 (SampleFrequencyIndex::FreqReserved, None),
216 (SampleFrequencyIndex::Freq7350, Some(7350)),
217 (SampleFrequencyIndex::Freq8000, Some(8000)),
218 (SampleFrequencyIndex::Freq11025, Some(11025)),
219 (SampleFrequencyIndex::Freq12000, Some(12000)),
220 (SampleFrequencyIndex::Freq16000, Some(16000)),
221 (SampleFrequencyIndex::Freq22050, Some(22050)),
222 (SampleFrequencyIndex::Freq24000, Some(24000)),
223 (SampleFrequencyIndex::Freq32000, Some(32000)),
224 (SampleFrequencyIndex::Freq44100, Some(44100)),
225 (SampleFrequencyIndex::Freq48000, Some(48000)),
226 (SampleFrequencyIndex::Freq64000, Some(64000)),
227 (SampleFrequencyIndex::Freq88200, Some(88200)),
228 (SampleFrequencyIndex::Freq96000, Some(96000)),
229 ];
230
231 for (idx, freq) in cases {
232 assert_eq!(freq, idx.to_freq(), "Expected frequency for {idx:?}");
233 }
234 }
235}