blob: a5cc076c44a9c62477c5c7bda0ab7e14f407c97f [file] [log] [blame]
// Copyright 2019 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 bitfield::bitfield;
use bitflags::bitflags;
use bt_avdtp as avdtp;
bitflags! {
/// Sampling Frequency field for SBC (Octet 0; b4-7).
/// 44100Hz and 48000Hz are mandatory for A2DP sink.
/// A2DP source must support at least one of 44100Hz and 48000Hz.
/// A2DP Sec. 4.3.2.1
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SbcSamplingFrequency:u8 {
const FREQ16000HZ = 0b1000;
const FREQ32000HZ = 0b0100;
const FREQ44100HZ = 0b0010;
const FREQ48000HZ = 0b0001;
const MANDATORY_SNK = Self::FREQ44100HZ.bits() | Self::FREQ48000HZ.bits();
}
}
impl SbcSamplingFrequency {
/// Select the "best" sampling frequency of the ones available.
fn best(&self) -> Option<Self> {
let ordered = [Self::FREQ48000HZ, Self::FREQ44100HZ, Self::FREQ32000HZ, Self::FREQ16000HZ];
ordered.iter().find(|freq| self.contains(**freq)).copied()
}
}
bitflags! {
/// Channel Mode field for SBC (Octet 0; b0-3).
/// Support for all modes is mandatory in A2DP sink.
/// Mono and at least one of Dual Channel, Stereo, and Joint Stereo must be
/// supported by A2DP source.
/// A2DP Sec. 4.3.2.2
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SbcChannelMode:u8 {
const MONO = 0b1000;
const DUAL_CHANNEL = 0b0100;
const STEREO = 0b0010;
const JOINT_STEREO = 0b0001;
const MANDATORY_SNK = Self::MONO.bits()
| Self::DUAL_CHANNEL.bits()
| Self::STEREO.bits()
| Self::JOINT_STEREO.bits();
}
}
impl SbcChannelMode {
fn best(&self) -> Option<Self> {
let ordered = [Self::JOINT_STEREO, Self::STEREO, Self::DUAL_CHANNEL, Self::MONO];
ordered.iter().find(|mode| self.contains(**mode)).copied()
}
}
bitflags! {
/// The Block Length field for SBC (Octet 1; b4-7).
/// Support for all block lengths is mandatory in both A2DP Sink and Source.
/// A2DP Sec. 4.3.2.3
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SbcBlockCount:u8 {
const FOUR = 0b1000;
const EIGHT = 0b0100;
const TWELVE = 0b0010;
const SIXTEEN = 0b0001;
const MANDATORY_SNK = Self::FOUR.bits()
| Self::EIGHT.bits()
| Self::TWELVE.bits()
| Self::SIXTEEN.bits();
const MANDATORY_SRC = Self::FOUR.bits()
| Self::EIGHT.bits()
| Self::TWELVE.bits()
| Self::SIXTEEN.bits();
}
}
bitflags! {
/// The Number of Subbands field for SBC (Octet 1; b2-3).
/// Support for both 4 and 8 subbands is mandatory in A2DP Sink.
/// Support for only 8 subbands is mandatory in A2DP Source.
/// 4 subbands is optional.
/// A2DP Sec. 4.3.2.4
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SbcSubBands:u8 {
const FOUR = 0b0010;
const EIGHT = 0b0001;
const MANDATORY_SNK = Self::FOUR.bits() | Self::EIGHT.bits();
const MANDATORY_SRC = Self::EIGHT.bits();
}
}
bitflags! {
/// Allocation Method field for SBC (Octet 1; b0-1).
/// Support for both SNR and Loudness is mandatory in A2DP Sink.
/// Support for at least Loudness is mandatory in A2DP Source. SNR is optional.
/// A2DP Sec. 4.3.2.5
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SbcAllocation:u8 {
const SNR = 0b0010;
const LOUDNESS = 0b0001;
const MANDATORY_SNK = Self::SNR.bits() | Self::LOUDNESS.bits();
const MANDATORY_SRC = Self::LOUDNESS.bits();
}
}
pub const SBC_CODEC_EXTRA_LEN: usize = 4;
bitfield! {
/// SBC Codec Specific Information Elements (A2DP Sec. 4.3.2).
/// Packet structure:
/// Octet0: Sampling Frequency (b4-7), Channel Mode (b0-3)
/// Octet1: Block Length (b4-7), Subbands (b2-3), Allocation Method (b0-1)
/// Octet2: Minimum Bitpool Value [2,250]
/// Octet3: Maximum Bitpool Value [2,250]
/// Some fields are mandatory choose 1, and therefore do not have a mandatory parameter method.
struct SbcCodecInfoBits(u32);
impl Debug;
u8;
maxbitpoolval, set_maxbpv: 7, 0;
minbitpoolval, set_minbpv: 15, 8;
allocation_method, set_allocation_method: 17,16;
sub_bands, set_sub_bands: 19, 18;
block_count, set_block_count: 23, 20;
channel_mode, set_channel_mode: 27, 24;
sampling_frequency, set_sampling_frequency: 31, 28;
}
#[derive(Debug)]
pub struct SbcCodecInfo(SbcCodecInfoBits);
impl SbcCodecInfo {
// Bitpool values can range from [2,250].
pub const BITPOOL_MIN: u8 = 2;
pub const BITPOOL_MAX: u8 = 250;
pub fn new(
sampling_frequency: SbcSamplingFrequency,
channel_mode: SbcChannelMode,
block_count: SbcBlockCount,
sub_bands: SbcSubBands,
allocation: SbcAllocation,
min_bpv: u8,
max_bpv: u8,
) -> avdtp::Result<Self> {
if min_bpv > max_bpv {
return Err(avdtp::Error::OutOfRange);
}
if min_bpv < Self::BITPOOL_MIN
|| min_bpv > Self::BITPOOL_MAX
|| max_bpv < Self::BITPOOL_MIN
|| max_bpv > Self::BITPOOL_MAX
{
return Err(avdtp::Error::OutOfRange);
}
let mut res = SbcCodecInfoBits(0);
res.set_maxbpv(max_bpv);
res.set_minbpv(min_bpv);
res.set_allocation_method(allocation.bits());
res.set_sub_bands(sub_bands.bits());
res.set_block_count(block_count.bits());
res.set_channel_mode(channel_mode.bits());
res.set_sampling_frequency(sampling_frequency.bits());
Ok(Self(res))
}
pub fn to_bytes(&self) -> [u8; 4] {
(self.0).0.to_be_bytes()
}
pub fn sub_bands(&self) -> SbcSubBands {
SbcSubBands::from_bits_truncate(self.0.sub_bands())
}
pub fn allocation_method(&self) -> SbcAllocation {
SbcAllocation::from_bits_truncate(self.0.allocation_method())
}
pub fn block_count(&self) -> SbcBlockCount {
SbcBlockCount::from_bits_truncate(self.0.block_count())
}
pub fn channel_mode(&self) -> SbcChannelMode {
SbcChannelMode::from_bits_truncate(self.0.channel_mode())
}
/// Returns the number of channels selected.
/// Returns Error::OutOfRange if both mono and stereo are selected.
pub fn channel_count(&self) -> avdtp::Result<usize> {
let chan_mode = self.channel_mode();
if chan_mode == SbcChannelMode::MONO {
return Ok(1);
} else if !chan_mode.is_empty() && (chan_mode & SbcChannelMode::MONO).is_empty() {
return Ok(2);
}
Err(avdtp::Error::OutOfRange)
}
pub fn max_bitpool(&self) -> u8 {
self.0.maxbitpoolval()
}
/// Returns the sampling frequeency selected, in hz.
/// Returns Error::OutOfRange if multiple frequencies are selected.
pub fn sampling_frequency(&self) -> avdtp::Result<u32> {
let hz = match SbcSamplingFrequency::from_bits_truncate(self.0.sampling_frequency()) {
SbcSamplingFrequency::FREQ16000HZ => 16000,
SbcSamplingFrequency::FREQ32000HZ => 32000,
SbcSamplingFrequency::FREQ44100HZ => 44100,
SbcSamplingFrequency::FREQ48000HZ => 48000,
_ => return Err(avdtp::Error::OutOfRange),
};
Ok(hz)
}
/// Returns true if `other` is a compatible configuration of `self`
pub fn supports(&self, other: &Self) -> bool {
let allowed_frequencies =
SbcSamplingFrequency::from_bits_truncate(self.0.sampling_frequency());
let selected_frequencies =
SbcSamplingFrequency::from_bits_truncate(other.0.sampling_frequency());
if !(allowed_frequencies.intersects(selected_frequencies)) {
return false;
}
if !(self.allocation_method().intersects(other.allocation_method())) {
return false;
}
if !(self.channel_mode().intersects(other.channel_mode())) {
return false;
}
if !(self.block_count().intersects(other.block_count())) {
return false;
}
if !(self.sub_bands().intersects(other.sub_bands())) {
return false;
}
if self.0.minbitpoolval() > other.0.minbitpoolval() {
return false;
}
if self.0.maxbitpoolval() < other.0.maxbitpoolval() {
return false;
}
return true;
}
/// Return the best intersection of a and b's capabilities, if one exists.
pub fn negotiate(a: &Self, b: &Self) -> Option<Self> {
let min_bitpool = std::cmp::max(a.0.minbitpoolval(), b.0.minbitpoolval());
let max_bitpool = std::cmp::min(a.0.maxbitpoolval(), b.0.maxbitpoolval());
if max_bitpool < min_bitpool {
return None;
}
let available_frequencies = SbcSamplingFrequency::from_bits_truncate(
a.0.sampling_frequency() & b.0.sampling_frequency(),
);
let frequency = match available_frequencies.best() {
None => return None,
Some(freq) => freq,
};
let available_mode = a.channel_mode() & b.channel_mode();
let channel_mode = match available_mode.best() {
None => return None,
Some(mode) => mode,
};
// All sources and sinks must support these options. A2DP 1.3.2 Sec 4.3.2
let allocation = SbcAllocation::LOUDNESS;
let block_count = SbcBlockCount::SIXTEEN;
let sub_bands = SbcSubBands::EIGHT;
Some(
SbcCodecInfo::new(
frequency,
channel_mode,
block_count,
sub_bands,
allocation,
min_bitpool,
max_bitpool,
)
.expect("supported options"),
)
}
}
impl TryFrom<&[u8]> for SbcCodecInfo {
type Error = avdtp::Error;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != SBC_CODEC_EXTRA_LEN {
return Err(avdtp::Error::OutOfRange);
}
let mut codec_info_bytes = [0_u8; SBC_CODEC_EXTRA_LEN];
codec_info_bytes.copy_from_slice(&value);
Ok(Self(SbcCodecInfoBits(u32::from_be_bytes(codec_info_bytes))))
}
}
impl From<SbcCodecInfo> for avdtp::ServiceCapability {
fn from(codec_info: SbcCodecInfo) -> Self {
Self::MediaCodec {
media_type: avdtp::MediaType::Audio,
codec_type: avdtp::MediaCodecType::AUDIO_SBC,
codec_extra: codec_info.to_bytes().to_vec(),
}
}
}
bitflags! {
/// Object Type field for MPEG-2,4 AAC (Octet 0; b0-7).
/// Support for MPEG-2 AAC LC is mandatory in both A2DP Sink and Source.
/// Bits 0 to 4 are RFA.
/// A2DP Sec. 4.5.2.1
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AacObjectType:u8 {
const MPEG2_AAC_LC = 0b10000000;
const MPEG4_AAC_LC = 0b01000000;
const MPEG4_AAC_LTP = 0b00100000;
const MPEG4_AAC_SCALABLE = 0b00010000;
const MANDATORY_SNK = Self::MPEG2_AAC_LC.bits();
const MANDATORY_SRC = Self::MPEG2_AAC_LC.bits();
}
}
bitflags! {
/// Sampling Frequency field for MPEG-2,4 AAC (Octet 1; b0-7, Octet 2; b4-7)
/// Support for 44.1KHz & 48.0KHz is mandatory in A2DP Sink.
/// Support for either 44.1KHz or 48.0KHz is mandatory in A2DP Source.
/// A2DP Sec. 4.5.2.2
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AacSamplingFrequency:u16 {
const FREQ8000HZ = 0b100000000000;
const FREQ11025HZ = 0b010000000000;
const FREQ12000HZ = 0b001000000000;
const FREQ16000HZ = 0b000100000000;
const FREQ22050HZ = 0b000010000000;
const FREQ24000HZ = 0b000001000000;
const FREQ32000HZ = 0b000000100000;
const FREQ44100HZ = 0b000000010000;
const FREQ48000HZ = 0b000000001000;
const FREQ64000HZ = 0b000000000100;
const FREQ88200HZ = 0b000000000010;
const FREQ96000HZ = 0b000000000001;
const MANDATORY_SNK = Self::FREQ44100HZ.bits() | Self::FREQ48000HZ.bits();
}
}
impl AacSamplingFrequency {
fn best(&self) -> Option<Self> {
// Since one of 48000 or 44100 is mandatory, this list should find one.
let ordered = [Self::FREQ96000HZ, Self::FREQ48000HZ, Self::FREQ44100HZ];
ordered.iter().find(|freq| self.contains(**freq)).copied()
}
}
bitflags! {
/// Channels field for MPEG-2,4 AAC (Octet 2; b2-3).
/// Support for both 1 and 2 channels is mandatory in A2DP Sink.
/// Support for either 1 or 2 channels is mandatory in A2DP Source.
/// A2DP Sec 4.5.2.3
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AacChannels:u8 {
const ONE = 0b10;
const TWO = 0b01;
const MANDATORY_SNK = Self::ONE.bits() | Self::TWO.bits();
}
}
impl AacChannels {
fn best(&self) -> Option<Self> {
let ordered = [Self::TWO, Self::ONE];
ordered.iter().find(|channels| self.contains(**channels)).copied()
}
}
bitflags! {
/// Support of Variable Bit Rate (VBR) field for MPEG-2,4 AAC (Octet 3; b7).
/// Support for VBR is mandatory in A2DP Sink.
/// A2DP Sec 4.5.2.5
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct AacVariableBitRate: u8 {
const VBR_SUPPORTED = 0b1;
const MANDATORY_SNK = Self::VBR_SUPPORTED.bits();
}
}
pub const AAC_CODEC_EXTRA_LEN: usize = 6;
bitfield! {
/// MPEG-2 AAC Codec Specific Information Elements (A2DP Sec 4.5.2)
/// Structure:
/// Octet0: Object Type (b 40-47)
/// Octet1: Sampling Frequency (b 32-39)
/// Octet2: Sampling Frequency (b 28-31), Channels (b 26-27), RFA (b 24-25)
/// Octet3: VBR (b 23), Bit Rate (b 16-22)
/// Octet4: Bit Rate (b 8-15)
/// Octet5: Bit Rate (b 0-7)
/// Some fields are mandatory choose 1, and therefore do not have a mandatory parameter method.
struct AacCodecInfoBits(u64);
impl Debug;
u8;
u32, bitrate, set_bitrate: 22, 0;
vbr, set_vbr: 23, 23;
// Bits 24-25 RFA.
channels, set_channels: 27,26;
u16, sampling_frequency, set_sampling_frequency: 39, 28;
object_type, set_object_type: 47, 40;
// Bits 48-63 Unused.
}
#[derive(Debug)]
pub struct AacCodecInfo(AacCodecInfoBits);
impl AacCodecInfo {
pub fn new(
object_type: AacObjectType,
sampling_frequency: AacSamplingFrequency,
channels: AacChannels,
vbr: bool,
bitrate: u32,
) -> avdtp::Result<Self> {
// Bitrate is expressed as a 23bit UiMsbf, stored in a u32.
if bitrate > 0x7fffff {
return Err(avdtp::Error::OutOfRange);
}
let mut res = AacCodecInfoBits(0);
res.set_bitrate(bitrate);
if vbr {
res.set_vbr(AacVariableBitRate::VBR_SUPPORTED.bits());
}
res.set_channels(channels.bits());
res.set_sampling_frequency(sampling_frequency.bits());
res.set_object_type(object_type.bits());
Ok(Self(res))
}
/// `AacCodecInfoBytes` is represented as an u64, with upper 16 bits unused.
/// Return a vector of the lower 6 bytes.
pub fn to_bytes(&self) -> [u8; 6] {
let codec_info = (self.0).0.to_be_bytes();
let mut res = [0u8; 6];
res.copy_from_slice(&codec_info[2..8]);
res
}
pub fn variable_bit_rate(&self) -> bool {
self.0.vbr() == 0b1
}
pub fn bitrate(&self) -> u32 {
self.0.bitrate()
}
pub fn channels(&self) -> AacChannels {
AacChannels::from_bits_truncate(self.0.channels())
}
/// Returns the number of channels selected.
/// Returns Error::OutOfRange if both mono and stereo are selected.
pub fn channel_count(&self) -> avdtp::Result<usize> {
let count = match self.channels() {
AacChannels::ONE => 1,
AacChannels::TWO => 2,
_ => return Err(avdtp::Error::OutOfRange),
};
Ok(count)
}
fn object_type(&self) -> AacObjectType {
AacObjectType::from_bits_truncate(self.0.object_type())
}
/// Returns the sampling frequeency selected, in hz.
/// Returns Error::OutOfRange if multiple frequencies are selected.
pub fn sampling_frequency(&self) -> avdtp::Result<u32> {
let hz = match AacSamplingFrequency::from_bits_truncate(self.0.sampling_frequency()) {
AacSamplingFrequency::FREQ8000HZ => 8000,
AacSamplingFrequency::FREQ11025HZ => 11025,
AacSamplingFrequency::FREQ12000HZ => 12000,
AacSamplingFrequency::FREQ16000HZ => 16000,
AacSamplingFrequency::FREQ22050HZ => 22050,
AacSamplingFrequency::FREQ24000HZ => 24000,
AacSamplingFrequency::FREQ32000HZ => 32000,
AacSamplingFrequency::FREQ44100HZ => 44100,
AacSamplingFrequency::FREQ48000HZ => 48000,
AacSamplingFrequency::FREQ64000HZ => 64000,
AacSamplingFrequency::FREQ88200HZ => 88200,
AacSamplingFrequency::FREQ96000HZ => 96000,
_ => return Err(avdtp::Error::OutOfRange),
};
Ok(hz)
}
/// Returns true if `other` is a compatable configuration of `self`
pub fn supports(&self, other: &Self) -> bool {
let allowed_frequencies =
AacSamplingFrequency::from_bits_truncate(self.0.sampling_frequency());
let selected_frequencies =
AacSamplingFrequency::from_bits_truncate(other.0.sampling_frequency());
if !(allowed_frequencies.intersects(selected_frequencies)) {
return false;
}
if !(self.channels().intersects(other.channels())) {
return false;
}
if !(self.object_type().intersects(other.object_type())) {
return false;
}
if !self.variable_bit_rate() && other.variable_bit_rate() {
return false;
}
// Note: the "capabilities" bitrate field is unclear in the A2DP spec: 4.5.2.4.
// Interpreting this as the max bitrate for either constant or vbr.
// Zero is "not known", which we interpret to be "any bitrate is okay", but only
// if we are interpreting our bitrate support
if self.bitrate() != 0 && (self.bitrate() < other.bitrate()) {
return false;
}
return true;
}
pub fn negotiate(a: &Self, b: &Self) -> Option<Self> {
let available_frequencies = AacSamplingFrequency::from_bits_truncate(
a.0.sampling_frequency() & b.0.sampling_frequency(),
);
let sampling_frequency = match available_frequencies.best() {
None => return None,
Some(freq) => freq,
};
let available_channels = a.channels() & b.channels();
let channels = match available_channels.best() {
None => return None,
Some(channels) => channels,
};
let vbr = a.variable_bit_rate() && b.variable_bit_rate();
// If either bitrate is unspecified, take the other one, otherwise, the minimum.
let bitrate = match (a.bitrate(), b.bitrate()) {
(0, b) => b,
(a, 0) => a,
(a, b) => std::cmp::min(a, b),
};
// This option is mandatory for source and sink and we prefer it. See A2DP 1.3.2 Sec 4.5.2
let object_type = AacObjectType::MPEG2_AAC_LC;
Some(AacCodecInfo::new(object_type, sampling_frequency, channels, vbr, bitrate).unwrap())
}
}
impl TryFrom<&[u8]> for AacCodecInfo {
type Error = avdtp::Error;
/// Create `AacCodecInfo` from slice of length `AAC_CODEC_EXTRA_LEN`
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != AAC_CODEC_EXTRA_LEN {
return Err(avdtp::Error::OutOfRange);
}
let mut codec_info_bytes = [0_u8; 8];
let codec_info_slice = &mut codec_info_bytes[2..8];
// AacCodecInfo is represented as 8 bytes, with lower 6 bytes containing
// the codec extra data.
codec_info_slice.copy_from_slice(&value);
Ok(Self(AacCodecInfoBits(u64::from_be_bytes(codec_info_bytes))))
}
}
impl From<AacCodecInfo> for avdtp::ServiceCapability {
fn from(codec_info: AacCodecInfo) -> Self {
Self::MediaCodec {
media_type: avdtp::MediaType::Audio,
codec_type: avdtp::MediaCodecType::AUDIO_AAC,
codec_extra: codec_info.to_bytes().to_vec(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
/// Unit test for the SBC media codec info generation.
fn test_sbc_codec_info() {
// Mandatory A2DP Sink support case.
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::MANDATORY_SNK,
SbcChannelMode::MANDATORY_SNK,
SbcBlockCount::MANDATORY_SNK,
SbcSubBands::MANDATORY_SNK,
SbcAllocation::MANDATORY_SNK,
2,
250,
)
.expect("Couldn't create sbc media codec info.");
let res = sbc_codec_info.to_bytes();
let codec_extra: Vec<u8> = vec![0x3F, 0xFF, 2, 250];
assert_eq!(codec_extra, res);
// reverse parsing and check we match
let res = SbcCodecInfo::try_from(&codec_extra[..]).expect("created codec info");
assert_eq!((res.0).0, (sbc_codec_info.0).0);
// Mandatory A2DP source support case. Some fields are choose 1 fields.
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::FREQ44100HZ,
SbcChannelMode::MONO | SbcChannelMode::DUAL_CHANNEL,
SbcBlockCount::MANDATORY_SRC,
SbcSubBands::MANDATORY_SRC,
SbcAllocation::MANDATORY_SRC,
2,
250,
)
.expect("Couldn't create sbc media codec info.");
let res = sbc_codec_info.to_bytes();
assert_eq!(vec![0x2C, 0xF5, 2, 250], res);
// No supported codec information
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::empty(),
SbcChannelMode::empty(),
SbcBlockCount::empty(),
SbcSubBands::empty(),
SbcAllocation::empty(),
2,
250,
)
.expect("Couldn't create sbc media codec info.");
assert_matches!(sbc_codec_info.channel_count(), Err(avdtp::Error::OutOfRange));
let res = sbc_codec_info.to_bytes();
assert_eq!(vec![0x00, 0x00, 2, 250], res);
// All codec field values are supported
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert_matches!(sbc_codec_info.channel_count(), Err(avdtp::Error::OutOfRange));
let res = sbc_codec_info.to_bytes();
assert_eq!(vec![0xFF, 0xFF, 2, 250], res);
// Out of range bitpool value
let sbc_codec_info = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
20,
252, // Too large.
);
assert!(sbc_codec_info.is_err());
// Out of range bitpool value
let sbc_codec_info = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
0, // Too small
240,
);
assert!(sbc_codec_info.is_err());
// Invalid bitpool value
let sbc_codec_info = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
100,
50,
);
assert!(sbc_codec_info.is_err());
let empty = vec![0, 0, 0, 0];
let res = SbcCodecInfo::try_from(&empty[..]).expect("created codec info");
assert_eq!((res.0).0, 0);
let too_big = vec![0, 0, 0, 0, 0];
assert_matches!(SbcCodecInfo::try_from(&too_big[..]), Err(avdtp::Error::OutOfRange));
// Mono and Stereo
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::FREQ44100HZ,
SbcChannelMode::MONO,
SbcBlockCount::MANDATORY_SRC,
SbcSubBands::MANDATORY_SRC,
SbcAllocation::MANDATORY_SRC,
2,
250,
)
.expect("Couldn't create sbc media codec info.");
assert_matches!(sbc_codec_info.channel_count(), Ok(1));
let sbc_codec_info: SbcCodecInfo = SbcCodecInfo::new(
SbcSamplingFrequency::FREQ44100HZ,
SbcChannelMode::JOINT_STEREO,
SbcBlockCount::MANDATORY_SRC,
SbcSubBands::MANDATORY_SRC,
SbcAllocation::MANDATORY_SRC,
2,
250,
)
.expect("Couldn't create sbc media codec info.");
assert_matches!(sbc_codec_info.channel_count(), Ok(2));
}
#[test]
fn test_sbc_codec_supports() {
let sbc_codec_all = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
// Should support itself.
assert!(sbc_codec_all.supports(&sbc_codec_all));
let sbc_codec_441 = SbcCodecInfo::new(
SbcSamplingFrequency::FREQ44100HZ,
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
53, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
let sbc_codec_48 = SbcCodecInfo::new(
SbcSamplingFrequency::FREQ48000HZ,
SbcChannelMode::all(),
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
53, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert!(sbc_codec_all.supports(&sbc_codec_441));
assert!(sbc_codec_all.supports(&sbc_codec_48));
// Frequency mismatches
assert!(!sbc_codec_48.supports(&sbc_codec_441));
assert!(!sbc_codec_441.supports(&sbc_codec_48));
// Min / Max bitpools
assert!(!sbc_codec_48.supports(&sbc_codec_all));
assert!(!sbc_codec_441.supports(&sbc_codec_all));
let sbc_codec_mono = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::MONO,
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
let sbc_codec_stereo = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::JOINT_STEREO,
SbcBlockCount::all(),
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert!(sbc_codec_all.supports(&sbc_codec_mono));
assert!(sbc_codec_all.supports(&sbc_codec_stereo));
assert!(!sbc_codec_mono.supports(&sbc_codec_stereo));
assert!(!sbc_codec_stereo.supports(&sbc_codec_mono));
let sbc_codec_blocks_4 = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::FOUR,
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
let sbc_codec_blocks_8 = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::EIGHT,
SbcSubBands::all(),
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert!(sbc_codec_all.supports(&sbc_codec_blocks_4));
assert!(sbc_codec_all.supports(&sbc_codec_blocks_8));
assert!(!sbc_codec_blocks_4.supports(&sbc_codec_blocks_8));
assert!(!sbc_codec_blocks_8.supports(&sbc_codec_blocks_4));
let sbc_codec_bands_4 = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::FOUR,
SbcSubBands::FOUR,
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
let sbc_codec_bands_8 = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::FOUR,
SbcSubBands::EIGHT,
SbcAllocation::all(),
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert!(sbc_codec_all.supports(&sbc_codec_bands_4));
assert!(sbc_codec_all.supports(&sbc_codec_bands_8));
assert!(!sbc_codec_bands_4.supports(&sbc_codec_bands_8));
assert!(!sbc_codec_bands_8.supports(&sbc_codec_bands_4));
let sbc_codec_snr = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::FOUR,
SbcSubBands::FOUR,
SbcAllocation::SNR,
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
let sbc_codec_loudness = SbcCodecInfo::new(
SbcSamplingFrequency::all(),
SbcChannelMode::all(),
SbcBlockCount::FOUR,
SbcSubBands::FOUR,
SbcAllocation::LOUDNESS,
SbcCodecInfo::BITPOOL_MIN, // Smallest bitpool value.
SbcCodecInfo::BITPOOL_MAX, // Largest bitpool value.
)
.expect("Couldn't create sbc media codec info.");
assert!(sbc_codec_all.supports(&sbc_codec_snr));
assert!(sbc_codec_all.supports(&sbc_codec_loudness));
assert!(!sbc_codec_snr.supports(&sbc_codec_loudness));
assert!(!sbc_codec_loudness.supports(&sbc_codec_snr));
}
#[test]
fn test_aac_codec_info() {
// Empty case.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::empty(),
AacSamplingFrequency::empty(),
AacChannels::empty(),
false,
0,
)
.expect("Error creating aac media codec info.");
let res = aac_codec_info.to_bytes();
assert_eq!(vec![0, 0, 0, 0, 0, 0], res);
// All codec info supported case.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::all(),
AacChannels::all(),
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert_matches!(aac_codec_info.channel_count(), Err(avdtp::Error::OutOfRange));
let res = aac_codec_info.to_bytes();
assert_eq!(vec![0xF0, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF], res);
// Only VBR specified.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::empty(),
AacSamplingFrequency::empty(),
AacChannels::empty(),
true,
0,
)
.expect("Error creating aac media codec info.");
assert_matches!(aac_codec_info.channel_count(), Err(avdtp::Error::OutOfRange));
let res = aac_codec_info.to_bytes();
assert_eq!(vec![0x00, 0x00, 0x00, 0x80, 0x00, 0x00], res);
// A2DP Sink mandatory fields supported.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::MANDATORY_SNK,
AacSamplingFrequency::MANDATORY_SNK,
AacChannels::MANDATORY_SNK,
true,
0xAAFF, // Arbitrary bit rate.
)
.expect("Error creating aac media codec info.");
let res = aac_codec_info.to_bytes();
let codec_extra: Vec<u8> = vec![0x80, 0x01, 0x8C, 0x80, 0xAA, 0xFF];
assert_eq!(codec_extra, res);
// reverse parsing and check we match
let res = AacCodecInfo::try_from(&codec_extra[..]).expect("created codec info");
assert_eq!((res.0).0, (aac_codec_info.0).0);
// A2DP Source mandatory fields supported.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::MANDATORY_SRC,
AacSamplingFrequency::FREQ44100HZ,
AacChannels::ONE,
false, // VBR is optional in SRC.
0xAAFF, // Arbitrary
)
.expect("Error creating aac media codec info.");
assert_matches!(aac_codec_info.channel_count(), Ok(1));
let res = aac_codec_info.to_bytes();
assert_eq!(vec![0x80, 0x01, 0x08, 0x00, 0xAA, 0xFF], res);
// A2DP Source with two channels
let aac_codec_info = AacCodecInfo::new(
AacObjectType::MANDATORY_SRC,
AacSamplingFrequency::FREQ44100HZ,
AacChannels::TWO,
false, // VBR is optional in SRC.
0xAAFF, // Arbitrary
)
.expect("Error creating aac media codec info.");
assert_matches!(aac_codec_info.channel_count(), Ok(2));
// Out of range bit rate.
let aac_codec_info = AacCodecInfo::new(
AacObjectType::MANDATORY_SRC,
AacSamplingFrequency::FREQ44100HZ,
AacChannels::ONE,
false,
0xFFFFFF, // Too large
);
assert!(aac_codec_info.is_err());
let empty = vec![0, 0, 0, 0, 0, 0];
let res = AacCodecInfo::try_from(&empty[..]).expect("created codec info");
assert_eq!((res.0).0, 0);
let too_big = vec![0, 0, 0, 0, 0, 0, 0];
assert_matches!(AacCodecInfo::try_from(&too_big[..]), Err(avdtp::Error::OutOfRange));
}
#[test]
fn test_aac_codec_supports() {
// All codec info supported case.
let aac_codec_all = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::all(),
AacChannels::all(),
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert!(aac_codec_all.supports(&aac_codec_all));
let aac_codec_441 = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::FREQ44100HZ,
AacChannels::all(),
true,
50, // Lower than largest.
)
.expect("Error creating aac media codec info.");
let aac_codec_48 = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::FREQ48000HZ,
AacChannels::all(),
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert!(aac_codec_all.supports(&aac_codec_441));
assert!(aac_codec_all.supports(&aac_codec_48));
// Frequencies
assert!(!aac_codec_441.supports(&aac_codec_48));
assert!(!aac_codec_48.supports(&aac_codec_441));
// Max bitrate.
assert!(!aac_codec_441.supports(&aac_codec_all));
// Channels
let aac_codec_chan_one = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::all(),
AacChannels::ONE,
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
let aac_codec_chan_two = AacCodecInfo::new(
AacObjectType::all(),
AacSamplingFrequency::all(),
AacChannels::TWO,
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert!(aac_codec_all.supports(&aac_codec_chan_one));
assert!(aac_codec_all.supports(&aac_codec_chan_two));
assert!(!aac_codec_chan_one.supports(&aac_codec_chan_two));
assert!(!aac_codec_chan_two.supports(&aac_codec_chan_one));
// object type
let aac_codec_mpeg2 = AacCodecInfo::new(
AacObjectType::MPEG2_AAC_LC,
AacSamplingFrequency::all(),
AacChannels::ONE,
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
let aac_codec_mpeg4 = AacCodecInfo::new(
AacObjectType::MPEG4_AAC_LC,
AacSamplingFrequency::all(),
AacChannels::ONE,
true,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert!(aac_codec_all.supports(&aac_codec_mpeg2));
assert!(aac_codec_all.supports(&aac_codec_mpeg4));
assert!(!aac_codec_mpeg2.supports(&aac_codec_mpeg4));
assert!(!aac_codec_mpeg4.supports(&aac_codec_mpeg2));
let aac_codec_not_vbr = AacCodecInfo::new(
AacObjectType::MPEG4_AAC_LC,
AacSamplingFrequency::all(),
AacChannels::ONE,
false,
8388607, // Largest 23-bit bit rate.
)
.expect("Error creating aac media codec info.");
assert!(!aac_codec_not_vbr.supports(&aac_codec_mpeg4));
let aac_codec_bitrate_not_known = AacCodecInfo::new(
AacObjectType::MPEG4_AAC_LC,
AacSamplingFrequency::all(),
AacChannels::ONE,
true,
0, // Bitrate "Not known"
)
.expect("Error creating aac media codec info.");
assert!(aac_codec_bitrate_not_known.supports(&aac_codec_not_vbr));
}
}