1use super::descriptor_body;
16use crate::error::{Error, Result};
17use dvb_common::{Parse, Serialize};
18
19pub const TAG: u8 = 0x7C;
21const HEADER_LEN: usize = 2;
22
23const FLAG_AAC_TYPE: u8 = 0x80;
24const FLAG_SAOC_DE: u8 = 0x40;
25const RESERVED_ZERO_MASK: u8 = 0x3F;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct AacComponentType {
34 pub mono: bool,
36 pub stereo: bool,
38 pub surround: bool,
40 pub visually_impaired: bool,
42 pub hard_of_hearing: bool,
44 pub supplementary: bool,
46 pub v2: bool,
48 pub saoc_de: bool,
50}
51
52impl AacComponentType {
53 #[must_use]
55 pub fn name(&self) -> &'static str {
57 match (
58 self.mono,
59 self.stereo,
60 self.surround,
61 self.visually_impaired,
62 self.hard_of_hearing,
63 self.supplementary,
64 self.v2,
65 self.saoc_de,
66 ) {
67 (true, false, false, false, false, false, false, false) => {
68 "HE-AAC audio, single mono channel"
69 }
70 (false, true, false, false, false, false, false, false) => "HE-AAC audio, stereo",
71 (false, false, true, false, false, false, false, false) => {
72 "HE-AAC audio, surround sound"
73 }
74 (_, _, _, true, false, false, false, false) => {
75 "HE-AAC audio description for the visually impaired"
76 }
77 (_, _, _, false, true, false, false, false) => "HE-AAC audio for the hard of hearing",
78 (_, _, _, false, false, true, false, false) => {
79 "HE-AAC receiver-mix supplementary audio"
80 }
81 (false, true, false, false, false, false, true, false) => "HE-AAC v2 audio, stereo",
82 (_, _, _, true, false, false, true, false) => {
83 "HE-AAC v2 audio description for the visually impaired"
84 }
85 (_, _, _, false, true, false, true, false) => "HE-AAC v2 audio for the hard of hearing",
86 (_, _, _, false, false, true, true, false) => {
87 "HE-AAC v2 receiver-mix supplementary audio"
88 }
89 (_, _, _, true, false, true, false, false) => {
90 "HE-AAC receiver-mix audio description for the visually impaired"
91 }
92 (_, _, _, true, false, true, true, false) => {
93 "HE-AAC v2 receiver-mix audio description for the visually impaired"
94 }
95 (_, _, _, _, _, _, _, true) => "HE-AAC or HE-AAC v2 with SAOC-DE ancillary data",
96 _ => "unknown HE-AAC component type",
97 }
98 }
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize))]
104#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
105pub struct AacExtension<'a> {
106 pub saoc_de_flag: bool,
108 pub aac_type: Option<u8>,
111 pub additional_info: &'a [u8],
113}
114
115impl AacExtension<'_> {
116 #[must_use]
122 pub fn decoded_component_type(&self) -> Option<AacComponentType> {
123 let ct = self.aac_type?;
124 let saoc_de = self.saoc_de_flag;
125 if ct == 0xA0 {
126 return Some(AacComponentType {
127 mono: false,
128 stereo: false,
129 surround: false,
130 visually_impaired: false,
131 hard_of_hearing: false,
132 supplementary: false,
133 v2: false,
134 saoc_de: true,
135 });
136 }
137 let v2 = matches!(ct, 0x43..=0x46 | 0x49..=0x4A);
138 let result = match ct {
139 0x01 => AacComponentType {
140 mono: true,
141 stereo: false,
142 surround: false,
143 visually_impaired: false,
144 hard_of_hearing: false,
145 supplementary: false,
146 v2: false,
147 saoc_de,
148 },
149 0x03 => AacComponentType {
150 mono: false,
151 stereo: true,
152 surround: false,
153 visually_impaired: false,
154 hard_of_hearing: false,
155 supplementary: false,
156 v2: false,
157 saoc_de,
158 },
159 0x05 => AacComponentType {
160 mono: false,
161 stereo: false,
162 surround: true,
163 visually_impaired: false,
164 hard_of_hearing: false,
165 supplementary: false,
166 v2: false,
167 saoc_de,
168 },
169 0x40 | 0x47 | 0x48 => AacComponentType {
170 mono: false,
171 stereo: false,
172 surround: false,
173 visually_impaired: true,
174 hard_of_hearing: false,
175 supplementary: matches!(ct, 0x47 | 0x48),
176 v2: false,
177 saoc_de,
178 },
179 0x41 => AacComponentType {
180 mono: false,
181 stereo: false,
182 surround: false,
183 visually_impaired: false,
184 hard_of_hearing: true,
185 supplementary: false,
186 v2: false,
187 saoc_de,
188 },
189 0x42 => AacComponentType {
190 mono: false,
191 stereo: false,
192 surround: false,
193 visually_impaired: false,
194 hard_of_hearing: false,
195 supplementary: true,
196 v2: false,
197 saoc_de,
198 },
199 0x43 => AacComponentType {
200 mono: false,
201 stereo: true,
202 surround: false,
203 visually_impaired: false,
204 hard_of_hearing: false,
205 supplementary: false,
206 v2: true,
207 saoc_de,
208 },
209 0x44 | 0x49 | 0x4A => AacComponentType {
210 mono: false,
211 stereo: false,
212 surround: false,
213 visually_impaired: true,
214 hard_of_hearing: false,
215 supplementary: matches!(ct, 0x49 | 0x4A),
216 v2,
217 saoc_de,
218 },
219 0x45 => AacComponentType {
220 mono: false,
221 stereo: false,
222 surround: false,
223 visually_impaired: false,
224 hard_of_hearing: true,
225 supplementary: false,
226 v2: true,
227 saoc_de,
228 },
229 0x46 => AacComponentType {
230 mono: false,
231 stereo: false,
232 surround: false,
233 visually_impaired: false,
234 hard_of_hearing: false,
235 supplementary: true,
236 v2: true,
237 saoc_de,
238 },
239 _ => return None,
240 };
241 Some(result)
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
247#[cfg_attr(feature = "serde", derive(serde::Serialize))]
248#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
249pub struct AacDescriptor<'a> {
250 pub profile_and_level: u8,
252 pub extension: Option<AacExtension<'a>>,
254}
255
256impl<'a> Parse<'a> for AacDescriptor<'a> {
257 type Error = crate::error::Error;
258 fn parse(bytes: &'a [u8]) -> Result<Self> {
259 if bytes.len() < HEADER_LEN + 1 {
260 return Err(Error::BufferTooShort {
261 need: HEADER_LEN + 1,
262 have: bytes.len(),
263 what: "AacDescriptor header+profile",
264 });
265 }
266 let body = descriptor_body(
267 bytes,
268 TAG,
269 "AacDescriptor",
270 "unexpected tag for AAC_descriptor",
271 )?;
272 if body.is_empty() {
273 return Err(Error::InvalidDescriptor {
274 tag: TAG,
275 reason: "AAC_descriptor body shorter than 1 byte",
276 });
277 }
278 let profile_and_level = body[0];
279 let extension = if body.len() > 1 {
280 let flags = body[1];
281 let aac_type_flag = (flags & FLAG_AAC_TYPE) != 0;
282 let saoc_de_flag = (flags & FLAG_SAOC_DE) != 0;
283 let mut pos = 2;
284 let aac_type = if aac_type_flag {
285 if pos >= body.len() {
286 return Err(Error::InvalidDescriptor {
287 tag: TAG,
288 reason: "AAC_type_flag set but AAC_type byte missing",
289 });
290 }
291 let t = body[pos];
292 pos += 1;
293 Some(t)
294 } else {
295 None
296 };
297 let additional_info = &body[pos..];
298 Some(AacExtension {
299 saoc_de_flag,
300 aac_type,
301 additional_info,
302 })
303 } else {
304 None
305 };
306 Ok(Self {
307 profile_and_level,
308 extension,
309 })
310 }
311}
312
313impl Serialize for AacDescriptor<'_> {
314 type Error = crate::error::Error;
315 fn serialized_len(&self) -> usize {
316 let body = 1 + match &self.extension {
317 None => 0,
318 Some(ext) => 1 + usize::from(ext.aac_type.is_some()) + ext.additional_info.len(),
319 };
320 HEADER_LEN + body
321 }
322
323 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
324 let body_len = self.serialized_len() - HEADER_LEN;
325 if body_len > u8::MAX as usize {
326 return Err(Error::InvalidDescriptor {
327 tag: TAG,
328 reason: "AAC_descriptor body exceeds 255 bytes",
329 });
330 }
331 let len = self.serialized_len();
332 if buf.len() < len {
333 return Err(Error::OutputBufferTooSmall {
334 need: len,
335 have: buf.len(),
336 });
337 }
338 buf[0] = TAG;
339 buf[1] = body_len as u8;
340 buf[2] = self.profile_and_level;
341 let mut pos = 3;
342 if let Some(ext) = &self.extension {
343 let mut flags = 0u8;
344 if ext.aac_type.is_some() {
345 flags |= FLAG_AAC_TYPE;
346 }
347 if ext.saoc_de_flag {
348 flags |= FLAG_SAOC_DE;
349 }
350 buf[pos] = flags & !RESERVED_ZERO_MASK;
352 pos += 1;
353 if let Some(t) = ext.aac_type {
354 buf[pos] = t;
355 pos += 1;
356 }
357 buf[pos..pos + ext.additional_info.len()].copy_from_slice(ext.additional_info);
358 }
359 Ok(len)
360 }
361}
362impl<'a> crate::traits::DescriptorDef<'a> for AacDescriptor<'a> {
363 const TAG: u8 = TAG;
364 const NAME: &'static str = "AAC";
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn parse_profile_only() {
373 let bytes = [TAG, 1, 0x50];
374 let d = AacDescriptor::parse(&bytes).unwrap();
375 assert_eq!(d.profile_and_level, 0x50);
376 assert!(d.extension.is_none());
377 }
378
379 #[test]
380 fn parse_with_flags_no_aac_type() {
381 let bytes = [TAG, 2, 0x51, FLAG_SAOC_DE];
383 let d = AacDescriptor::parse(&bytes).unwrap();
384 let ext = d.extension.unwrap();
385 assert!(ext.saoc_de_flag);
386 assert!(ext.aac_type.is_none());
387 assert!(ext.additional_info.is_empty());
388 }
389
390 #[test]
391 fn parse_with_aac_type() {
392 let bytes = [TAG, 3, 0x52, FLAG_AAC_TYPE, 0x03];
393 let d = AacDescriptor::parse(&bytes).unwrap();
394 let ext = d.extension.unwrap();
395 assert!(!ext.saoc_de_flag);
396 assert_eq!(ext.aac_type, Some(0x03));
397 assert!(ext.additional_info.is_empty());
398 }
399
400 #[test]
401 fn parse_with_aac_type_and_additional_info() {
402 let bytes = [TAG, 5, 0x52, FLAG_AAC_TYPE | FLAG_SAOC_DE, 0x05, 0xAA, 0xBB];
403 let d = AacDescriptor::parse(&bytes).unwrap();
404 let ext = d.extension.unwrap();
405 assert!(ext.saoc_de_flag);
406 assert_eq!(ext.aac_type, Some(0x05));
407 assert_eq!(ext.additional_info, &[0xAA, 0xBB]);
408 }
409
410 #[test]
411 fn decode_aac_component_type_he_aac_stereo() {
412 let d = AacDescriptor {
413 profile_and_level: 0x50,
414 extension: Some(AacExtension {
415 saoc_de_flag: false,
416 aac_type: Some(0x03),
417 additional_info: &[],
418 }),
419 };
420 let ct = d.extension.unwrap().decoded_component_type().unwrap();
421 assert!(!ct.mono);
422 assert!(ct.stereo);
423 assert!(!ct.surround);
424 assert_eq!(ct.name(), "HE-AAC audio, stereo");
425 }
426
427 #[test]
428 fn decode_aac_component_type_saoc_de() {
429 let d = AacDescriptor {
430 profile_and_level: 0x50,
431 extension: Some(AacExtension {
432 saoc_de_flag: true,
433 aac_type: Some(0xA0),
434 additional_info: &[],
435 }),
436 };
437 let ct = d.extension.unwrap().decoded_component_type().unwrap();
438 assert!(ct.saoc_de);
439 assert_eq!(ct.name(), "HE-AAC or HE-AAC v2 with SAOC-DE ancillary data");
440 }
441
442 #[test]
443 fn decode_aac_component_type_unknown() {
444 let d = AacDescriptor {
445 profile_and_level: 0x50,
446 extension: Some(AacExtension {
447 saoc_de_flag: false,
448 aac_type: Some(0xFF),
449 additional_info: &[],
450 }),
451 };
452 assert!(d.extension.unwrap().decoded_component_type().is_none());
453 }
454
455 #[test]
456 fn parse_rejects_wrong_tag() {
457 let bytes = [0x7B, 1, 0x50];
458 assert!(matches!(
459 AacDescriptor::parse(&bytes).unwrap_err(),
460 Error::InvalidDescriptor { tag: 0x7B, .. }
461 ));
462 }
463
464 #[test]
465 fn parse_rejects_aac_type_flag_without_byte() {
466 let bytes = [TAG, 2, 0x50, FLAG_AAC_TYPE];
468 assert!(matches!(
469 AacDescriptor::parse(&bytes).unwrap_err(),
470 Error::InvalidDescriptor { .. }
471 ));
472 }
473
474 #[test]
475 fn parse_rejects_length_overrunning_buffer() {
476 let bytes = [TAG, 4, 0x50];
477 assert!(matches!(
478 AacDescriptor::parse(&bytes).unwrap_err(),
479 Error::BufferTooShort { .. }
480 ));
481 }
482
483 #[test]
484 fn serialize_round_trip_profile_only() {
485 let d = AacDescriptor {
486 profile_and_level: 0x58,
487 extension: None,
488 };
489 let mut buf = vec![0u8; d.serialized_len()];
490 d.serialize_into(&mut buf).unwrap();
491 assert_eq!(buf, vec![TAG, 1, 0x58]);
492 assert_eq!(AacDescriptor::parse(&buf).unwrap(), d);
493 }
494
495 #[test]
496 fn serialize_round_trip_full() {
497 let d = AacDescriptor {
498 profile_and_level: 0x52,
499 extension: Some(AacExtension {
500 saoc_de_flag: true,
501 aac_type: Some(0x40),
502 additional_info: &[0xFE, 0xED],
503 }),
504 };
505 let mut buf = vec![0u8; d.serialized_len()];
506 d.serialize_into(&mut buf).unwrap();
507 assert_eq!(AacDescriptor::parse(&buf).unwrap(), d);
508 }
509
510 #[test]
511 fn serialize_emits_reserved_bits_zero() {
512 let d = AacDescriptor {
513 profile_and_level: 0x50,
514 extension: Some(AacExtension {
515 saoc_de_flag: false,
516 aac_type: None,
517 additional_info: &[],
518 }),
519 };
520 let mut buf = vec![0u8; d.serialized_len()];
521 d.serialize_into(&mut buf).unwrap();
522 assert_eq!(buf[3] & RESERVED_ZERO_MASK, 0);
524 assert_eq!(buf[3], 0x00);
525 }
526
527 #[cfg(feature = "serde")]
528 #[test]
529 fn serde_serializes_to_stable_json() {
530 let d = AacDescriptor {
533 profile_and_level: 0x52,
534 extension: Some(AacExtension {
535 saoc_de_flag: true,
536 aac_type: Some(0x03),
537 additional_info: &[0x11],
538 }),
539 };
540 let j = serde_json::to_string(&d).unwrap();
541 let _v: serde_json::Value = serde_json::from_str(&j).unwrap();
544 assert!(j.contains("profile_and_level"));
545 }
546}