#![no_std]
use class_codes::*;
use core::convert::From;
use usb_device::control::{Recipient, Request, RequestType};
use usb_device::device::DEFAULT_ALTERNATE_SETTING;
use usb_device::endpoint::{Endpoint, EndpointDirection, In, Out};
use usb_device::{class_prelude::*, UsbDirection};
mod terminal_type;
pub use terminal_type::TerminalType;
mod class_codes;
const ID_INPUT_TERMINAL: u8 = 0x01;
const ID_OUTPUT_TERMINAL: u8 = 0x02;
const MAX_ISO_EP_SIZE: u32 = 1023;
#[derive(Clone, Copy, Debug)]
pub enum Format {
S16le,
S24le,
}
#[derive(Debug)]
pub enum Rates<'a> {
Continuous(u32, u32),
Discrete(&'a [u32]),
}
#[derive(Debug)]
pub struct StreamConfig<'a> {
format: Format,
channels: u8,
rates: Rates<'a>,
terminal_type: TerminalType,
ep_size: u16,
}
impl StreamConfig<'_> {
pub fn new_discrete(
format: Format,
channels: u8,
rates: &'_ [u32],
terminal_type: TerminalType,
) -> Result<StreamConfig<'_>> {
let max_rate = rates.iter().max().unwrap();
let ep_size = Self::ep_size(format, channels, *max_rate)?;
let rates = Rates::Discrete(rates);
Ok(StreamConfig {
format,
channels,
rates,
terminal_type,
ep_size,
})
}
pub fn new_continuous(
format: Format,
channels: u8,
min_rate: u32,
max_rate: u32,
terminal_type: TerminalType,
) -> Result<StreamConfig<'static>> {
if min_rate >= max_rate {
return Err(Error::InvalidValue);
}
let ep_size = Self::ep_size(format, channels, max_rate)?;
let rates = Rates::Continuous(min_rate, max_rate);
Ok(StreamConfig {
format,
channels,
rates,
terminal_type,
ep_size,
})
}
fn ep_size(format: Format, channels: u8, max_rate: u32) -> Result<u16> {
let octets_per_frame = channels as u32
* match format {
Format::S16le => 2,
Format::S24le => 3,
};
let ep_size = octets_per_frame * max_rate / 1000;
if ep_size > MAX_ISO_EP_SIZE {
return Err(Error::BandwidthExceeded);
}
Ok(ep_size as u16)
}
}
#[derive(Debug)]
pub enum Error {
InvalidValue,
BandwidthExceeded,
StreamNotInitialized,
UsbError(usb_device::UsbError),
}
impl From<UsbError> for Error {
fn from(err: UsbError) -> Self {
Error::UsbError(err)
}
}
type Result<T> = core::result::Result<T, Error>;
struct AudioStream<'a, B: UsbBus, D: EndpointDirection> {
stream_config: StreamConfig<'a>,
interface: InterfaceNumber,
endpoint: Endpoint<'a, B, D>,
alt_setting: u8,
}
macro_rules! append {
($iter:ident, $value:expr) => {
*($iter.next().ok_or(UsbError::BufferOverflow)?.1) = $value;
};
}
macro_rules! append_u24le {
($iter:ident, $value:expr) => {
append!($iter, $value as u8);
append!($iter, ($value >> 8) as u8);
append!($iter, ($value >> 16) as u8);
};
}
impl<B: UsbBus, D: EndpointDirection> AudioStream<'_, B, D> {
fn write_ac_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()> {
let is_input = self.endpoint.address().direction() == UsbDirection::In;
let terminal_type: u16 = self.stream_config.terminal_type.into();
let id_offset = if is_input { 0 } else { 4 };
let tt = if is_input {
terminal_type
} else {
TerminalType::UsbStreaming.into()
}
.to_le_bytes();
let channel_config = match self.stream_config.channels {
1 => 0x0001u16, 2 => 0x0003u16, 4 => 0x0033u16, 6 => 0x003Fu16, 8 => 0x00FFu16, _ => 0x0003u16, };
writer.write(
CS_INTERFACE,
&[
INPUT_TERMINAL, ID_INPUT_TERMINAL + id_offset, tt[0], tt[1],
0x00, self.stream_config.channels, (channel_config & 0xFF) as u8,
(channel_config >> 8) as u8, 0x00, 0x00, ],
)?;
let tt = if is_input {
TerminalType::UsbStreaming.into()
} else {
terminal_type
}
.to_le_bytes();
writer.write(
CS_INTERFACE,
&[
OUTPUT_TERMINAL, ID_OUTPUT_TERMINAL + id_offset, tt[0], tt[1],
0x00, ID_INPUT_TERMINAL + id_offset, 0x00, ],
)
}
fn write_as_and_ep_descriptors(&self, writer: &mut DescriptorWriter) -> usb_device::Result<()> {
let is_input = self.endpoint.address().direction() == UsbDirection::In;
let id_offset = if is_input { 0 } else { 4 };
writer.interface(self.interface, AUDIO, AUDIOSTREAMING, 0x00)?;
writer.interface_alt(self.interface, 0x01, AUDIO, AUDIOSTREAMING, 0x00, None)?;
let terminal_link = id_offset
+ if is_input {
ID_OUTPUT_TERMINAL
} else {
ID_INPUT_TERMINAL
};
writer.write(
CS_INTERFACE,
&[
AS_GENERAL, terminal_link, 0x01, PCM as u8,
(PCM >> 8) as u8, ],
)?;
let mut format_desc = [0x00u8; 128];
let mut iter = format_desc.iter_mut().enumerate();
append!(iter, FORMAT_TYPE); append!(iter, FORMAT_TYPE_I); append!(iter, self.stream_config.channels); append!(
iter,
match self.stream_config.format {
Format::S16le => 2,
Format::S24le => 3,
}
);
append!(
iter,
match self.stream_config.format {
Format::S16le => 16,
Format::S24le => 24,
}
);
match self.stream_config.rates {
Rates::Continuous(min, max) => {
append!(iter, 0x00); append_u24le!(iter, min);
append_u24le!(iter, max);
}
Rates::Discrete(rates) => {
append!(iter, rates.len() as u8); for rate in rates {
append_u24le!(iter, *rate);
}
}
}
let length = iter.next().unwrap().0;
writer.write(CS_INTERFACE, &format_desc[..length])?;
writer.endpoint(&self.endpoint)?;
writer.write(
0x25,
&[
0x01, 0x00, 0x00, 0x00, 0x00, ],
)
}
}
pub struct AudioClassBuilder<'a> {
input: Option<StreamConfig<'a>>,
output: Option<StreamConfig<'a>>,
}
impl<'a> AudioClassBuilder<'a> {
pub fn new() -> AudioClassBuilder<'static> {
AudioClassBuilder {
input: None,
output: None,
}
}
pub fn input(self, input: StreamConfig<'a>) -> AudioClassBuilder<'a> {
AudioClassBuilder {
input: Some(input),
output: self.output,
}
}
pub fn output(self, output: StreamConfig<'a>) -> AudioClassBuilder<'a> {
AudioClassBuilder {
input: self.input,
output: Some(output),
}
}
pub fn build<B: UsbBus>(self, alloc: &'a UsbBusAllocator<B>) -> Result<AudioClass<'a, B>> {
let control_iface = alloc.interface();
let mut ac = AudioClass {
control_iface,
input: None,
output: None,
};
if let Some(stream_config) = self.input {
let interface = alloc.interface();
let endpoint = alloc.alloc(
None,
EndpointType::Isochronous {
synchronization: IsochronousSynchronizationType::Asynchronous,
usage: IsochronousUsageType::Data,
},
stream_config.ep_size,
1,
)?;
let alt_setting = DEFAULT_ALTERNATE_SETTING;
ac.input = Some(AudioStream {
stream_config,
interface,
endpoint,
alt_setting,
})
}
if let Some(stream_config) = self.output {
let interface = alloc.interface();
let endpoint = alloc.alloc(
None,
EndpointType::Isochronous {
synchronization: IsochronousSynchronizationType::Adaptive,
usage: IsochronousUsageType::Data,
},
stream_config.ep_size,
1,
)?;
let alt_setting = DEFAULT_ALTERNATE_SETTING;
ac.output = Some(AudioStream {
stream_config,
interface,
endpoint,
alt_setting,
})
}
Ok(ac)
}
}
pub struct AudioClass<'a, B: UsbBus> {
control_iface: InterfaceNumber,
input: Option<AudioStream<'a, B, In>>,
output: Option<AudioStream<'a, B, Out>>,
}
impl<B: UsbBus> AudioClass<'_, B> {
pub fn read(&self, data: &mut [u8]) -> Result<usize> {
if let Some(ref info) = self.output {
info.endpoint.read(data).map_err(Error::UsbError)
} else {
Err(Error::StreamNotInitialized)
}
}
pub fn write(&self, data: &[u8]) -> Result<usize> {
if let Some(ref info) = self.input {
info.endpoint.write(data).map_err(Error::UsbError)
} else {
Err(Error::StreamNotInitialized)
}
}
pub fn input_alt_setting(&self) -> Result<u8> {
self.input
.as_ref()
.ok_or(Error::StreamNotInitialized)
.map(|si| si.alt_setting)
}
pub fn output_alt_setting(&self) -> Result<u8> {
self.output
.as_ref()
.ok_or(Error::StreamNotInitialized)
.map(|si| si.alt_setting)
}
}
impl<B: UsbBus> UsbClass<B> for AudioClass<'_, B> {
fn get_configuration_descriptors(
&self,
writer: &mut DescriptorWriter,
) -> usb_device::Result<()> {
let mut in_collection = 0u8;
if self.input.is_some() {
in_collection += 1;
}
if self.output.is_some() {
in_collection += 1;
}
writer.iad(
self.control_iface,
in_collection + 1, AUDIO, AUDIOCONTROL,
0x00, None, )?;
writer.interface(self.control_iface, AUDIO, AUDIOCONTROL, 0x00)?;
let total_length = 8u16 + (1 + 21) * in_collection as u16;
let mut ac_header = [
HEADER, 0x00,
0x01, total_length as u8,
(total_length >> 8) as u8, in_collection, 0x00,
0x00, ];
let mut ndx = 6;
if let Some(ref input) = self.input {
ac_header[ndx] = input.interface.into();
ndx += 1;
}
if let Some(ref output) = self.output {
ac_header[ndx] = output.interface.into();
ndx += 1;
}
writer.write(CS_INTERFACE, &ac_header[..ndx])?;
if let Some(ref a) = self.input {
a.write_ac_descriptors(writer)?;
}
if let Some(ref a) = self.output {
a.write_ac_descriptors(writer)?;
}
if let Some(ref a) = self.input {
a.write_as_and_ep_descriptors(writer)?;
}
if let Some(ref a) = self.output {
a.write_as_and_ep_descriptors(writer)?;
}
Ok(())
}
fn control_in(&mut self, xfer: ControlIn<B>) {
let req = xfer.request();
if req.request_type == RequestType::Standard
&& req.recipient == Recipient::Interface
&& req.request == Request::GET_INTERFACE
&& req.length == 1
{
let iface = req.index as u8;
if let Some(info) = self.input.as_ref() {
if iface == info.interface.into() {
xfer.accept_with(&[info.alt_setting]).ok();
return;
}
}
if let Some(info) = self.output.as_ref() {
if iface == info.interface.into() {
xfer.accept_with(&[info.alt_setting]).ok();
}
}
}
}
fn control_out(&mut self, xfer: ControlOut<B>) {
let req = xfer.request();
if req.request_type == RequestType::Standard
&& req.recipient == Recipient::Interface
&& req.request == Request::SET_INTERFACE
{
let iface = req.index as u8;
let alt_setting = req.value;
if let Some(info) = self.input.as_mut() {
if iface == info.interface.into() {
info.alt_setting = alt_setting as u8;
xfer.accept().ok();
return;
}
}
if let Some(info) = self.output.as_mut() {
if iface == info.interface.into() {
info.alt_setting = alt_setting as u8;
xfer.accept().ok();
}
}
}
}
}