use alloc::vec::Vec;
use broadcast_common::bits::{BitReader, BitWriter};
use broadcast_common::{Parse, Serialize};
use crate::error::{Error, Result};
use crate::plex::{plex_bits, read_plex, write_plex};
use crate::util::{expect_fully_consumed, read_reserved, write_reserved};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum ChannelId {
LeftScreen,
LeftCenterScreen,
CenterScreen,
RightCenterScreen,
RightScreen,
LeftSideSurround71,
LeftSurround,
LeftRearSurround71,
RightRearSurround71,
RightSideSurround71,
RightSurround,
LeftTopSurround91,
RightTopSurround91,
Lfe,
Reserved(u8),
}
impl ChannelId {
#[must_use]
pub fn name(&self) -> &'static str {
match self {
Self::LeftScreen => "left screen speaker",
Self::LeftCenterScreen => "left center screen speaker",
Self::CenterScreen => "center screen speaker",
Self::RightCenterScreen => "right center screen speaker",
Self::RightScreen => "right screen speaker",
Self::LeftSideSurround71 => "left side surround speaker (7.1)",
Self::LeftSurround => "left surround speaker",
Self::LeftRearSurround71 => "left rear surround speaker (7.1)",
Self::RightRearSurround71 => "right rear surround speaker (7.1)",
Self::RightSideSurround71 => "right side surround speaker (7.1)",
Self::RightSurround => "right surround speaker",
Self::LeftTopSurround91 => "left top surround speaker (9.1)",
Self::RightTopSurround91 => "right top surround speaker (9.1)",
Self::Lfe => "lfe speaker",
Self::Reserved(_) => "reserved",
}
}
fn from_bits(bits: u64) -> Self {
match bits {
0x0 => Self::LeftScreen,
0x1 => Self::LeftCenterScreen,
0x2 => Self::CenterScreen,
0x3 => Self::RightCenterScreen,
0x4 => Self::RightScreen,
0x5 => Self::LeftSideSurround71,
0x6 => Self::LeftSurround,
0x7 => Self::LeftRearSurround71,
0x8 => Self::RightRearSurround71,
0x9 => Self::RightSideSurround71,
0xA => Self::RightSurround,
0xB => Self::LeftTopSurround91,
0xC => Self::RightTopSurround91,
0xD => Self::Lfe,
other => Self::Reserved(other as u8),
}
}
fn to_bits(self) -> u64 {
match self {
Self::LeftScreen => 0x0,
Self::LeftCenterScreen => 0x1,
Self::CenterScreen => 0x2,
Self::RightCenterScreen => 0x3,
Self::RightScreen => 0x4,
Self::LeftSideSurround71 => 0x5,
Self::LeftSurround => 0x6,
Self::LeftRearSurround71 => 0x7,
Self::RightRearSurround71 => 0x8,
Self::RightSideSurround71 => 0x9,
Self::RightSurround => 0xA,
Self::LeftTopSurround91 => 0xB,
Self::RightTopSurround91 => 0xC,
Self::Lfe => 0xD,
Self::Reserved(v) => u64::from(v),
}
}
}
broadcast_common::impl_spec_display!(ChannelId, Reserved);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BedChannel {
pub channel_id: ChannelId,
pub audio_data_id: u32,
}
const RESERVED_PRE_CHANNEL_COUNT: u64 = 0;
const RESERVED_PER_CHANNEL: u64 = 0;
const RESERVED_TRAILER_1: u64 = 0x180;
const RESERVED_TRAILER_2: u64 = 0x5;
const RESERVED_TRAILER_3: u64 = 0;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BedDefinition1 {
pub meta_id: u32,
pub channels: Vec<BedChannel>,
}
impl BedDefinition1 {
#[must_use]
pub fn new(meta_id: u32, channels: Vec<BedChannel>) -> Self {
Self { meta_id, channels }
}
}
impl<'a> Parse<'a> for BedDefinition1 {
type Error = Error;
fn parse(bytes: &'a [u8]) -> Result<Self> {
let mut r = BitReader::new(bytes);
let meta_id = read_plex(&mut r, 8, "BedDefinition1.MetaID")? as u32;
read_reserved(
&mut r,
1,
RESERVED_PRE_CHANNEL_COUNT,
"BedDefinition1.Reserved(pre-ChannelCount)",
)?;
let channel_count = read_plex(&mut r, 4, "BedDefinition1.ChannelCount")?;
let mut channels = Vec::with_capacity(channel_count as usize);
for _ in 0..channel_count {
let channel_id =
ChannelId::from_bits(read_plex(&mut r, 4, "BedDefinition1.ChannelID")?);
let audio_data_id = read_plex(&mut r, 8, "BedDefinition1.AudioDataID")? as u32;
read_reserved(
&mut r,
3,
RESERVED_PER_CHANNEL,
"BedDefinition1.Reserved(per-channel)",
)?;
channels.push(BedChannel {
channel_id,
audio_data_id,
});
}
read_reserved(
&mut r,
10,
RESERVED_TRAILER_1,
"BedDefinition1.Reserved(trailer1)",
)?;
r.align_to_byte();
read_reserved(
&mut r,
8,
RESERVED_TRAILER_2,
"BedDefinition1.Reserved(trailer2)",
)?;
read_reserved(
&mut r,
8,
RESERVED_TRAILER_3,
"BedDefinition1.Reserved(trailer3)",
)?;
expect_fully_consumed(&r, "BedDefinition1")?;
Ok(Self { meta_id, channels })
}
}
impl Serialize for BedDefinition1 {
type Error = Error;
fn serialized_len(&self) -> usize {
let mut bits = plex_bits(u64::from(self.meta_id), 8) + 1;
bits += plex_bits(self.channels.len() as u64, 4);
for ch in &self.channels {
bits += plex_bits(ch.channel_id.to_bits(), 4);
bits += plex_bits(u64::from(ch.audio_data_id), 8);
bits += 3;
}
bits += 10;
let pre_trailer_bytes = (bits as usize).div_ceil(8);
pre_trailer_bytes + 1 + 1
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
let need = self.serialized_len();
if buf.len() < need {
return Err(Error::BufferTooShort {
need,
have: buf.len(),
what: "BedDefinition1",
});
}
let mut w = BitWriter::new(&mut buf[..need]);
write_plex(&mut w, u64::from(self.meta_id), 8, "BedDefinition1.MetaID")?;
write_reserved(
&mut w,
1,
RESERVED_PRE_CHANNEL_COUNT,
"BedDefinition1.Reserved(pre-ChannelCount)",
)?;
write_plex(
&mut w,
self.channels.len() as u64,
4,
"BedDefinition1.ChannelCount",
)?;
for ch in &self.channels {
write_plex(
&mut w,
ch.channel_id.to_bits(),
4,
"BedDefinition1.ChannelID",
)?;
write_plex(
&mut w,
u64::from(ch.audio_data_id),
8,
"BedDefinition1.AudioDataID",
)?;
write_reserved(
&mut w,
3,
RESERVED_PER_CHANNEL,
"BedDefinition1.Reserved(per-channel)",
)?;
}
write_reserved(
&mut w,
10,
RESERVED_TRAILER_1,
"BedDefinition1.Reserved(trailer1)",
)?;
w.align_to_byte().map_err(|source| Error::Bits {
what: "BedDefinition1.AlignBits",
source,
})?;
write_reserved(
&mut w,
8,
RESERVED_TRAILER_2,
"BedDefinition1.Reserved(trailer2)",
)?;
write_reserved(
&mut w,
8,
RESERVED_TRAILER_3,
"BedDefinition1.Reserved(trailer3)",
)?;
Ok(need)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample() -> BedDefinition1 {
BedDefinition1::new(
7,
alloc::vec![
BedChannel {
channel_id: ChannelId::LeftScreen,
audio_data_id: 1,
},
BedChannel {
channel_id: ChannelId::RightScreen,
audio_data_id: 2,
},
BedChannel {
channel_id: ChannelId::Lfe,
audio_data_id: 3,
},
],
)
}
#[test]
fn round_trips() {
let bed = sample();
let bytes = bed.to_bytes();
let parsed = BedDefinition1::parse(&bytes).unwrap();
assert_eq!(parsed, bed);
let bytes2 = parsed.to_bytes();
assert_eq!(bytes, bytes2);
}
#[test]
fn trailer_constants_are_validated() {
let bed = sample();
let mut bytes = bed.to_bytes();
let last = bytes.len() - 2;
bytes[last] = 0xAA; let err = BedDefinition1::parse(&bytes).unwrap_err();
assert!(matches!(err, Error::InvalidReserved { .. }));
}
#[test]
fn empty_bed_round_trips() {
let bed = BedDefinition1::new(0, Vec::new());
let bytes = bed.to_bytes();
let parsed = BedDefinition1::parse(&bytes).unwrap();
assert_eq!(parsed, bed);
}
#[test]
fn mutating_meta_id_changes_only_meta_id_bytes() {
let mut bed = sample();
let original = bed.to_bytes();
bed.meta_id = 200; let mutated = bed.to_bytes();
assert_ne!(original[0], mutated[0]);
assert_eq!(&original[1..], &mutated[1..]);
}
}