use heapless::Vec;
use heapless::index_map::FnvIndexMap;
use super::codes::*;
use crate::descriptor::descriptor_type::{CS_ENDPOINT, CS_INTERFACE, INTERFACE_ASSOCIATION};
use crate::descriptor::{
ConfigurationDescriptor, DescriptorVisitor, EndpointDescriptor, InterfaceDescriptor as GenericInterfaceDescriptor,
StringIndex, USBDescriptor, VisitError,
};
const MAX_AUDIO_STREAMING_INTERFACES: usize = 16;
const MAX_ALTERNATE_SETTINGS: usize = 4;
const MAX_CLOCK_DESCRIPTORS: usize = 8;
const MAX_UNIT_DESCRIPTORS: usize = 16;
const MAX_TERMINAL_DESCRIPTORS: usize = 16;
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AudioInterfaceCollection {
pub interface_association_descriptor: InterfaceAssociationDescriptor,
pub control_interface: AudioControlInterface,
pub audio_streaming_interfaces: Vec<AudioStreamingInterface, MAX_AUDIO_STREAMING_INTERFACES>,
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AudioInterfaceError {
BufferFull(&'static str),
MissingControlInterface,
MissingControlInterfaceHeader,
InvalidDescriptor,
NoAudioConfiguration,
MissingAudioStreamingClassDescriptor,
}
struct AudioCollectionBuilder {
iad: Option<InterfaceAssociationDescriptor>,
interfaces: Vec<InterfaceDescriptor, MAX_ALTERNATE_SETTINGS>,
control: Option<AudioControlInterface>,
streaming: Vec<AudioStreamingInterface, MAX_AUDIO_STREAMING_INTERFACES>,
error: Option<AudioInterfaceError>,
}
impl AudioCollectionBuilder {
fn new() -> Self {
Self {
iad: None,
interfaces: Vec::new(),
control: None,
streaming: Vec::new(),
error: None,
}
}
fn build(self) -> Result<AudioInterfaceCollection, AudioInterfaceError> {
if let Some(e) = self.error {
return Err(e);
}
Ok(AudioInterfaceCollection {
interface_association_descriptor: self.iad.ok_or(AudioInterfaceError::NoAudioConfiguration)?,
control_interface: self.control.ok_or(AudioInterfaceError::MissingControlInterface)?,
audio_streaming_interfaces: self.streaming,
})
}
}
impl<'a> DescriptorVisitor<'a> for AudioCollectionBuilder {
type Error = AudioInterfaceError;
fn on_interface(&mut self, iface: &GenericInterfaceDescriptor<'a>) -> bool {
let Some(ref iad) = self.iad else {
return true;
};
if iface.interface_number >= iad.first_interface + iad.num_interfaces {
return false; }
if iface.interface_class != interface::AUDIO {
return true; }
if iface.interface_protocol != function_protocol::AF_VERSION_02_00 {
debug!(
"Skipping interface with unsupported protocol: {:#04x}",
iface.interface_protocol
);
return true;
}
match iface.interface_subclass {
interface::subclass::AUDIOCONTROL => {
if self.control.is_some() {
warn!("Audio Control Interface already parsed, skipping");
return true;
}
if !self.interfaces.is_empty() {
self.error = Some(AudioInterfaceError::MissingAudioStreamingClassDescriptor);
return false;
}
trace!("Processing Audio Control Interface");
self.interfaces = Vec::from_slice(&[InterfaceDescriptor::from(iface)]).unwrap();
}
interface::subclass::AUDIOSTREAMING => {
let is_alternate = self
.interfaces
.first()
.is_some_and(|i| i.interface_number == iface.interface_number);
if is_alternate {
if self.interfaces.push(InterfaceDescriptor::from(iface)).is_err() {
self.error = Some(AudioInterfaceError::BufferFull("Too many interfaces"));
return false;
}
return true;
}
if !self.interfaces.is_empty() {
self.error = Some(match self.interfaces[0].interface_subclass {
interface::subclass::AUDIOCONTROL => AudioInterfaceError::MissingControlInterfaceHeader,
_ => AudioInterfaceError::MissingAudioStreamingClassDescriptor,
});
return false;
}
trace!("Processing Audio Streaming Interface");
self.interfaces = Vec::from_slice(&[InterfaceDescriptor::from(iface)]).unwrap();
}
_ => {
trace!("Skipping unknown audio subclass: {:#04x}", iface.interface_subclass);
}
}
true
}
fn on_endpoint(&mut self, iface: &GenericInterfaceDescriptor<'a>, ep: &EndpointDescriptor) -> bool {
match iface.interface_subclass {
interface::subclass::AUDIOSTREAMING => {
if let Some(si) = self.streaming.last_mut() {
if ep.attributes == 0b010001 {
si.feedback_endpoint_descriptor = Some(*ep);
} else {
si.endpoint_descriptor = Some(*ep);
}
}
}
interface::subclass::AUDIOCONTROL => {
if let Some(ac) = &mut self.control {
ac.interrupt_endpoint_descriptor = Some(*ep);
}
}
_ => {}
}
true
}
fn on_other(&mut self, _iface: Option<&GenericInterfaceDescriptor<'a>>, raw: &[u8]) -> Result<bool, Self::Error> {
if raw.len() < 2 {
return Ok(true);
}
match raw[1] {
INTERFACE_ASSOCIATION => {
if self.iad.is_none() {
if let Ok(iad) = InterfaceAssociationDescriptor::try_from_bytes(raw) {
if iad.is_audio_association() {
self.iad = Some(iad);
}
}
}
}
CS_INTERFACE => {
if !self.interfaces.is_empty() {
match self.interfaces[0].interface_subclass {
interface::subclass::AUDIOCONTROL => {
if let Ok(header) = AudioControlHeaderDescriptor::try_from_bytes(raw) {
let interfaces = core::mem::take(&mut self.interfaces);
debug!(
"Found Audio Control Header: version={}.{}",
header.audio_device_class.0, header.audio_device_class.1
);
self.control = Some(AudioControlInterface::new(interfaces, header));
return Ok(true);
}
}
interface::subclass::AUDIOSTREAMING => {
if let Ok(class_desc) = AudioStreamingClassDescriptor::try_from_bytes(raw) {
let interfaces = core::mem::take(&mut self.interfaces);
trace!("Found Audio Streaming Class Descriptor: {:?}", class_desc.format);
self.streaming
.push(AudioStreamingInterface::new(interfaces, class_desc))
.map_err(|_| {
AudioInterfaceError::BufferFull("Too many audio streaming interfaces")
})?;
return Ok(true);
}
}
_ => {}
}
}
if let Some(si) = self.streaming.last_mut() {
if let Ok(format_type) = FormatTypeDescriptor::try_from_bytes(raw) {
si.format_type_descriptor = Some(format_type);
}
} else if let Some(ac) = &mut self.control {
ac.add_cs_interface(raw)?;
}
}
CS_ENDPOINT => {
if let Some(si) = self.streaming.last_mut() {
if let Ok(audio_ep) = AudioEndpointDescriptor::try_from_bytes(raw) {
si.audio_endpoint_descriptor = Some(audio_ep);
}
}
}
_ => {}
}
Ok(true)
}
}
impl AudioInterfaceCollection {
pub fn try_from_configuration(cfg: &ConfigurationDescriptor) -> Result<Self, AudioInterfaceError> {
let mut builder = AudioCollectionBuilder::new();
cfg.visit_descriptors(&mut builder).map_err(|e| match e {
VisitError::BadDescriptor => AudioInterfaceError::InvalidDescriptor,
VisitError::Visitor(e) => e,
})?;
builder.build()
}
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterfaceAssociationDescriptor {
pub first_interface: u8,
pub num_interfaces: u8,
pub class: u8,
pub subclass: u8,
pub protocol: u8,
pub interface_name: StringIndex,
}
impl USBDescriptor for InterfaceAssociationDescriptor {
const SIZE: usize = 8;
const DESC_TYPE: u8 = INTERFACE_ASSOCIATION;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
Ok(Self {
first_interface: bytes[2],
num_interfaces: bytes[3],
class: bytes[4],
subclass: bytes[5],
protocol: bytes[6],
interface_name: bytes[7],
})
}
}
impl InterfaceAssociationDescriptor {
pub fn is_audio_association(&self) -> bool {
self.class == AUDIO_FUNCTION && self.protocol == function_protocol::AF_VERSION_02_00
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InterfaceDescriptor {
pub len: u8,
pub descriptor_type: u8,
pub interface_number: u8,
pub alternate_setting: u8,
pub num_endpoints: u8,
pub interface_class: u8,
pub interface_subclass: u8,
pub interface_protocol: u8,
pub interface_name: StringIndex,
}
impl From<&GenericInterfaceDescriptor<'_>> for InterfaceDescriptor {
fn from(g: &GenericInterfaceDescriptor<'_>) -> Self {
Self {
len: g.len,
descriptor_type: g.descriptor_type,
interface_number: g.interface_number,
alternate_setting: g.alternate_setting,
num_endpoints: g.num_endpoints,
interface_class: g.interface_class,
interface_subclass: g.interface_subclass,
interface_protocol: g.interface_protocol,
interface_name: g.interface_name,
}
}
}
#[derive(Debug, PartialEq)]
pub struct AudioControlInterface {
pub interface_descriptors: Vec<InterfaceDescriptor, MAX_ALTERNATE_SETTINGS>,
pub header_descriptor: AudioControlHeaderDescriptor,
pub interrupt_endpoint_descriptor: Option<EndpointDescriptor>,
pub clock_descriptors: FnvIndexMap<u8, ClockDescriptor, MAX_CLOCK_DESCRIPTORS>,
pub unit_descriptors: FnvIndexMap<u8, UnitDescriptor, MAX_UNIT_DESCRIPTORS>,
pub terminal_descriptors: FnvIndexMap<u8, TerminalDescriptor, MAX_TERMINAL_DESCRIPTORS>,
}
#[cfg(feature = "defmt")]
impl defmt::Format for AudioControlInterface {
fn format(&self, fmt: defmt::Formatter<'_>) {
defmt::write!(
fmt,
"AudioControlInterface {{ interface_descriptors: {=?}, header_descriptor: {=?}, interrupt_endpoint_descriptor: {=?}, clock_descriptors_len: {=usize}, unit_descriptors_len: {=usize}, terminal_descriptors_len: {=usize} }}",
self.interface_descriptors,
self.header_descriptor,
self.interrupt_endpoint_descriptor,
self.clock_descriptors.len(),
self.unit_descriptors.len(),
self.terminal_descriptors.len(),
);
}
}
impl AudioControlInterface {
fn new(interfaces: Vec<InterfaceDescriptor, MAX_ALTERNATE_SETTINGS>, header: AudioControlHeaderDescriptor) -> Self {
Self {
interface_descriptors: interfaces,
header_descriptor: header,
interrupt_endpoint_descriptor: None,
clock_descriptors: FnvIndexMap::new(),
unit_descriptors: FnvIndexMap::new(),
terminal_descriptors: FnvIndexMap::new(),
}
}
fn add_cs_interface(&mut self, raw: &[u8]) -> Result<(), AudioInterfaceError> {
match ClockDescriptor::try_from_bytes(raw) {
Ok(clock) => {
self.clock_descriptors
.insert(clock.clock_id(), clock)
.map_err(|_| AudioInterfaceError::BufferFull("Too many clock descriptors"))?;
}
Err(AudioInterfaceError::InvalidDescriptor) => {}
Err(e) => return Err(e),
}
if let Ok(terminal) = TerminalDescriptor::try_from_bytes(raw) {
self.terminal_descriptors
.insert(terminal.terminal_id(), terminal)
.map_err(|_| AudioInterfaceError::BufferFull("Too many terminal descriptors"))?;
}
if let Ok(unit) = UnitDescriptor::try_from_bytes(raw) {
self.unit_descriptors
.insert(unit.unit_id(), unit)
.map_err(|_| AudioInterfaceError::BufferFull("Too many unit descriptors"))?;
}
Ok(())
}
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AudioControlHeaderDescriptor {
pub audio_device_class: (u8, u8),
pub category: u8,
pub controls_bitmap: u8,
}
impl USBDescriptor for AudioControlHeaderDescriptor {
const SIZE: usize = 9;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
if bytes[2] != ac_descriptor::HEADER {
return Err(());
}
Ok(Self {
audio_device_class: (bytes[4], bytes[3]),
category: bytes[5],
controls_bitmap: bytes[8],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ClockDescriptor {
Source(ClockSourceDescriptor),
Selector(ClockSelectorDescriptor),
Multiplier(ClockMultiplierDescriptor),
}
impl ClockDescriptor {
fn try_from_bytes(bytes: &[u8]) -> Result<Self, AudioInterfaceError> {
if bytes.len() < 4 {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[1] != CS_INTERFACE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
match bytes[2] {
ac_descriptor::CLOCK_SOURCE => Ok(Self::Source(ClockSourceDescriptor::try_from_bytes(bytes)?)),
ac_descriptor::CLOCK_SELECTOR => Ok(Self::Selector(ClockSelectorDescriptor::try_from_bytes(bytes)?)),
ac_descriptor::CLOCK_MULTIPLIER => Ok(Self::Multiplier(ClockMultiplierDescriptor::try_from_bytes(bytes)?)),
_ => Err(AudioInterfaceError::InvalidDescriptor),
}
}
pub fn clock_id(&self) -> u8 {
match self {
Self::Source(desc) => desc.clock_id,
Self::Selector(desc) => desc.clock_id,
Self::Multiplier(desc) => desc.clock_id,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClockSourceDescriptor {
pub clock_id: u8,
pub attributes_bitmap: u8,
pub controls_bitmap: u8,
pub associated_terminal: u8,
pub clock_name: StringIndex,
}
impl USBDescriptor for ClockSourceDescriptor {
const SIZE: usize = 8;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = AudioInterfaceError;
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[1] != Self::DESC_TYPE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[2] != ac_descriptor::CLOCK_SOURCE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
Ok(Self {
clock_id: bytes[3],
attributes_bitmap: bytes[4],
controls_bitmap: bytes[5],
associated_terminal: bytes[6],
clock_name: bytes[7],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClockSelectorDescriptor {
pub clock_id: u8,
pub source_ids: Vec<u8, MAX_CLOCK_DESCRIPTORS>,
pub controls_bitmap: u8,
pub clock_name: StringIndex,
}
impl ClockSelectorDescriptor {
fn try_from_bytes(bytes: &[u8]) -> Result<Self, AudioInterfaceError> {
if bytes.len() < 7 {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[1] != CS_INTERFACE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[2] != ac_descriptor::CLOCK_SELECTOR {
return Err(AudioInterfaceError::InvalidDescriptor);
}
let mut source_ids = Vec::new();
let num_source_ids = bytes[4] as usize;
for i in 0..num_source_ids {
source_ids
.push(bytes[5 + i])
.map_err(|_| AudioInterfaceError::BufferFull("Too many clock source ids"))?;
}
Ok(Self {
clock_id: bytes[3],
source_ids,
controls_bitmap: bytes[5 + num_source_ids as usize],
clock_name: bytes[6 + num_source_ids as usize],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClockMultiplierDescriptor {
pub clock_id: u8,
pub source_id: u8,
pub controls_bitmap: u8,
pub clock_name: StringIndex,
}
impl USBDescriptor for ClockMultiplierDescriptor {
const SIZE: usize = 7;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = AudioInterfaceError;
fn try_from_bytes(bytes: &[u8]) -> Result<Self, AudioInterfaceError> {
if bytes.len() < Self::SIZE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[1] != Self::DESC_TYPE {
return Err(AudioInterfaceError::InvalidDescriptor);
}
if bytes[2] != ac_descriptor::CLOCK_MULTIPLIER {
return Err(AudioInterfaceError::InvalidDescriptor);
}
Ok(Self {
clock_id: bytes[3],
source_id: bytes[4],
controls_bitmap: bytes[5],
clock_name: bytes[6],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TerminalDescriptor {
Input(InputTerminalDescriptor),
Output(OutputTerminalDescriptor),
}
impl TerminalDescriptor {
fn try_from_bytes(bytes: &[u8]) -> Result<Self, ()> {
if bytes.len() < 3 {
return Err(());
}
if bytes[1] != CS_INTERFACE {
return Err(());
}
match bytes[2] {
ac_descriptor::INPUT_TERMINAL => Ok(Self::Input(InputTerminalDescriptor::try_from_bytes(bytes)?)),
ac_descriptor::OUTPUT_TERMINAL => Ok(Self::Output(OutputTerminalDescriptor::try_from_bytes(bytes)?)),
_ => Err(()),
}
}
pub fn terminal_id(&self) -> u8 {
match self {
Self::Input(desc) => desc.terminal_id,
Self::Output(desc) => desc.terminal_id,
}
}
pub fn terminal_type(&self) -> TerminalType {
match self {
Self::Input(desc) => desc.terminal_type,
Self::Output(desc) => desc.terminal_type,
}
}
pub fn clock_source_id(&self) -> u8 {
match self {
Self::Input(desc) => desc.clock_source_id,
Self::Output(desc) => desc.clock_source_id,
}
}
pub fn terminal_name(&self) -> StringIndex {
match self {
Self::Input(desc) => desc.terminal_name,
Self::Output(desc) => desc.terminal_name,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TerminalType {
Unknown(u16),
UsbUndefined,
UsbStreaming,
UsbVendorSpecific,
InputUndefined,
Microphone,
DesktopMicrophone,
PersonalMicrophone,
OmniMicrophone,
MicrophoneArray,
ProcessingMicrophoneArray,
OutputUndefined,
Speaker,
Headphones,
HeadMountedDisplay,
DesktopSpeaker,
RoomSpeaker,
CommunicationSpeaker,
LowFrequencyEffectsSpeaker,
BiDirectionalUndefined,
Handset,
Headset,
SpeakerPhone,
EchoSuppressing,
EchoCanceling,
TelephonyUndefined,
PhoneLine,
Telephone,
DownLinePhone,
ExternalUndefined,
AnalogConnector,
DigitalAudioInterface,
LineConnector,
LegacyAudioConnector,
SpdifInterface,
Da1394Stream,
DvdAudioStream,
AvcStream,
}
fn terminal_type_from_u16(terminal_type: u16) -> TerminalType {
use TerminalType::*;
use crate::class::uac::codes::terminal_type::*;
match terminal_type {
usb::UNDEFINED => UsbUndefined,
usb::STREAMING => UsbStreaming,
usb::VENDOR_SPECIFIC => UsbVendorSpecific,
input::UNDEFINED => InputUndefined,
input::MICROPHONE => Microphone,
input::DESKTOP_MICROPHONE => DesktopMicrophone,
input::PERSONAL_MICROPHONE => PersonalMicrophone,
input::OMNI_DIRECTIONAL_MICROPHONE => OmniMicrophone,
input::MICROPHONE_ARRAY => MicrophoneArray,
input::PROCESSING_MICROPHONE_ARRAY => ProcessingMicrophoneArray,
output::UNDEFINED => OutputUndefined,
output::SPEAKER => Speaker,
output::HEADPHONES => Headphones,
output::HEAD_MOUNTED_DISPLAY_AUDIO => HeadMountedDisplay,
output::DESKTOP_SPEAKER => DesktopSpeaker,
output::ROOM_SPEAKER => RoomSpeaker,
output::COMMUNICATION_SPEAKER => CommunicationSpeaker,
output::LOW_FREQUENCY_EFFECTS_SPEAKER => LowFrequencyEffectsSpeaker,
bidirectional::UNDEFINED => BiDirectionalUndefined,
bidirectional::HANDSET => Handset,
bidirectional::HEADSET => Headset,
bidirectional::SPEAKERPHONE_NO_ECHO => SpeakerPhone,
bidirectional::ECHO_SUPPRESSING_SPEAKERPHONE => EchoSuppressing,
bidirectional::ECHO_CANCELING_SPEAKERPHONE => EchoCanceling,
telephony::UNDEFINED => TelephonyUndefined,
telephony::PHONE_LINE => PhoneLine,
telephony::TELEPHONE => Telephone,
telephony::DOWN_LINE_PHONE => DownLinePhone,
external::UNDEFINED => ExternalUndefined,
external::ANALOG_CONNECTOR => AnalogConnector,
external::DIGITAL_AUDIO_INTERFACE => DigitalAudioInterface,
external::LINE_CONNECTOR => LineConnector,
external::LEGACY_AUDIO_CONNECTOR => LegacyAudioConnector,
external::SPDIF_INTERFACE => SpdifInterface,
external::DA_STREAM_1394 => Da1394Stream,
external::DV_STREAM_SOUNDTRACK_1394 => DvdAudioStream,
external::ADAT_LIGHTPIPE => AvcStream,
_ => Unknown(terminal_type),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InputTerminalDescriptor {
pub terminal_id: u8,
pub terminal_type: TerminalType,
pub associated_terminal_id: u8,
pub clock_source_id: u8,
pub num_channels: u8,
pub channel_config_bitmap: u32,
pub channel_names: StringIndex,
pub controls_bitmap: u16,
pub terminal_name: StringIndex,
}
impl USBDescriptor for InputTerminalDescriptor {
const SIZE: usize = 17;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
if bytes[2] != ac_descriptor::INPUT_TERMINAL {
return Err(());
}
Ok(Self {
terminal_id: bytes[3],
terminal_type: terminal_type_from_u16(u16::from_le_bytes([bytes[4], bytes[5]])),
associated_terminal_id: bytes[6],
clock_source_id: bytes[7],
num_channels: bytes[8],
channel_config_bitmap: u32::from_le_bytes([bytes[9], bytes[10], bytes[11], bytes[12]]),
channel_names: bytes[13],
controls_bitmap: u16::from_le_bytes([bytes[14], bytes[15]]),
terminal_name: bytes[16],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OutputTerminalDescriptor {
pub terminal_id: u8,
pub terminal_type: TerminalType,
pub associated_terminal_id: u8,
pub source_id: u8,
pub clock_source_id: u8,
pub controls_bitmap: u16,
pub terminal_name: StringIndex,
}
impl USBDescriptor for OutputTerminalDescriptor {
const SIZE: usize = 12;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
if bytes[2] != ac_descriptor::OUTPUT_TERMINAL {
return Err(());
}
Ok(Self {
terminal_id: bytes[3],
terminal_type: terminal_type_from_u16(u16::from_le_bytes([bytes[4], bytes[5]])),
associated_terminal_id: bytes[6],
source_id: bytes[7],
clock_source_id: bytes[8],
controls_bitmap: u16::from_le_bytes([bytes[9], bytes[10]]),
terminal_name: bytes[11],
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum UnitDescriptor {
Mixer(u8),
Selector(u8),
Feature(u8),
Processing(u8),
Effect(u8),
SampleRateConverter(u8),
Extension(u8),
}
impl USBDescriptor for UnitDescriptor {
const SIZE: usize = 4; const DESC_TYPE: u8 = CS_INTERFACE;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
match bytes[2] {
ac_descriptor::MIXER_UNIT => Ok(Self::Mixer(bytes[3])),
ac_descriptor::SELECTOR_UNIT => Ok(Self::Selector(bytes[3])),
ac_descriptor::FEATURE_UNIT => Ok(Self::Feature(bytes[3])),
ac_descriptor::PROCESSING_UNIT => Ok(Self::Processing(bytes[3])),
ac_descriptor::EFFECT_UNIT => Ok(Self::Effect(bytes[3])),
ac_descriptor::SAMPLE_RATE_CONVERTER => Ok(Self::SampleRateConverter(bytes[3])),
ac_descriptor::EXTENSION_UNIT => Ok(Self::Extension(bytes[3])),
_ => Err(()),
}
}
}
impl UnitDescriptor {
pub fn unit_id(&self) -> u8 {
match self {
Self::Mixer(id) => *id,
Self::Selector(id) => *id,
Self::Feature(id) => *id,
Self::Processing(id) => *id,
Self::Effect(id) => *id,
Self::SampleRateConverter(id) => *id,
Self::Extension(id) => *id,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AudioStreamingInterface {
pub interface_descriptors: Vec<InterfaceDescriptor, MAX_ALTERNATE_SETTINGS>,
pub class_descriptor: AudioStreamingClassDescriptor,
pub endpoint_descriptor: Option<EndpointDescriptor>,
pub feedback_endpoint_descriptor: Option<EndpointDescriptor>,
pub audio_endpoint_descriptor: Option<AudioEndpointDescriptor>,
pub format_type_descriptor: Option<FormatTypeDescriptor>,
}
impl AudioStreamingInterface {
fn new(
interfaces: Vec<InterfaceDescriptor, MAX_ALTERNATE_SETTINGS>,
class_desc: AudioStreamingClassDescriptor,
) -> Self {
Self {
interface_descriptors: interfaces,
class_descriptor: class_desc,
endpoint_descriptor: None,
feedback_endpoint_descriptor: None,
audio_endpoint_descriptor: None,
format_type_descriptor: None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AudioStreamingClassDescriptor {
pub terminal_link_id: u8,
pub controls_bitmap: u8,
pub format: format_type::Format,
pub num_channels: u8,
pub channel_config_bitmap: u32,
pub channel_name: StringIndex,
}
impl USBDescriptor for AudioStreamingClassDescriptor {
const SIZE: usize = 16;
const DESC_TYPE: u8 = CS_INTERFACE;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
if bytes[2] != as_descriptor::GENERAL {
return Err(());
}
let format =
format_type::Format::from_u32(bytes[5], u32::from_le_bytes([bytes[6], bytes[7], bytes[8], bytes[9]]));
if format.is_none() {
error!("Invalid format type descriptor: type {:?}", bytes[5]);
return Err(());
}
Ok(Self {
terminal_link_id: bytes[3],
controls_bitmap: bytes[4],
format: format.unwrap(),
num_channels: bytes[10],
channel_config_bitmap: u32::from_le_bytes([bytes[11], bytes[12], bytes[13], bytes[14]]),
channel_name: bytes[15],
})
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AudioEndpointDescriptor {
pub attributes_bitmap: u8,
pub controls_bitmap: u8,
pub lock_delay_units: u8,
pub lock_delay: u16,
}
impl USBDescriptor for AudioEndpointDescriptor {
const SIZE: usize = 6;
const DESC_TYPE: u8 = descriptor_type::CS_ENDPOINT;
type Error = ();
fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < Self::SIZE {
return Err(());
}
if bytes[1] != Self::DESC_TYPE {
return Err(());
}
if bytes[2] != as_descriptor::GENERAL {
return Err(());
}
Ok(Self {
attributes_bitmap: bytes[3],
controls_bitmap: bytes[4],
lock_delay_units: bytes[5],
lock_delay: u16::from_le_bytes([bytes[6], bytes[7]]),
})
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FormatTypeDescriptor {
I(FormatTypeI),
II(FormatTypeII),
III(FormatTypeIII),
IV,
ExtendedI(FormatTypeExtendedI),
ExtendedII(FormatTypeExtendedII),
ExtendedIII(FormatTypeExtendedIII),
}
impl FormatTypeDescriptor {
fn try_from_bytes(bytes: &[u8]) -> Result<Self, ()> {
if bytes.len() < 4 {
return Err(());
}
let len = bytes[0] as usize;
if bytes[1] != CS_INTERFACE {
return Err(());
}
if bytes[2] != as_descriptor::FORMAT_TYPE {
return Err(());
}
match bytes[3] {
format_type::I => {
if len != 6 {
return Err(());
}
Ok(Self::I(FormatTypeI {
subslot_size: bytes[4],
bit_resolution: bytes[5],
}))
}
format_type::II => {
if len != 8 {
return Err(());
}
Ok(Self::II(FormatTypeII {
max_bit_rate: u16::from_le_bytes([bytes[4], bytes[5]]),
slots_per_frame: u16::from_le_bytes([bytes[6], bytes[7]]),
}))
}
format_type::III => {
if len != 6 {
return Err(());
}
Ok(Self::III(FormatTypeIII {
subslot_size: bytes[4],
bit_resolution: bytes[5],
}))
}
format_type::IV => Ok(Self::IV),
format_type::EXT_I => {
if len != 9 {
return Err(());
}
Ok(Self::ExtendedI(FormatTypeExtendedI {
subslot_size: bytes[4],
bit_resolution: bytes[5],
header_length: bytes[6],
control_size: bytes[7],
sideband_protocol: bytes[8],
}))
}
format_type::EXT_II => {
if len != 10 {
return Err(());
}
Ok(Self::ExtendedII(FormatTypeExtendedII {
max_bit_rate: u16::from_le_bytes([bytes[4], bytes[5]]),
samples_per_frame: u16::from_le_bytes([bytes[6], bytes[7]]),
header_length: bytes[8],
sideband_protocol: bytes[9],
}))
}
format_type::EXT_III => {
if len != 8 {
return Err(());
}
Ok(Self::ExtendedIII(FormatTypeExtendedIII {
subslot_size: bytes[4],
bit_resolution: bytes[5],
header_length: bytes[6],
sideband_protocol: bytes[7],
}))
}
_ => Err(()),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeI {
pub subslot_size: u8,
pub bit_resolution: u8,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeII {
pub max_bit_rate: u16,
pub slots_per_frame: u16,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeIII {
pub subslot_size: u8,
pub bit_resolution: u8,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeExtendedI {
pub subslot_size: u8,
pub bit_resolution: u8,
pub header_length: u8,
pub control_size: u8,
pub sideband_protocol: u8,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeExtendedII {
pub max_bit_rate: u16,
pub samples_per_frame: u16,
pub header_length: u8,
pub sideband_protocol: u8,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FormatTypeExtendedIII {
pub subslot_size: u8,
pub bit_resolution: u8,
pub header_length: u8,
pub sideband_protocol: u8,
}
#[cfg(test)]
mod test {
use env_logger;
use heapless::Vec;
use super::*;
use crate::descriptor::ConfigurationDescriptor;
#[test]
fn test_parse() {
let _ = env_logger::try_init();
let mut buffer: [u8; 512] = [0; 512];
let descriptors = [
8, 11, 0, 4, 1, 0, 32, 0, 9, 4, 0, 0, 0, 1, 1, 32, 7, 9, 36, 1, 0, 2, 8, 223, 0, 0, 8, 36, 10, 40, 1, 7, 0, 16, 17, 36, 2, 2, 1, 1, 0, 40, 16, 0, 0, 0, 0, 18, 0, 0, 2, 74, 36, 6, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 15, 12, 36, 3, 20, 1, 3, 0, 10, 40, 0, 0, 5, 17, 36, 2, 1, 1, 2, 0, 40, 16, 0, 0, 0, 0, 50, 0, 0, 3, 74, 36, 6, 11, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 14, 12, 36, 3, 22, 1, 1, 0, 11, 40, 0, 0, 4, 9, 4, 1, 0, 0, 1, 2, 32, 8, 9, 4, 1, 1, 2, 1, 2, 32, 9, 16, 36, 1, 2, 0, 1, 1, 0, 0, 0, 16, 0, 0, 0, 0, 18, 6, 36, 2, 1, 4, 24, 7, 5, 1, 5, 0, 2, 1, 8, 37, 1, 0, 0, 2, 8, 0, 7, 5, 129, 17, 4, 0, 4, 9, 4, 2, 0, 0, 1, 2, 32, 10, 9, 4, 2, 1, 1, 1, 2, 32, 11, 16, 36, 1, 22, 0, 1, 1, 0, 0, 0, 16, 0, 0, 0, 0, 50, 6, 36, 2, 1, 4, 24, 7, 5, 130, 5, 0, 2, 1, 8, 37, 1, 0, 0, 2, 8, 0, 9, 4, 3, 0, 0, 1, 1, 0, 0, 9, 36, 1, 0, 1, 9, 0, 1, 1, 9, 4, 4, 0, 2, 1, 3, 0, 0, 7, 36, 1, 0, 1, 61, 0, 6, 36, 2, 1, 51, 0, 6, 36, 2, 2, 52, 82, 9, 36, 3, 1, 55, 1, 52, 1, 0, 9, 36, 3, 2, 56, 1, 51, 1, 83, 7, 5, 131, 2, 0, 2, 0, 5, 37, 1, 1, 55, 7, 5, 2, 2, 0, 2, 0, 5, 37, 1, 1, 51, 9, 4, 5, 0, 0, 254, 1, 1, 0, 7, 33, 7, 250, 0, 64, 0, ];
buffer[..descriptors.len()].copy_from_slice(&descriptors);
let descriptor = ConfigurationDescriptor {
len: 0,
descriptor_type: 0,
total_len: 0,
num_interfaces: 0,
configuration_value: 1,
configuration_name: 0,
attributes: 0,
max_power: 0,
buffer: &buffer,
};
let mut expected_clock_descriptors = FnvIndexMap::<u8, ClockDescriptor, MAX_CLOCK_DESCRIPTORS>::new();
let mut expected_unit_descriptors = FnvIndexMap::<u8, UnitDescriptor, MAX_UNIT_DESCRIPTORS>::new();
let mut expected_terminal_descriptors = FnvIndexMap::<u8, TerminalDescriptor, MAX_TERMINAL_DESCRIPTORS>::new();
expected_clock_descriptors
.insert(
40,
ClockDescriptor::Source(ClockSourceDescriptor {
clock_id: 40,
attributes_bitmap: 1,
controls_bitmap: 7,
associated_terminal: 0,
clock_name: 16,
}),
)
.unwrap();
expected_unit_descriptors
.insert(10, UnitDescriptor::Feature(10))
.unwrap();
expected_unit_descriptors
.insert(11, UnitDescriptor::Feature(11))
.unwrap();
expected_terminal_descriptors
.insert(
2,
TerminalDescriptor::Input(InputTerminalDescriptor {
terminal_id: 2,
terminal_type: TerminalType::UsbStreaming,
associated_terminal_id: 0,
clock_source_id: 40,
num_channels: 16,
channel_config_bitmap: 0,
channel_names: 18,
controls_bitmap: 0,
terminal_name: 2,
}),
)
.unwrap();
expected_terminal_descriptors
.insert(
20,
TerminalDescriptor::Output(OutputTerminalDescriptor {
terminal_id: 20,
terminal_type: TerminalType::Speaker,
associated_terminal_id: 0,
source_id: 10,
clock_source_id: 40,
controls_bitmap: 0,
terminal_name: 5,
}),
)
.unwrap();
expected_terminal_descriptors
.insert(
1,
TerminalDescriptor::Input(InputTerminalDescriptor {
terminal_id: 1,
terminal_type: TerminalType::Microphone,
associated_terminal_id: 0,
clock_source_id: 40,
num_channels: 16,
channel_config_bitmap: 0,
channel_names: 50,
controls_bitmap: 0,
terminal_name: 3,
}),
)
.unwrap();
expected_terminal_descriptors
.insert(
22,
TerminalDescriptor::Output(OutputTerminalDescriptor {
terminal_id: 22,
terminal_type: TerminalType::UsbStreaming,
associated_terminal_id: 0,
source_id: 11,
clock_source_id: 40,
controls_bitmap: 0,
terminal_name: 4,
}),
)
.unwrap();
let expected = AudioInterfaceCollection {
interface_association_descriptor: InterfaceAssociationDescriptor {
first_interface: 0,
num_interfaces: 4,
class: 1,
subclass: 0,
protocol: 32,
interface_name: 0,
},
control_interface: AudioControlInterface {
interface_descriptors: Vec::from_slice(&[InterfaceDescriptor {
len: 9,
descriptor_type: 4,
interface_number: 0,
alternate_setting: 0,
num_endpoints: 0,
interface_class: 1,
interface_subclass: 1,
interface_protocol: 32,
interface_name: 7,
}])
.unwrap(),
header_descriptor: AudioControlHeaderDescriptor {
audio_device_class: (2, 0),
category: 8,
controls_bitmap: 0,
},
interrupt_endpoint_descriptor: None,
clock_descriptors: expected_clock_descriptors,
unit_descriptors: expected_unit_descriptors,
terminal_descriptors: expected_terminal_descriptors,
},
audio_streaming_interfaces: Vec::from_slice(&[
AudioStreamingInterface {
interface_descriptors: Vec::from_slice(&[
InterfaceDescriptor {
len: 9,
descriptor_type: 4,
interface_number: 1,
alternate_setting: 0,
num_endpoints: 0,
interface_class: 1,
interface_subclass: 2,
interface_protocol: 32,
interface_name: 8,
},
InterfaceDescriptor {
len: 9,
descriptor_type: 4,
interface_number: 1,
alternate_setting: 1,
num_endpoints: 2,
interface_class: 1,
interface_subclass: 2,
interface_protocol: 32,
interface_name: 9,
},
])
.unwrap(),
class_descriptor: AudioStreamingClassDescriptor {
terminal_link_id: 2,
controls_bitmap: 0,
format: format_type::Format::Type1(format_type::Type1::PCM),
num_channels: 16,
channel_config_bitmap: 0,
channel_name: 18,
},
endpoint_descriptor: Some(EndpointDescriptor {
len: 7,
descriptor_type: 5,
endpoint_address: 1,
attributes: 5,
max_packet_size: 512,
interval: 1,
}),
feedback_endpoint_descriptor: Some(EndpointDescriptor {
len: 7,
descriptor_type: 5,
endpoint_address: 129,
attributes: 17,
max_packet_size: 4,
interval: 4,
}),
audio_endpoint_descriptor: Some(AudioEndpointDescriptor {
attributes_bitmap: 0,
controls_bitmap: 0,
lock_delay_units: 2,
lock_delay: 8,
}),
format_type_descriptor: Some(FormatTypeDescriptor::I(FormatTypeI {
subslot_size: 4,
bit_resolution: 24,
})),
},
AudioStreamingInterface {
interface_descriptors: Vec::from_slice(&[
InterfaceDescriptor {
len: 9,
descriptor_type: 4,
interface_number: 2,
alternate_setting: 0,
num_endpoints: 0,
interface_class: 1,
interface_subclass: 2,
interface_protocol: 32,
interface_name: 10,
},
InterfaceDescriptor {
len: 9,
descriptor_type: 4,
interface_number: 2,
alternate_setting: 1,
num_endpoints: 1,
interface_class: 1,
interface_subclass: 2,
interface_protocol: 32,
interface_name: 11,
},
])
.unwrap(),
class_descriptor: AudioStreamingClassDescriptor {
terminal_link_id: 22,
controls_bitmap: 0,
format: format_type::Format::Type1(format_type::Type1::PCM),
num_channels: 16,
channel_config_bitmap: 0,
channel_name: 50,
},
endpoint_descriptor: Some(EndpointDescriptor {
len: 7,
descriptor_type: 5,
endpoint_address: 130,
attributes: 5,
max_packet_size: 512,
interval: 1,
}),
feedback_endpoint_descriptor: None,
audio_endpoint_descriptor: Some(AudioEndpointDescriptor {
attributes_bitmap: 0,
controls_bitmap: 0,
lock_delay_units: 2,
lock_delay: 8,
}),
format_type_descriptor: Some(FormatTypeDescriptor::I(FormatTypeI {
subslot_size: 4,
bit_resolution: 24,
})),
},
])
.unwrap(),
};
let audio_interface_collection = AudioInterfaceCollection::try_from_configuration(&descriptor).unwrap();
assert_eq!(audio_interface_collection, expected);
}
}