1use super::descriptor_body;
8use crate::error::{Error, Result};
9use dvb_common::{Parse, Serialize};
10
11pub const TAG: u8 = 0x6A;
13const HEADER_LEN: usize = 2;
14
15const FLAG_COMPONENT_TYPE: u8 = 0x80;
16const FLAG_BSID: u8 = 0x40;
17const FLAG_MAINID: u8 = 0x20;
18const FLAG_ASVC: u8 = 0x10;
19
20const COMPONENT_TYPE_ENHANCED_AC3_MASK: u8 = 0x80;
21const COMPONENT_TYPE_FULL_SERVICE_MASK: u8 = 0x40;
22const COMPONENT_TYPE_SERVICE_TYPE_SHIFT: u8 = 3;
23const COMPONENT_TYPE_SERVICE_TYPE_MASK: u8 = 0x07;
24const COMPONENT_TYPE_CHANNELS_MASK: u8 = 0x07;
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34#[non_exhaustive]
35pub enum Ac3ServiceType {
36 CompleteMain,
38 MusicAndEffects,
40 VisuallyImpaired,
42 HearingImpaired,
44 Dialogue,
46 Commentary,
48 Emergency,
50 VoiceOver,
52 Unknown(u8),
54}
55
56impl Ac3ServiceType {
57 #[must_use]
59 pub fn from_u8(v: u8) -> Self {
60 match v {
61 0 => Self::CompleteMain,
62 1 => Self::MusicAndEffects,
63 2 => Self::VisuallyImpaired,
64 3 => Self::HearingImpaired,
65 4 => Self::Dialogue,
66 5 => Self::Commentary,
67 6 => Self::Emergency,
68 7 => Self::VoiceOver,
69 _ => Self::Unknown(v),
70 }
71 }
72
73 #[must_use]
75 pub fn to_u8(self) -> u8 {
76 match self {
77 Self::CompleteMain => 0,
78 Self::MusicAndEffects => 1,
79 Self::VisuallyImpaired => 2,
80 Self::HearingImpaired => 3,
81 Self::Dialogue => 4,
82 Self::Commentary => 5,
83 Self::Emergency => 6,
84 Self::VoiceOver => 7,
85 Self::Unknown(v) => v,
86 }
87 }
88
89 #[must_use]
91 pub fn name(self) -> &'static str {
92 match self {
93 Self::CompleteMain => "Complete Main (CM)",
94 Self::MusicAndEffects => "Music and Effects (ME)",
95 Self::VisuallyImpaired => "Visually Impaired (VI)",
96 Self::HearingImpaired => "Hearing Impaired (HI)",
97 Self::Dialogue => "Dialogue (D)",
98 Self::Commentary => "Commentary (C)",
99 Self::Emergency => "Emergency (E)",
100 Self::VoiceOver => "Voice Over (VO)",
101 Self::Unknown(_) => "unknown",
102 }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111#[cfg_attr(feature = "serde", derive(serde::Serialize))]
112#[non_exhaustive]
113pub enum Ac3ChannelMode {
114 Mono,
116 OnePlusOne,
118 Stereo,
120 SurroundEncodedStereo,
122 Multichannel,
124 MultichannelAbove51,
126 MultipleSubstreams,
128 Reserved,
130 Unknown(u8),
132}
133
134impl Ac3ChannelMode {
135 #[must_use]
137 pub fn from_u8(v: u8) -> Self {
138 match v {
139 0 => Self::Mono,
140 1 => Self::OnePlusOne,
141 2 => Self::Stereo,
142 3 => Self::SurroundEncodedStereo,
143 4 => Self::Multichannel,
144 5 => Self::MultichannelAbove51,
145 6 => Self::MultipleSubstreams,
146 7 => Self::Reserved,
147 _ => Self::Unknown(v),
148 }
149 }
150
151 #[must_use]
153 pub fn to_u8(self) -> u8 {
154 match self {
155 Self::Mono => 0,
156 Self::OnePlusOne => 1,
157 Self::Stereo => 2,
158 Self::SurroundEncodedStereo => 3,
159 Self::Multichannel => 4,
160 Self::MultichannelAbove51 => 5,
161 Self::MultipleSubstreams => 6,
162 Self::Reserved => 7,
163 Self::Unknown(v) => v,
164 }
165 }
166
167 #[must_use]
169 pub fn name(self) -> &'static str {
170 match self {
171 Self::Mono => "Mono",
172 Self::OnePlusOne => "1+1 Mode",
173 Self::Stereo => "2 channel (stereo)",
174 Self::SurroundEncodedStereo => "2 channel Surround encoded (Dolby surround)",
175 Self::Multichannel => "Multichannel audio (> 2 channels)",
176 Self::MultichannelAbove51 => "Multichannel audio (> 5.1 channels)",
177 Self::MultipleSubstreams => "Multiple programmes in independent substreams",
178 Self::Reserved => "reserved",
179 Self::Unknown(_) => "unknown",
180 }
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize))]
195#[non_exhaustive]
196pub struct Ac3ComponentType {
197 pub enhanced_ac3: bool,
199 pub full_service: bool,
201 pub service_type: Ac3ServiceType,
203 pub channels: Ac3ChannelMode,
205}
206
207impl Ac3ComponentType {
208 #[must_use]
213 pub fn from_byte(byte: u8) -> Self {
214 let enhanced_ac3 = (byte & COMPONENT_TYPE_ENHANCED_AC3_MASK) != 0;
215 let full_service = (byte & COMPONENT_TYPE_FULL_SERVICE_MASK) != 0;
216 let service_type = Ac3ServiceType::from_u8(
217 (byte >> COMPONENT_TYPE_SERVICE_TYPE_SHIFT) & COMPONENT_TYPE_SERVICE_TYPE_MASK,
218 );
219 let channels = Ac3ChannelMode::from_u8(byte & COMPONENT_TYPE_CHANNELS_MASK);
220 Self {
221 enhanced_ac3,
222 full_service,
223 service_type,
224 channels,
225 }
226 }
227
228 #[must_use]
230 pub fn to_byte(self) -> u8 {
231 (self.enhanced_ac3 as u8) << 7
232 | (self.full_service as u8) << 6
233 | (self.service_type.to_u8() & COMPONENT_TYPE_SERVICE_TYPE_MASK)
234 << COMPONENT_TYPE_SERVICE_TYPE_SHIFT
235 | (self.channels.to_u8() & COMPONENT_TYPE_CHANNELS_MASK)
236 }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq)]
241#[cfg_attr(feature = "serde", derive(serde::Serialize))]
242#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
243pub struct Ac3Descriptor<'a> {
244 pub component_type: Option<u8>,
246 pub bsid: Option<u8>,
248 pub mainid: Option<u8>,
250 pub asvc: Option<u8>,
252 pub additional_info: &'a [u8],
254}
255
256impl Ac3Descriptor<'_> {
257 #[must_use]
261 pub fn decoded_component_type(&self) -> Option<Ac3ComponentType> {
262 Some(Ac3ComponentType::from_byte(self.component_type?))
263 }
264}
265
266impl<'a> Parse<'a> for Ac3Descriptor<'a> {
267 type Error = crate::error::Error;
268 fn parse(bytes: &'a [u8]) -> Result<Self> {
269 let body = descriptor_body(
270 bytes,
271 TAG,
272 "Ac3Descriptor",
273 "unexpected tag for AC-3 descriptor",
274 )?;
275 if body.is_empty() {
276 return Err(Error::InvalidDescriptor {
277 tag: TAG,
278 reason: "descriptor body is empty (length=0)",
279 });
280 }
281 let flags = body[0];
282 let mut pos = 1;
283 let mut read_one = |set: bool| -> Result<Option<u8>> {
284 if !set {
285 return Ok(None);
286 }
287 if pos >= body.len() {
288 return Err(Error::InvalidDescriptor {
289 tag: TAG,
290 reason: "AC-3 descriptor flags claim more bytes than length permits",
291 });
292 }
293 let b = body[pos];
294 pos += 1;
295 Ok(Some(b))
296 };
297
298 let component_type = read_one(flags & FLAG_COMPONENT_TYPE != 0)?;
299 let bsid = read_one(flags & FLAG_BSID != 0)?;
300 let mainid = read_one(flags & FLAG_MAINID != 0)?;
301 let asvc = read_one(flags & FLAG_ASVC != 0)?;
302 let additional_info = &body[pos..];
303 Ok(Self {
304 component_type,
305 bsid,
306 mainid,
307 asvc,
308 additional_info,
309 })
310 }
311}
312
313impl Serialize for Ac3Descriptor<'_> {
314 type Error = crate::error::Error;
315 fn serialized_len(&self) -> usize {
316 HEADER_LEN
317 + 1
318 + usize::from(self.component_type.is_some())
319 + usize::from(self.bsid.is_some())
320 + usize::from(self.mainid.is_some())
321 + usize::from(self.asvc.is_some())
322 + self.additional_info.len()
323 }
324
325 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
326 let len = self.serialized_len();
327 if buf.len() < len {
328 return Err(Error::OutputBufferTooSmall {
329 need: len,
330 have: buf.len(),
331 });
332 }
333 buf[0] = TAG;
334 buf[1] = (len - HEADER_LEN) as u8;
335 let mut flags: u8 = 0;
336 if self.component_type.is_some() {
337 flags |= FLAG_COMPONENT_TYPE;
338 }
339 if self.bsid.is_some() {
340 flags |= FLAG_BSID;
341 }
342 if self.mainid.is_some() {
343 flags |= FLAG_MAINID;
344 }
345 if self.asvc.is_some() {
346 flags |= FLAG_ASVC;
347 }
348 buf[2] = flags | 0x0F;
350 let mut pos = 3;
351 for b in [self.component_type, self.bsid, self.mainid, self.asvc]
352 .into_iter()
353 .flatten()
354 {
355 buf[pos] = b;
356 pos += 1;
357 }
358 buf[pos..pos + self.additional_info.len()].copy_from_slice(self.additional_info);
359 Ok(len)
360 }
361}
362impl<'a> crate::traits::DescriptorDef<'a> for Ac3Descriptor<'a> {
363 const TAG: u8 = TAG;
364 const NAME: &'static str = "AC3";
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370
371 #[test]
372 fn parse_with_all_fields() {
373 let bytes = [
374 TAG,
375 5,
376 FLAG_COMPONENT_TYPE | FLAG_BSID | FLAG_MAINID | FLAG_ASVC,
377 0x11,
378 0x22,
379 0x33,
380 0x44,
381 ];
382 let d = Ac3Descriptor::parse(&bytes).unwrap();
383 assert_eq!(d.component_type, Some(0x11));
384 assert_eq!(d.bsid, Some(0x22));
385 assert_eq!(d.mainid, Some(0x33));
386 assert_eq!(d.asvc, Some(0x44));
387 assert_eq!(d.additional_info, &[] as &[u8]);
388 }
389
390 #[test]
391 fn parse_with_only_component_type() {
392 let bytes = [TAG, 2, FLAG_COMPONENT_TYPE, 0x07];
393 let d = Ac3Descriptor::parse(&bytes).unwrap();
394 assert_eq!(d.component_type, Some(0x07));
395 assert_eq!(d.bsid, None);
396 }
397
398 #[test]
399 fn parse_with_additional_info_only() {
400 let bytes = [TAG, 3, 0x00, 0xAA, 0xBB];
401 let d = Ac3Descriptor::parse(&bytes).unwrap();
402 assert_eq!(d.component_type, None);
403 assert_eq!(d.additional_info, &[0xAA, 0xBB]);
404 }
405
406 #[test]
407 fn decode_component_type_full_service_cm_stereo() {
408 let ct = Ac3ComponentType::from_byte(0x42);
411 assert!(!ct.enhanced_ac3);
412 assert!(ct.full_service);
413 assert_eq!(ct.service_type, Ac3ServiceType::CompleteMain);
414 assert_eq!(ct.channels, Ac3ChannelMode::Stereo);
415 }
416
417 #[test]
418 fn decode_component_type_enhanced_me_1plus1() {
419 let ct = Ac3ComponentType::from_byte(0x89);
422 assert!(ct.enhanced_ac3);
423 assert!(!ct.full_service);
424 assert_eq!(ct.service_type, Ac3ServiceType::MusicAndEffects);
425 assert_eq!(ct.channels, Ac3ChannelMode::OnePlusOne);
426 }
427
428 #[test]
429 fn decode_component_type_vi_surround() {
430 let ct = Ac3ComponentType::from_byte(0x53);
433 assert!(!ct.enhanced_ac3);
434 assert!(ct.full_service);
435 assert_eq!(ct.service_type, Ac3ServiceType::VisuallyImpaired);
436 assert_eq!(ct.channels, Ac3ChannelMode::SurroundEncodedStereo);
437 }
438
439 #[test]
440 fn decode_component_type_emergency_mono() {
441 let ct = Ac3ComponentType::from_byte(0x30);
444 assert!(!ct.enhanced_ac3);
445 assert!(!ct.full_service);
446 assert_eq!(ct.service_type, Ac3ServiceType::Emergency);
447 assert_eq!(ct.channels, Ac3ChannelMode::Mono);
448 }
449
450 #[test]
451 fn decode_component_type_reserved_channels() {
452 let ct = Ac3ComponentType::from_byte(0xC7);
455 assert!(ct.enhanced_ac3);
456 assert!(ct.full_service);
457 assert_eq!(ct.service_type, Ac3ServiceType::CompleteMain);
458 assert_eq!(ct.channels, Ac3ChannelMode::Reserved);
459 }
460
461 #[test]
462 fn decode_component_type_none() {
463 let d = Ac3Descriptor {
464 component_type: None,
465 bsid: None,
466 mainid: None,
467 asvc: None,
468 additional_info: &[],
469 };
470 assert!(d.decoded_component_type().is_none());
471 }
472
473 #[test]
474 fn component_type_round_trip_all_bytes() {
475 for b in 0u8..=255 {
476 let ct = Ac3ComponentType::from_byte(b);
477 assert_eq!(ct.to_byte(), b, "round-trip failed for byte {b:#04x}");
478 }
479 }
480
481 #[test]
482 fn service_type_round_trip() {
483 for v in 0u8..=7 {
484 let st = Ac3ServiceType::from_u8(v);
485 assert_eq!(st.to_u8(), v, "service_type round-trip failed for {v}");
486 }
487 assert_eq!(Ac3ServiceType::Unknown(42).to_u8(), 42);
489 }
490
491 #[test]
492 fn channel_mode_round_trip() {
493 for v in 0u8..=7 {
494 let cm = Ac3ChannelMode::from_u8(v);
495 assert_eq!(cm.to_u8(), v, "channel_mode round-trip failed for {v}");
496 }
497 assert_eq!(Ac3ChannelMode::Unknown(42).to_u8(), 42);
498 }
499
500 #[test]
501 fn service_type_name() {
502 assert_eq!(Ac3ServiceType::CompleteMain.name(), "Complete Main (CM)");
503 assert_eq!(Ac3ServiceType::Dialogue.name(), "Dialogue (D)");
504 assert_eq!(Ac3ServiceType::Unknown(99).name(), "unknown");
505 }
506
507 #[test]
508 fn channel_mode_name() {
509 assert_eq!(Ac3ChannelMode::Mono.name(), "Mono");
510 assert_eq!(
511 Ac3ChannelMode::SurroundEncodedStereo.name(),
512 "2 channel Surround encoded (Dolby surround)"
513 );
514 assert_eq!(Ac3ChannelMode::Reserved.name(), "reserved");
515 assert_eq!(Ac3ChannelMode::Unknown(99).name(), "unknown");
516 }
517
518 #[test]
519 fn parse_rejects_wrong_tag() {
520 assert!(matches!(
521 Ac3Descriptor::parse(&[0x7A, 1, 0]).unwrap_err(),
522 Error::InvalidDescriptor { tag: 0x7A, .. }
523 ));
524 }
525
526 #[test]
527 fn parse_rejects_flags_past_length() {
528 let bytes = [TAG, 1, FLAG_COMPONENT_TYPE];
529 assert!(matches!(
530 Ac3Descriptor::parse(&bytes).unwrap_err(),
531 Error::InvalidDescriptor { .. }
532 ));
533 }
534
535 #[test]
536 fn serialize_round_trip() {
537 let d = Ac3Descriptor {
538 component_type: Some(0x40),
539 bsid: Some(8),
540 mainid: None,
541 asvc: None,
542 additional_info: &[0xFE, 0xED],
543 };
544 let mut buf = vec![0u8; d.serialized_len()];
545 d.serialize_into(&mut buf).unwrap();
546 assert_eq!(Ac3Descriptor::parse(&buf).unwrap(), d);
547 }
548
549 #[test]
550 fn parse_rejects_empty_body() {
551 let bytes = [TAG, 0];
552 assert!(matches!(
553 Ac3Descriptor::parse(&bytes).unwrap_err(),
554 Error::InvalidDescriptor { .. }
555 ));
556 }
557}