1mod import;
7
8pub use import::*;
9
10use bytes::{Buf, Bytes};
11
12#[derive(Debug, Clone, thiserror::Error)]
14#[non_exhaustive]
15pub enum Error {
16 #[error("AudioSpecificConfig must be at least 2 bytes")]
17 ConfigTooShort,
18
19 #[error("extended audioObjectType requires 2 additional bytes")]
20 ExtendedConfigTooShort,
21
22 #[error("AudioSpecificConfig incomplete")]
23 IncompleteConfig,
24
25 #[error("explicit sample rate requires 3 additional bytes")]
26 ExplicitSampleRateTooShort,
27
28 #[error("unsupported sample rate index: {0}")]
29 UnsupportedSampleRateIndex(u8),
30
31 #[error("reserved channelConfiguration: {0}")]
33 ReservedChannelConfig(u8),
34
35 #[error("channelConfiguration 0 is unsupported for audioObjectType {0}")]
37 ProgramConfigUnsupported(u8),
38
39 #[error("channelConfiguration 0 without a program config element leading the first raw data block")]
41 ProgramConfigMissing,
42
43 #[error("program config element truncated")]
45 ProgramConfigTruncated,
46
47 #[error("program config element declares no channels")]
49 ProgramConfigEmpty,
50}
51
52pub type Result<T> = std::result::Result<T, Error>;
53
54pub struct Config {
57 pub profile: u8,
58 pub sample_rate: u32,
59 pub channel_count: u32,
60}
61
62impl Config {
63 pub fn parse<T: Buf>(buf: &mut T) -> Result<Self> {
73 let mut reader = BitReader::new(buf);
74 let (object_type, sample_rate, channel_config) = read_header(&mut reader)?;
75 let channel_count = match channel_config {
76 0 => {
77 let core = read_core(&mut reader, object_type)?;
78 read_general_audio(&mut reader, core)?;
79 program_config(&mut reader)?
80 }
81 _ => channel_count_from_config(channel_config)?,
82 };
83
84 if buf.remaining() > 0 {
87 buf.advance(buf.remaining());
88 }
89
90 Ok(Self {
91 profile: object_type,
92 sample_rate,
93 channel_count,
94 })
95 }
96
97 pub fn encode(&self) -> Bytes {
102 let profile = self.profile & 0x1F;
104
105 let freq_index: u8 = match self.sample_rate {
106 96000 => 0,
107 88200 => 1,
108 64000 => 2,
109 48000 => 3,
110 44100 => 4,
111 32000 => 5,
112 24000 => 6,
113 22050 => 7,
114 16000 => 8,
115 12000 => 9,
116 11025 => 10,
117 8000 => 11,
118 7350 => 12,
119 _ => 0xF, };
121
122 let channel_config = channel_config_from_count(self.channel_count) as u64;
123
124 if freq_index != 0xF {
125 let b0 = (profile << 3) | (freq_index >> 1);
127 let b1 = ((freq_index & 1) << 7) | ((channel_config as u8 & 0x0F) << 3);
128 Bytes::from(vec![b0, b1])
129 } else {
130 let mut bits: u64 = 0;
132 bits |= (profile as u64) << 35;
133 bits |= 0xF_u64 << 31;
134 bits |= (self.sample_rate as u64) << 7;
135 bits |= (channel_config & 0xF) << 3;
136 let all = bits.to_be_bytes();
137 Bytes::copy_from_slice(&all[3..8])
138 }
139 }
140}
141
142fn read_header<T: Buf>(reader: &mut BitReader<T>) -> Result<(u8, u32, u8)> {
145 if reader.buf.remaining() < 2 {
146 return Err(Error::ConfigTooShort);
147 }
148 let object_type = read_object_type(reader)?;
149
150 let freq_index = reader.read(4, Error::IncompleteConfig)? as u8;
152 let sample_rate = if freq_index == 15 {
153 reader.read(24, Error::ExplicitSampleRateTooShort)?
154 } else {
155 *SAMPLE_RATES
156 .get(freq_index as usize)
157 .ok_or(Error::UnsupportedSampleRateIndex(freq_index))?
158 };
159
160 let channel_config = reader.read(4, Error::IncompleteConfig)? as u8;
162 Ok((object_type, sample_rate, channel_config))
163}
164
165fn read_core<T: Buf>(reader: &mut BitReader<T>, object_type: u8) -> Result<u8> {
168 if !matches!(object_type, 5 | 29) {
169 return Ok(object_type);
170 }
171 if reader.read(4, Error::IncompleteConfig)? == 15 {
172 reader.read(24, Error::IncompleteConfig)?;
173 }
174 let core = read_object_type(reader)?;
175 if core == 22 {
176 reader.read(4, Error::IncompleteConfig)?;
178 }
179 Ok(core)
180}
181
182fn read_general_audio<T: Buf>(reader: &mut BitReader<T>, core: u8) -> Result<()> {
185 if !GENERAL_AUDIO.contains(&core) {
186 return Err(Error::ProgramConfigUnsupported(core));
187 }
188
189 reader.read(1, Error::IncompleteConfig)?;
191 if reader.read(1, Error::IncompleteConfig)? == 1 {
192 reader.read(14, Error::IncompleteConfig)?;
193 }
194 reader.read(1, Error::IncompleteConfig)?;
195 Ok(())
196}
197
198pub(crate) fn in_band_config(profile: u8, sample_rate: u32, channel_config: u8, block: &mut &[u8]) -> Result<Bytes> {
205 let mut out = BitWriter::default();
206 out.write(5, u32::from(profile & 0x1F));
207 match SAMPLE_RATES.iter().position(|&rate| rate == sample_rate) {
208 Some(index) => out.write(4, index as u32),
209 None => {
210 out.write(4, 15);
211 out.write(24, sample_rate);
212 }
213 }
214 out.write(4, u32::from(channel_config));
215
216 if channel_config == 0 {
217 out.write(3, 0);
219
220 let mut reader = BitReader::new(block);
222 if reader.read(3, Error::ProgramConfigMissing)? != ID_PCE {
223 return Err(Error::ProgramConfigMissing);
224 }
225 reader.record = Some(out);
226 program_config(&mut reader)?;
227 out = reader.record.take().expect("recording set above");
228 }
229
230 Ok(Bytes::from(out.bytes))
231}
232
233#[derive(Clone, Debug, PartialEq)]
235pub(crate) struct InBand {
236 pub object_type: u8,
239 pub sample_rate: u32,
241 pub channel_config: u8,
242 pub program_config: Option<Bytes>,
245}
246
247pub(crate) fn in_band(asc: &[u8]) -> Result<InBand> {
250 let mut asc = asc;
251 let mut reader = BitReader::new(&mut asc);
252 let (object_type, sample_rate, channel_config) = read_header(&mut reader)?;
253 let core = read_core(&mut reader, object_type)?;
254
255 let program_config = match channel_config {
256 0 => {
257 read_general_audio(&mut reader, core)?;
258 let mut out = BitWriter::default();
259 out.write(3, ID_PCE);
260 reader.record = Some(out);
261 program_config(&mut reader)?;
262 Some(Bytes::from(reader.record.take().expect("recording set above").bytes))
263 }
264 _ => None,
265 };
266
267 Ok(InBand {
268 object_type: core,
269 sample_rate,
270 channel_config,
271 program_config,
272 })
273}
274
275const ID_PCE: u32 = 5;
277
278const GENERAL_AUDIO: [u8; 12] = [1, 2, 3, 4, 6, 7, 17, 19, 20, 21, 22, 23];
281
282fn read_object_type<T: Buf>(reader: &mut BitReader<T>) -> Result<u8> {
284 let object_type = reader.read(5, Error::ConfigTooShort)? as u8;
285 if object_type == 31 {
286 return Ok(32 + reader.read(6, Error::ExtendedConfigTooShort)? as u8);
287 }
288 Ok(object_type)
289}
290
291fn program_config<T: Buf>(reader: &mut BitReader<T>) -> Result<u32> {
296 let mut read = |n| reader.read(n, Error::ProgramConfigTruncated);
297
298 read(10)?;
300 let (front, side, back) = (read(4)?, read(4)?, read(4)?);
301 let (lfe, assoc, cc) = (read(2)?, read(3)?, read(4)?);
302 for bits in [4, 4, 3] {
304 if read(1)? == 1 {
305 read(bits)?;
306 }
307 }
308
309 let mut channels = lfe;
310 for _ in 0..front + side + back {
311 channels += 1 + read(1)?;
313 read(4)?;
314 }
315 for _ in 0..lfe + assoc {
317 read(4)?;
318 }
319 for _ in 0..cc {
320 read(5)?;
321 }
322
323 reader.align();
324 let comment = reader.read(8, Error::ProgramConfigTruncated)?;
325 for _ in 0..comment {
326 reader.read(8, Error::ProgramConfigTruncated)?;
327 }
328
329 if channels == 0 {
330 return Err(Error::ProgramConfigEmpty);
331 }
332 Ok(channels)
333}
334
335const SAMPLE_RATES: [u32; 13] = [
338 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350,
339];
340
341struct BitReader<'a, T: Buf> {
347 buf: &'a mut T,
348 current: u8,
349 bits_left: u8,
350 record: Option<BitWriter>,
352}
353
354impl<'a, T: Buf> BitReader<'a, T> {
355 fn new(buf: &'a mut T) -> Self {
356 Self {
357 buf,
358 current: 0,
359 bits_left: 0,
360 record: None,
361 }
362 }
363
364 fn align(&mut self) {
366 self.bits_left = 0;
367 if let Some(record) = &mut self.record {
368 record.align();
369 }
370 }
371
372 fn read(&mut self, n: u8, short: Error) -> Result<u32> {
374 let mut value = 0u32;
375 for _ in 0..n {
376 if self.bits_left == 0 {
377 if !self.buf.has_remaining() {
378 return Err(short);
379 }
380 self.current = self.buf.get_u8();
381 self.bits_left = 8;
382 }
383 self.bits_left -= 1;
384 value = (value << 1) | u32::from((self.current >> self.bits_left) & 1);
385 }
386 if let Some(record) = &mut self.record {
387 record.write(n, value);
388 }
389 Ok(value)
390 }
391}
392
393#[derive(Default)]
395struct BitWriter {
396 bytes: Vec<u8>,
397 used: u8,
399}
400
401impl BitWriter {
402 fn write(&mut self, n: u8, value: u32) {
404 for i in (0..n).rev() {
405 if self.used == 0 {
406 self.bytes.push(0);
407 }
408 let bit = ((value >> i) & 1) as u8;
409 *self.bytes.last_mut().expect("pushed above") |= bit << (7 - self.used);
410 self.used = (self.used + 1) % 8;
411 }
412 }
413
414 fn align(&mut self) {
416 self.used = 0;
417 }
418}
419
420fn channel_count_from_config(channel_config: u8) -> Result<u32> {
425 match channel_config {
426 1..=6 => Ok(channel_config as u32),
427 7 | 12 | 14 => Ok(8),
428 11 => Ok(7),
429 13 => Ok(24),
430 _ => Err(Error::ReservedChannelConfig(channel_config)),
431 }
432}
433
434fn channel_config_from_count(channel_count: u32) -> u8 {
437 match channel_count {
438 1..=6 => channel_count as u8,
439 8 => 7,
440 _ => {
441 tracing::warn!(channel_count, "unsupported channel count, defaulting to stereo");
442 2
443 }
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450
451 #[test]
452 fn parses_standard_2_byte_config() {
453 let buf = vec![0x12, 0x10];
457 let cfg = Config::parse(&mut buf.as_slice()).unwrap();
458 assert_eq!(cfg.profile, 2);
459 assert_eq!(cfg.sample_rate, 44100);
460 assert_eq!(cfg.channel_count, 2);
461 }
462
463 #[test]
464 fn round_trip_explicit_sample_rate() {
465 let cfg = Config {
469 profile: 2,
470 sample_rate: 44_056, channel_count: 2,
472 };
473 let encoded = cfg.encode();
474 assert_eq!(encoded.len(), 5, "explicit-rate config is 5 bytes");
475
476 let parsed = Config::parse(&mut encoded.as_ref()).unwrap();
477 assert_eq!(parsed.profile, 2);
478 assert_eq!(parsed.sample_rate, 44_056);
479 assert_eq!(parsed.channel_count, 2);
480 }
481
482 #[test]
483 fn parses_extended_object_type() {
484 let buf: [u8; 3] = [0xF8, 0x86, 0x40];
488 let cfg = Config::parse(&mut buf.as_slice()).unwrap();
489 assert_eq!(cfg.profile, 36);
490 assert_eq!(cfg.sample_rate, 48_000);
491 assert_eq!(cfg.channel_count, 2);
492 }
493
494 #[test]
495 fn round_trip_5_1_channels() {
496 let cfg = Config {
498 profile: 2,
499 sample_rate: 48000,
500 channel_count: 6,
501 };
502 let encoded = cfg.encode();
503 let parsed = Config::parse(&mut encoded.as_ref()).unwrap();
504 assert_eq!(parsed.channel_count, 6);
505 }
506
507 #[test]
508 fn round_trip_7_1_channels() {
509 let cfg = Config {
511 profile: 2,
512 sample_rate: 48000,
513 channel_count: 8,
514 };
515 let encoded = cfg.encode();
516 let parsed = Config::parse(&mut encoded.as_ref()).unwrap();
517 assert_eq!(parsed.channel_count, 8, "7.1 surround should round-trip as 8 channels");
518 }
519
520 const FFMPEG_QUAD_ASC: [u8; 24] = [
524 0x11, 0x80, 0x04, 0xC4, 0x04, 0x00, 0x21, 0x10, 0x0C, 0x4C, 0x61, 0x76, 0x63, 0x36, 0x33, 0x2E, 0x31, 0x2E,
525 0x31, 0x30, 0x31, 0x56, 0xE5, 0x00,
526 ];
527
528 fn write_pce(out: &mut BitWriter, front: &[bool], side: &[bool], back: &[bool], lfe: u32) {
531 out.write(4, 0);
533 out.write(2, 1);
534 out.write(4, 3);
535 out.write(4, front.len() as u32);
536 out.write(4, side.len() as u32);
537 out.write(4, back.len() as u32);
538 out.write(2, lfe);
539 out.write(3, 0);
541 out.write(4, 0);
542 out.write(3, 0);
543 for (tag, &cpe) in front.iter().chain(side).chain(back).enumerate() {
544 out.write(1, cpe.into());
545 out.write(4, tag as u32);
546 }
547 for tag in 0..lfe {
548 out.write(4, tag);
549 }
550 out.align();
551 out.write(8, 1);
553 out.write(8, b'x'.into());
554 }
555
556 fn pce_asc(object_type: u8, front: &[bool], side: &[bool], back: &[bool], lfe: u32) -> Vec<u8> {
558 let mut out = BitWriter::default();
559 out.write(5, object_type.into());
560 out.write(4, 3);
561 out.write(4, 0);
562 out.write(3, 0);
563 write_pce(&mut out, front, side, back, lfe);
564 out.bytes
565 }
566
567 #[test]
568 fn parses_ffmpeg_program_config_element() {
569 let cfg = Config::parse(&mut FFMPEG_QUAD_ASC.as_slice()).unwrap();
570 assert_eq!(cfg.profile, 2);
571 assert_eq!(cfg.sample_rate, 48_000);
572 assert_eq!(cfg.channel_count, 4, "two channel pair elements");
573 }
574
575 #[test]
576 fn parses_program_config_element_counts() {
577 let asc = pce_asc(2, &[false, true], &[], &[true], 1);
579 assert_eq!(Config::parse(&mut asc.as_slice()).unwrap().channel_count, 6);
580
581 let asc = pce_asc(2, &[false, true], &[true], &[true], 0);
583 assert_eq!(Config::parse(&mut asc.as_slice()).unwrap().channel_count, 7);
584 }
585
586 fn sbr_pce_asc() -> Vec<u8> {
589 let mut out = BitWriter::default();
590 out.write(5, 5);
591 out.write(4, 6);
592 out.write(4, 0);
593 out.write(4, 3);
594 out.write(5, 2);
595 out.write(3, 0);
596 write_pce(&mut out, &[true], &[], &[true], 0);
597 out.bytes
598 }
599
600 #[test]
601 fn parses_program_config_element_behind_explicit_sbr() {
602 let cfg = Config::parse(&mut sbr_pce_asc().as_slice()).unwrap();
603 assert_eq!(cfg.profile, 5);
604 assert_eq!(cfg.channel_count, 4);
605 }
606
607 #[test]
608 fn refuses_bad_program_config_elements() {
609 let asc = pce_asc(2, &[], &[], &[], 0);
610 assert!(matches!(
611 Config::parse(&mut asc.as_slice()),
612 Err(Error::ProgramConfigEmpty)
613 ));
614
615 let asc = pce_asc(2, &[true], &[], &[], 0);
616 assert!(matches!(
617 Config::parse(&mut &asc[..asc.len() - 1]),
618 Err(Error::ProgramConfigTruncated)
619 ));
620
621 let mut out = BitWriter::default();
623 out.write(5, 31);
624 out.write(6, 4);
625 out.write(4, 3);
626 out.write(4, 0);
627 out.write(8, 0);
628 assert!(matches!(
629 Config::parse(&mut out.bytes.as_slice()),
630 Err(Error::ProgramConfigUnsupported(36))
631 ));
632 }
633
634 #[test]
635 fn channel_config_dispositions() {
636 let expected = [1, 2, 3, 4, 5, 6, 8];
637 for (config, count) in (1..=7).zip(expected) {
638 let asc = [0x11, 0x80 | (config << 3)];
639 assert_eq!(Config::parse(&mut asc.as_slice()).unwrap().channel_count, count);
640 }
641
642 for (config, count) in [(11, 7), (12, 8), (13, 24), (14, 8)] {
643 let asc = [0x11, 0x80 | (config << 3)];
644 assert_eq!(Config::parse(&mut asc.as_slice()).unwrap().channel_count, count);
645 }
646
647 for config in [8, 9, 10, 15] {
648 let asc = [0x11, 0x80 | (config << 3)];
649 assert!(matches!(
650 Config::parse(&mut asc.as_slice()),
651 Err(Error::ReservedChannelConfig(c)) if c == config
652 ));
653 }
654 }
655
656 #[test]
657 fn in_band_config_moves_the_program_config_element() {
658 let mut block = BitWriter::default();
661 block.write(3, ID_PCE);
662 write_pce(&mut block, &[false, true], &[], &[true], 1);
663 let pce = block.bytes.clone();
664 block.write(8, 0xFF);
666
667 let mut rest = block.bytes.as_slice();
668 let asc = in_band_config(2, 48_000, 0, &mut rest).unwrap();
669 assert_eq!(asc, pce_asc(2, &[false, true], &[], &[true], 1));
670 assert_eq!(Config::parse(&mut asc.as_ref()).unwrap().channel_count, 6);
671 assert_eq!(rest, [0xFF], "the element moves out of the block");
672
673 let in_band = in_band(&asc).unwrap();
675 assert_eq!(in_band.channel_config, 0);
676 assert_eq!(in_band.program_config, Some(Bytes::from(pce)));
677 }
678
679 #[test]
680 fn in_band_of_ffmpeg_program_config_element() {
681 let in_band = in_band(&FFMPEG_QUAD_ASC).unwrap();
684 assert_eq!(in_band.channel_config, 0);
685 let pce = in_band.program_config.unwrap();
686 let mut block = pce.as_ref();
687 let asc = in_band_config(2, 48_000, 0, &mut block).unwrap();
688 assert!(block.is_empty(), "the element is all that was framed");
689 assert_eq!(asc, FFMPEG_QUAD_ASC[..FFMPEG_QUAD_ASC.len() - 3]);
690 }
691
692 #[test]
693 fn in_band_without_a_program_config_element() {
694 let stereo = in_band(&[0x11, 0x90]).unwrap();
695 assert_eq!((stereo.channel_config, stereo.program_config), (2, None));
696 assert_eq!(in_band(&[0x11, 0xE0]).unwrap().channel_config, 12);
697 }
698
699 #[test]
700 fn in_band_of_explicit_sbr_is_its_lc_core() {
701 for (asc, channel_config) in [([0x2B, 0x11, 0x88, 0x00], 2), ([0xEB, 0x09, 0x88, 0x00], 1)] {
704 let expected = InBand {
705 object_type: 2,
706 sample_rate: 24_000,
707 channel_config,
708 program_config: None,
709 };
710 assert_eq!(in_band(&asc).unwrap(), expected);
711 }
712
713 assert!(matches!(in_band(&[0x2A, 0x10]), Err(Error::IncompleteConfig)));
715 }
716
717 #[test]
718 fn in_band_of_explicit_sbr_keeps_its_program_config_element() {
719 let in_band = in_band(&sbr_pce_asc()).unwrap();
720 assert_eq!(in_band.object_type, 2);
721 assert_eq!(in_band.sample_rate, 24_000);
722 assert_eq!(in_band.channel_config, 0);
723 let pce = in_band.program_config.expect("a program config element");
724 let mut block = pce.as_ref();
725 let asc = in_band_config(2, 24_000, 0, &mut block).unwrap();
726 assert_eq!(Config::parse(&mut asc.as_ref()).unwrap().channel_count, 4);
727 }
728
729 #[test]
730 fn in_band_config_refuses_a_block_without_a_leading_pce() {
731 assert!(matches!(
733 in_band_config(2, 48_000, 0, &mut [0x20, 0x00].as_slice()),
734 Err(Error::ProgramConfigMissing)
735 ));
736 assert!(matches!(
737 in_band_config(2, 48_000, 0, &mut [].as_slice()),
738 Err(Error::ProgramConfigMissing)
739 ));
740 }
741
742 #[test]
743 fn in_band_config_matches_encode() {
744 let asc = in_band_config(2, 44_100, 2, &mut [].as_slice()).unwrap();
746 let encoded = Config {
747 profile: 2,
748 sample_rate: 44_100,
749 channel_count: 2,
750 }
751 .encode();
752 assert_eq!(asc, encoded);
753 }
754
755 #[test]
756 fn unsupported_channel_count_falls_back_to_stereo_config() {
757 assert_eq!(channel_config_from_count(9), 2);
758 }
759}