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}
105dvb_common::impl_spec_display!(Ac3ServiceType, Unknown);
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize))]
113#[non_exhaustive]
114pub enum Ac3ChannelMode {
115 Mono,
117 OnePlusOne,
119 Stereo,
121 SurroundEncodedStereo,
123 Multichannel,
125 MultichannelAbove51,
127 MultipleSubstreams,
129 Reserved,
131 Unknown(u8),
133}
134
135impl Ac3ChannelMode {
136 #[must_use]
138 pub fn from_u8(v: u8) -> Self {
139 match v {
140 0 => Self::Mono,
141 1 => Self::OnePlusOne,
142 2 => Self::Stereo,
143 3 => Self::SurroundEncodedStereo,
144 4 => Self::Multichannel,
145 5 => Self::MultichannelAbove51,
146 6 => Self::MultipleSubstreams,
147 7 => Self::Reserved,
148 _ => Self::Unknown(v),
149 }
150 }
151
152 #[must_use]
154 pub fn to_u8(self) -> u8 {
155 match self {
156 Self::Mono => 0,
157 Self::OnePlusOne => 1,
158 Self::Stereo => 2,
159 Self::SurroundEncodedStereo => 3,
160 Self::Multichannel => 4,
161 Self::MultichannelAbove51 => 5,
162 Self::MultipleSubstreams => 6,
163 Self::Reserved => 7,
164 Self::Unknown(v) => v,
165 }
166 }
167
168 #[must_use]
170 pub fn name(self) -> &'static str {
171 match self {
172 Self::Mono => "Mono",
173 Self::OnePlusOne => "1+1 Mode",
174 Self::Stereo => "2 channel (stereo)",
175 Self::SurroundEncodedStereo => "2 channel Surround encoded (Dolby surround)",
176 Self::Multichannel => "Multichannel audio (> 2 channels)",
177 Self::MultichannelAbove51 => "Multichannel audio (> 5.1 channels)",
178 Self::MultipleSubstreams => "Multiple programmes in independent substreams",
179 Self::Reserved => "reserved",
180 Self::Unknown(_) => "unknown",
181 }
182 }
183}
184dvb_common::impl_spec_display!(Ac3ChannelMode, Unknown);
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196#[cfg_attr(feature = "serde", derive(serde::Serialize))]
197#[non_exhaustive]
198pub struct Ac3ComponentType {
199 pub enhanced_ac3: bool,
201 pub full_service: bool,
203 pub service_type: Ac3ServiceType,
205 pub channels: Ac3ChannelMode,
207}
208
209impl Ac3ComponentType {
210 #[must_use]
215 pub fn from_byte(byte: u8) -> Self {
216 let enhanced_ac3 = (byte & COMPONENT_TYPE_ENHANCED_AC3_MASK) != 0;
217 let full_service = (byte & COMPONENT_TYPE_FULL_SERVICE_MASK) != 0;
218 let service_type = Ac3ServiceType::from_u8(
219 (byte >> COMPONENT_TYPE_SERVICE_TYPE_SHIFT) & COMPONENT_TYPE_SERVICE_TYPE_MASK,
220 );
221 let channels = Ac3ChannelMode::from_u8(byte & COMPONENT_TYPE_CHANNELS_MASK);
222 Self {
223 enhanced_ac3,
224 full_service,
225 service_type,
226 channels,
227 }
228 }
229
230 #[must_use]
232 pub fn to_byte(self) -> u8 {
233 (self.enhanced_ac3 as u8) << 7
234 | (self.full_service as u8) << 6
235 | (self.service_type.to_u8() & COMPONENT_TYPE_SERVICE_TYPE_MASK)
236 << COMPONENT_TYPE_SERVICE_TYPE_SHIFT
237 | (self.channels.to_u8() & COMPONENT_TYPE_CHANNELS_MASK)
238 }
239}
240
241#[derive(Debug, Clone, PartialEq, Eq)]
243#[cfg_attr(feature = "serde", derive(serde::Serialize))]
244#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
245pub struct Ac3Descriptor<'a> {
246 pub component_type: Option<u8>,
248 pub bsid: Option<u8>,
250 pub mainid: Option<u8>,
252 pub asvc: Option<u8>,
254 pub additional_info: &'a [u8],
256}
257
258impl Ac3Descriptor<'_> {
259 #[must_use]
263 pub fn decoded_component_type(&self) -> Option<Ac3ComponentType> {
264 Some(Ac3ComponentType::from_byte(self.component_type?))
265 }
266}
267
268impl<'a> Parse<'a> for Ac3Descriptor<'a> {
269 type Error = crate::error::Error;
270 fn parse(bytes: &'a [u8]) -> Result<Self> {
271 let body = descriptor_body(
272 bytes,
273 TAG,
274 "Ac3Descriptor",
275 "unexpected tag for AC-3 descriptor",
276 )?;
277 if body.is_empty() {
278 return Err(Error::InvalidDescriptor {
279 tag: TAG,
280 reason: "descriptor body is empty (length=0)",
281 });
282 }
283 let flags = body[0];
284 let mut pos = 1;
285 let mut read_one = |set: bool| -> Result<Option<u8>> {
286 if !set {
287 return Ok(None);
288 }
289 if pos >= body.len() {
290 return Err(Error::InvalidDescriptor {
291 tag: TAG,
292 reason: "AC-3 descriptor flags claim more bytes than length permits",
293 });
294 }
295 let b = body[pos];
296 pos += 1;
297 Ok(Some(b))
298 };
299
300 let component_type = read_one(flags & FLAG_COMPONENT_TYPE != 0)?;
301 let bsid = read_one(flags & FLAG_BSID != 0)?;
302 let mainid = read_one(flags & FLAG_MAINID != 0)?;
303 let asvc = read_one(flags & FLAG_ASVC != 0)?;
304 let additional_info = &body[pos..];
305 Ok(Self {
306 component_type,
307 bsid,
308 mainid,
309 asvc,
310 additional_info,
311 })
312 }
313}
314
315impl Serialize for Ac3Descriptor<'_> {
316 type Error = crate::error::Error;
317 fn serialized_len(&self) -> usize {
318 HEADER_LEN
319 + 1
320 + usize::from(self.component_type.is_some())
321 + usize::from(self.bsid.is_some())
322 + usize::from(self.mainid.is_some())
323 + usize::from(self.asvc.is_some())
324 + self.additional_info.len()
325 }
326
327 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
328 let len = self.serialized_len();
329 if buf.len() < len {
330 return Err(Error::OutputBufferTooSmall {
331 need: len,
332 have: buf.len(),
333 });
334 }
335 buf[0] = TAG;
336 buf[1] = (len - HEADER_LEN) as u8;
337 let mut flags: u8 = 0;
338 if self.component_type.is_some() {
339 flags |= FLAG_COMPONENT_TYPE;
340 }
341 if self.bsid.is_some() {
342 flags |= FLAG_BSID;
343 }
344 if self.mainid.is_some() {
345 flags |= FLAG_MAINID;
346 }
347 if self.asvc.is_some() {
348 flags |= FLAG_ASVC;
349 }
350 buf[2] = flags | 0x0F;
352 let mut pos = 3;
353 for b in [self.component_type, self.bsid, self.mainid, self.asvc]
354 .into_iter()
355 .flatten()
356 {
357 buf[pos] = b;
358 pos += 1;
359 }
360 buf[pos..pos + self.additional_info.len()].copy_from_slice(self.additional_info);
361 Ok(len)
362 }
363}
364impl<'a> crate::traits::DescriptorDef<'a> for Ac3Descriptor<'a> {
365 const TAG: u8 = TAG;
366 const NAME: &'static str = "AC3";
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372
373 #[test]
374 fn parse_with_all_fields() {
375 let bytes = [
376 TAG,
377 5,
378 FLAG_COMPONENT_TYPE | FLAG_BSID | FLAG_MAINID | FLAG_ASVC,
379 0x11,
380 0x22,
381 0x33,
382 0x44,
383 ];
384 let d = Ac3Descriptor::parse(&bytes).unwrap();
385 assert_eq!(d.component_type, Some(0x11));
386 assert_eq!(d.bsid, Some(0x22));
387 assert_eq!(d.mainid, Some(0x33));
388 assert_eq!(d.asvc, Some(0x44));
389 assert_eq!(d.additional_info, &[] as &[u8]);
390 }
391
392 #[test]
393 fn parse_with_only_component_type() {
394 let bytes = [TAG, 2, FLAG_COMPONENT_TYPE, 0x07];
395 let d = Ac3Descriptor::parse(&bytes).unwrap();
396 assert_eq!(d.component_type, Some(0x07));
397 assert_eq!(d.bsid, None);
398 }
399
400 #[test]
401 fn parse_with_additional_info_only() {
402 let bytes = [TAG, 3, 0x00, 0xAA, 0xBB];
403 let d = Ac3Descriptor::parse(&bytes).unwrap();
404 assert_eq!(d.component_type, None);
405 assert_eq!(d.additional_info, &[0xAA, 0xBB]);
406 }
407
408 #[test]
409 fn decode_component_type_full_service_cm_stereo() {
410 let ct = Ac3ComponentType::from_byte(0x42);
413 assert!(!ct.enhanced_ac3);
414 assert!(ct.full_service);
415 assert_eq!(ct.service_type, Ac3ServiceType::CompleteMain);
416 assert_eq!(ct.channels, Ac3ChannelMode::Stereo);
417 }
418
419 #[test]
420 fn decode_component_type_enhanced_me_1plus1() {
421 let ct = Ac3ComponentType::from_byte(0x89);
424 assert!(ct.enhanced_ac3);
425 assert!(!ct.full_service);
426 assert_eq!(ct.service_type, Ac3ServiceType::MusicAndEffects);
427 assert_eq!(ct.channels, Ac3ChannelMode::OnePlusOne);
428 }
429
430 #[test]
431 fn decode_component_type_vi_surround() {
432 let ct = Ac3ComponentType::from_byte(0x53);
435 assert!(!ct.enhanced_ac3);
436 assert!(ct.full_service);
437 assert_eq!(ct.service_type, Ac3ServiceType::VisuallyImpaired);
438 assert_eq!(ct.channels, Ac3ChannelMode::SurroundEncodedStereo);
439 }
440
441 #[test]
442 fn decode_component_type_emergency_mono() {
443 let ct = Ac3ComponentType::from_byte(0x30);
446 assert!(!ct.enhanced_ac3);
447 assert!(!ct.full_service);
448 assert_eq!(ct.service_type, Ac3ServiceType::Emergency);
449 assert_eq!(ct.channels, Ac3ChannelMode::Mono);
450 }
451
452 #[test]
453 fn decode_component_type_reserved_channels() {
454 let ct = Ac3ComponentType::from_byte(0xC7);
457 assert!(ct.enhanced_ac3);
458 assert!(ct.full_service);
459 assert_eq!(ct.service_type, Ac3ServiceType::CompleteMain);
460 assert_eq!(ct.channels, Ac3ChannelMode::Reserved);
461 }
462
463 #[test]
464 fn decode_component_type_none() {
465 let d = Ac3Descriptor {
466 component_type: None,
467 bsid: None,
468 mainid: None,
469 asvc: None,
470 additional_info: &[],
471 };
472 assert!(d.decoded_component_type().is_none());
473 }
474
475 #[test]
476 fn component_type_round_trip_all_bytes() {
477 for b in 0u8..=255 {
478 let ct = Ac3ComponentType::from_byte(b);
479 assert_eq!(ct.to_byte(), b, "round-trip failed for byte {b:#04x}");
480 }
481 }
482
483 #[test]
484 fn service_type_round_trip() {
485 for v in 0u8..=7 {
486 let st = Ac3ServiceType::from_u8(v);
487 assert_eq!(st.to_u8(), v, "service_type round-trip failed for {v}");
488 }
489 assert_eq!(Ac3ServiceType::Unknown(42).to_u8(), 42);
491 }
492
493 #[test]
494 fn channel_mode_round_trip() {
495 for v in 0u8..=7 {
496 let cm = Ac3ChannelMode::from_u8(v);
497 assert_eq!(cm.to_u8(), v, "channel_mode round-trip failed for {v}");
498 }
499 assert_eq!(Ac3ChannelMode::Unknown(42).to_u8(), 42);
500 }
501
502 #[test]
503 fn service_type_name() {
504 assert_eq!(Ac3ServiceType::CompleteMain.name(), "Complete Main (CM)");
505 assert_eq!(Ac3ServiceType::Dialogue.name(), "Dialogue (D)");
506 assert_eq!(Ac3ServiceType::Unknown(99).name(), "unknown");
507 }
508
509 #[test]
510 fn channel_mode_name() {
511 assert_eq!(Ac3ChannelMode::Mono.name(), "Mono");
512 assert_eq!(
513 Ac3ChannelMode::SurroundEncodedStereo.name(),
514 "2 channel Surround encoded (Dolby surround)"
515 );
516 assert_eq!(Ac3ChannelMode::Reserved.name(), "reserved");
517 assert_eq!(Ac3ChannelMode::Unknown(99).name(), "unknown");
518 }
519
520 #[test]
521 fn parse_rejects_wrong_tag() {
522 assert!(matches!(
523 Ac3Descriptor::parse(&[0x7A, 1, 0]).unwrap_err(),
524 Error::InvalidDescriptor { tag: 0x7A, .. }
525 ));
526 }
527
528 #[test]
529 fn parse_rejects_flags_past_length() {
530 let bytes = [TAG, 1, FLAG_COMPONENT_TYPE];
531 assert!(matches!(
532 Ac3Descriptor::parse(&bytes).unwrap_err(),
533 Error::InvalidDescriptor { .. }
534 ));
535 }
536
537 #[test]
538 fn serialize_round_trip() {
539 let d = Ac3Descriptor {
540 component_type: Some(0x40),
541 bsid: Some(8),
542 mainid: None,
543 asvc: None,
544 additional_info: &[0xFE, 0xED],
545 };
546 let mut buf = vec![0u8; d.serialized_len()];
547 d.serialize_into(&mut buf).unwrap();
548 assert_eq!(Ac3Descriptor::parse(&buf).unwrap(), d);
549 }
550
551 #[test]
552 fn parse_rejects_empty_body() {
553 let bytes = [TAG, 0];
554 assert!(matches!(
555 Ac3Descriptor::parse(&bytes).unwrap_err(),
556 Error::InvalidDescriptor { .. }
557 ));
558 }
559}