1#![forbid(unsafe_code)]
4
5use crate::error::Error;
6use crate::types::{AdtsConfig, sampling_frequency_index};
7
8const HEADER_LEN: usize = 7;
9const MAX_FRAME_LEN: usize = 0x1FFF; const BUFFER_FULLNESS_UNKNOWN: u16 = 0x7FF; #[derive(Debug, Clone, Copy)]
18pub struct Muxer {
19 config: AdtsConfig,
20 sfi: u8,
21}
22
23impl Muxer {
24 pub fn new(config: AdtsConfig) -> Result<Self, Error> {
26 let sfi = sampling_frequency_index(config.sample_rate)
27 .ok_or(Error::UnsupportedSampleRate(config.sample_rate))?;
28 Ok(Self { config, sfi })
29 }
30
31 #[allow(
33 clippy::cast_possible_truncation,
34 reason = "every cast operand is bit-masked to fit u8 immediately before the cast"
35 )]
36 pub fn write_frame(&self, raw_aac: &[u8], out: &mut Vec<u8>) -> Result<(), Error> {
37 let frame_len = HEADER_LEN + raw_aac.len();
38 if frame_len > MAX_FRAME_LEN {
39 return Err(Error::FrameTooLarge(frame_len));
40 }
41 let profile = self.config.profile.bits();
42 let channels = self.config.channels & 0x07;
43 let fullness = usize::from(BUFFER_FULLNESS_UNKNOWN);
44
45 out.push(0xFF);
46 out.push(0xF1); out.push((profile << 6) | (self.sfi << 2) | (channels >> 2));
48 out.push(((channels & 0x03) << 6) | ((frame_len >> 11) & 0x03) as u8);
49 out.push(((frame_len >> 3) & 0xFF) as u8);
50 out.push((((frame_len & 0x07) as u8) << 5) | ((fullness >> 6) & 0x1F) as u8);
51 out.push(((fullness & 0x3F) as u8) << 2); out.extend_from_slice(raw_aac);
53 Ok(())
54 }
55}
56
57#[cfg(test)]
58#[path = "mux_tests.rs"]
59mod tests;