blob: a5c23a5bdd4a036c92c84af9b3c379fded30df27 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::collections::HashSet;
use std::ops::RangeBounds;
use crate::core::ltv::LtValue;
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
pub enum CodecCapabilityType {
SupportedSamplingFrequencies,
SupportedFrameDurations,
SupportedAudioChannelCounts,
SupportedOctetsPerCodecFrame,
SupportedMaxCodecFramesPerSdu,
}
impl From<CodecCapabilityType> for u8 {
fn from(value: CodecCapabilityType) -> Self {
match value {
CodecCapabilityType::SupportedSamplingFrequencies => 1,
CodecCapabilityType::SupportedFrameDurations => 2,
CodecCapabilityType::SupportedAudioChannelCounts => 3,
CodecCapabilityType::SupportedOctetsPerCodecFrame => 4,
CodecCapabilityType::SupportedMaxCodecFramesPerSdu => 5,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum FrameDurationSupport {
SevenFiveMs,
TenMs,
BothNoPreference,
PreferSevenFiveMs,
PreferTenMs,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum SamplingFrequency {
F8000Hz,
F11025Hz,
F16000Hz,
F22050Hz,
F24000Hz,
F32000Hz,
F44100Hz,
F48000Hz,
F88200Hz,
F96000Hz,
F176400Hz,
F192000Hz,
F384000Hz,
}
impl SamplingFrequency {
fn bitpos(&self) -> u8 {
match self {
SamplingFrequency::F8000Hz => 0,
SamplingFrequency::F11025Hz => 1,
SamplingFrequency::F16000Hz => 2,
SamplingFrequency::F22050Hz => 3,
SamplingFrequency::F24000Hz => 4,
SamplingFrequency::F32000Hz => 5,
SamplingFrequency::F44100Hz => 6,
SamplingFrequency::F48000Hz => 7,
SamplingFrequency::F88200Hz => 8,
SamplingFrequency::F96000Hz => 9,
SamplingFrequency::F176400Hz => 10,
SamplingFrequency::F192000Hz => 11,
SamplingFrequency::F384000Hz => 12,
}
}
fn from_bitpos(value: u8) -> Option<Self> {
match value {
0 => Some(SamplingFrequency::F8000Hz),
1 => Some(SamplingFrequency::F11025Hz),
2 => Some(SamplingFrequency::F16000Hz),
3 => Some(SamplingFrequency::F22050Hz),
4 => Some(SamplingFrequency::F24000Hz),
5 => Some(SamplingFrequency::F32000Hz),
6 => Some(SamplingFrequency::F44100Hz),
7 => Some(SamplingFrequency::F48000Hz),
8 => Some(SamplingFrequency::F88200Hz),
9 => Some(SamplingFrequency::F96000Hz),
10 => Some(SamplingFrequency::F176400Hz),
11 => Some(SamplingFrequency::F192000Hz),
12 => Some(SamplingFrequency::F384000Hz),
_ => None,
}
}
}
/// Codec Capability LTV Structures
///
/// Defined in Assigned Numbers Section 6.12.4.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CodecCapability {
SupportedSamplingFrequencies(std::collections::HashSet<SamplingFrequency>),
SupportedFrameDurations(FrameDurationSupport),
SupportedAudioChannelCounts(std::collections::HashSet<u8>),
SupportedMaxCodecFramesPerSdu(u8),
SupportedOctetsPerCodecFrame { min: u16, max: u16 },
}
impl LtValue for CodecCapability {
type Type = CodecCapabilityType;
const NAME: &'static str = "Codec Compatability";
fn type_from_octet(x: u8) -> Option<Self::Type> {
match x {
1 => Some(CodecCapabilityType::SupportedSamplingFrequencies),
2 => Some(CodecCapabilityType::SupportedFrameDurations),
3 => Some(CodecCapabilityType::SupportedAudioChannelCounts),
4 => Some(CodecCapabilityType::SupportedOctetsPerCodecFrame),
5 => Some(CodecCapabilityType::SupportedMaxCodecFramesPerSdu),
_ => None,
}
}
fn length_range_from_type(ty: Self::Type) -> std::ops::RangeInclusive<u8> {
match ty {
CodecCapabilityType::SupportedAudioChannelCounts => 2..=2,
CodecCapabilityType::SupportedFrameDurations => 2..=2,
CodecCapabilityType::SupportedMaxCodecFramesPerSdu => 2..=2,
CodecCapabilityType::SupportedOctetsPerCodecFrame => 5..=5,
CodecCapabilityType::SupportedSamplingFrequencies => 3..=3,
}
}
fn into_type(&self) -> Self::Type {
match self {
CodecCapability::SupportedAudioChannelCounts(_) => {
CodecCapabilityType::SupportedAudioChannelCounts
}
CodecCapability::SupportedFrameDurations(_) => {
CodecCapabilityType::SupportedFrameDurations
}
CodecCapability::SupportedMaxCodecFramesPerSdu(_) => {
CodecCapabilityType::SupportedMaxCodecFramesPerSdu
}
CodecCapability::SupportedOctetsPerCodecFrame { .. } => {
CodecCapabilityType::SupportedOctetsPerCodecFrame
}
CodecCapability::SupportedSamplingFrequencies(_) => {
CodecCapabilityType::SupportedSamplingFrequencies
}
}
}
fn value_encoded_len(&self) -> u8 {
// All the CodecCapabilities are constant length. Remove the type octet.
let range = Self::length_range_from_type(self.into_type());
let std::ops::Bound::Included(len) = range.start_bound() else {
unreachable!();
};
(len - 1).into()
}
fn encode_value(&self, buf: &mut [u8]) -> Result<(), crate::packet_encoding::Error> {
match self {
CodecCapability::SupportedAudioChannelCounts(counts) => {
buf[0] = counts
.iter()
.fold(0, |acc, count| if *count > 8 { acc } else { acc | (1 << (*count - 1)) });
}
CodecCapability::SupportedFrameDurations(support) => {
buf[0] = match support {
FrameDurationSupport::SevenFiveMs => 0b000001,
FrameDurationSupport::TenMs => 0b000010,
FrameDurationSupport::BothNoPreference => 0b000011,
FrameDurationSupport::PreferSevenFiveMs => 0b010011,
FrameDurationSupport::PreferTenMs => 0b100011,
};
}
CodecCapability::SupportedMaxCodecFramesPerSdu(max) => {
buf[0] = *max;
}
CodecCapability::SupportedOctetsPerCodecFrame { min, max } => {
let min_bytes = min.to_le_bytes();
buf[0..=1].copy_from_slice(&min_bytes);
let max_bytes = max.to_le_bytes();
buf[2..=3].copy_from_slice(&max_bytes);
}
CodecCapability::SupportedSamplingFrequencies(supported) => {
let sup_bytes = supported
.iter()
.fold(0u16, |acc, freq| acc | (1 << freq.bitpos()))
.to_le_bytes();
buf[0..=1].copy_from_slice(&sup_bytes)
}
};
Ok(())
}
fn decode_value(
ty: &CodecCapabilityType,
buf: &[u8],
) -> Result<Self, crate::packet_encoding::Error> {
match ty {
CodecCapabilityType::SupportedAudioChannelCounts => {
let mut supported = HashSet::new();
for bitpos in 0..8 {
if (buf[0] & (1 << bitpos)) != 0 {
supported.insert(bitpos + 1);
}
}
Ok(Self::SupportedAudioChannelCounts(supported))
}
CodecCapabilityType::SupportedFrameDurations => {
let support = match buf[0] & 0b110011 {
0b000001 => FrameDurationSupport::SevenFiveMs,
0b000010 => FrameDurationSupport::TenMs,
0b000011 => FrameDurationSupport::BothNoPreference,
0b010011 => FrameDurationSupport::PreferSevenFiveMs,
0b100011 => FrameDurationSupport::PreferTenMs,
_ => {
return Err(crate::packet_encoding::Error::InvalidParameter(format!(
"Unrecognized bit pattern: {:#b}",
buf[0]
)));
}
};
Ok(Self::SupportedFrameDurations(support))
}
CodecCapabilityType::SupportedMaxCodecFramesPerSdu => {
Ok(Self::SupportedMaxCodecFramesPerSdu(buf[0]))
}
CodecCapabilityType::SupportedOctetsPerCodecFrame => {
let min = u16::from_le_bytes([buf[0], buf[1]]);
let max = u16::from_le_bytes([buf[2], buf[3]]);
Ok(Self::SupportedOctetsPerCodecFrame { min, max })
}
CodecCapabilityType::SupportedSamplingFrequencies => {
let bitflags = u16::from_le_bytes([buf[0], buf[1]]);
let mut supported = HashSet::new();
for bitpos in 0..13 {
if bitflags & (1 << bitpos) != 0 {
let Some(f) = SamplingFrequency::from_bitpos(bitpos) else {
continue;
};
let _ = supported.insert(f);
}
}
Ok(Self::SupportedSamplingFrequencies(supported))
}
}
}
}
#[cfg(test)]
mod tests {}