| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568 |
- //! USB audio class for asynchronous, bidirectional (microphone + speakers) 48kHz audio.
- //!
- //! See "Universal Serial Bus Device Class Definition for Audio Devices", release 1.0 (March 18,
- //! 1998) for a specification of the USB audio class.
- use usb_device::class_prelude::*;
- use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
- use usb_device::Result;
-
- const DEVICE_CLASS_AUDIO: u8 = 0x01;
- const AUDIO_SUBCLASS_CONTROL: u8 = 0x01;
- const AUDIO_SUBCLASS_STREAMING: u8 = 0x02;
- const AUDIO_PROTOCOL_NONE: u8 = 0x00;
-
- const AUDIO_INTERFACE_DESC_TYPE: u8 = 0x24;
- const AUDIO_ENDPOINT_DESC_TYPE: u8 = 0x25;
-
- const AUDIO_CONTROL_HEADER: u8 = 0x01;
- const AUDIO_CONTROL_INPUT_TERMINAL: u8 = 0x02;
- const AUDIO_CONTROL_OUTPUT_TERMINAL: u8 = 0x03;
- const AUDIO_CONTROL_FEATURE_UNIT: u8 = 0x06;
-
- const AUDIO_STREAMING_GENERAL: u8 = 0x01;
- const AUDIO_STREAMING_FORMAT_TYPE: u8 = 0x02;
-
- const AUDIO_ENDPOINT_GENERAL: u8 = 0x01;
-
- // TODO: Update bDelay.
-
- pub struct UsbAudioClass<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> {
- audio_control: InterfaceNumber,
- audio_streaming_inactive: InterfaceNumber,
- audio_streaming: InterfaceNumber,
- audio_out: EndpointOut<'a, B>,
- audio_out_sync: EndpointIn<'a, B>,
- //audio_in: EndpointIn<'a, B>,
- samples_per_frame: [u8; 3],
-
- audio_out_buf: Option<OUTBUF>,
- }
-
- impl<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> UsbAudioClass<'a, B, OUTBUF> {
- pub fn new(bus_alloc: &'a UsbBusAllocator<B>) -> Self {
- UsbAudioClass {
- audio_control: bus_alloc.interface(),
- audio_streaming_inactive: bus_alloc.interface(),
- audio_streaming: bus_alloc.interface(),
- // 48kHz * 2 * 16bit = 192B per packet. We allocate a bit more in case the device clock
- // is faster than the host clock.
- /*audio_out: bus_alloc.isochronous(
- IsochronousSynchronizationType::Asynchronous,
- IsochronousUsageType::Data,
- 256,
- 1,
- ),*/
- audio_out: bus_alloc.isochronous(
- IsochronousSynchronizationType::Synchronous,
- IsochronousUsageType::Data,
- 256,
- 1,
- ),
- audio_out_sync: bus_alloc.isochronous(
- IsochronousSynchronizationType::Asynchronous,
- IsochronousUsageType::Feedback,
- 3,
- 1,
- ),
- /*audio_in: bus_alloc.isochronous(
- IsochronousSynchronizationType::Asynchronous,
- IsochronousUsageType::Data,
- 256,
- 1,
- ),*/
- samples_per_frame: [48 >> 2, 48 << 6, 0], // 48 kHz
- audio_out_buf: None,
- }
- }
-
- // TODO: Functions to read and write data?
- }
-
- impl<B: UsbBus, OUTBUF: AsRef<[u32]>> UsbClass<B> for UsbAudioClass<'_, B, OUTBUF> {
- fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
- writer.iad(
- self.audio_control,
- 2, // Two interfaces (control + streaming).
- 0x0, // Each interface specifies its own class.
- 0x0, // Each interface specifies its own subclass.
- 0x0, // No class-specific protocols for this device.
- )?;
-
- // Audio control interface.
- writer.interface(
- self.audio_control,
- DEVICE_CLASS_AUDIO,
- AUDIO_SUBCLASS_CONTROL,
- AUDIO_PROTOCOL_NONE,
- )?;
-
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_CONTROL_HEADER, // bDescriptorSubtype
- 0x00, // bcdADC
- 0x01, //
- 37, // wTotalLength
- 0, //
- 0x01, // bInCollection
- self.audio_streaming.into(), // baInterfaceNr
- ],
- )?;
-
- // Input terminal (USB streaming).
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_CONTROL_INPUT_TERMINAL, // bDescriptorSubtype
- 0x01, // bTerminalID
- 0x01, // wTerminalType
- 0x01, //
- 0x00, // bAssocTerminal
- 0x02, // bNrChannels
- 0x03, // wChannelConfig
- 0x00, //
- 0x00, // iChannelNames
- 0x00, // iTerminal
- ],
- )?;
-
- // Feature unit (volume and mute).
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_CONTROL_FEATURE_UNIT, // bDescriptorSubtype
- 0x02, // bUnitID
- 0x01, // bSourceID
- 0x01, // bControlSize
- 0x03, // bmaControls(0)
- 0x00, // iFeature
- ],
- )?;
-
- // Output terminal (speaker).
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_CONTROL_OUTPUT_TERMINAL, // bDescriptorSubtype
- 0x03, // bTerminalID
- 0x01, // wTerminalType
- 0x03, //
- 0x00, // bAssocTerminal
- 0x02, // bSourceID
- 0x00, // iTerminal
- ],
- )?;
-
- // Audio streaming interface (zero-bandwidth).
- writer.interface(
- self.audio_streaming_inactive,
- DEVICE_CLASS_AUDIO,
- AUDIO_SUBCLASS_STREAMING,
- AUDIO_PROTOCOL_NONE,
- )?;
-
- // Audio streaming interface (operational).
- writer.interface_alt(
- self.audio_streaming,
- 1,
- DEVICE_CLASS_AUDIO,
- AUDIO_SUBCLASS_STREAMING,
- AUDIO_PROTOCOL_NONE,
- None,
- )?;
-
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_STREAMING_GENERAL, // bDescriptorSubtype
- 0x01, // bTerminalLink
- 0x03, // bDelay
- 0x01, // wFormatTag
- 0x00, //
- ],
- )?;
-
- writer.write(
- AUDIO_INTERFACE_DESC_TYPE,
- &[
- AUDIO_STREAMING_FORMAT_TYPE, // bDescriptorSubtype
- 0x01, // bFormatType
- 0x02, // bNrChannels
- 0x02, // bSubframeSize
- 0x10, // bBitResolution
- 0x01, // bSamFreqType
- ],
- )?;
-
- /*writer.endpoint_ex(&self.audio_out, |data| {
- // TODO: Faster refresh
- data[0] = 0x09; // bRefresh
- data[1] = self.audio_out_sync.address().into(); // bSynchAddress
- Ok(2)
- })?;*/
- writer.endpoint(&self.audio_out)?;
-
- writer.write(
- AUDIO_ENDPOINT_DESC_TYPE,
- &[
- AUDIO_ENDPOINT_GENERAL, // bDescriptorSubtype
- 0x00, // bmAttributes
- 0x01, // bLockDelayUnits
- 0x00, // wLockDelay
- 0x00,
- ],
- )?;
-
- /*writer.endpoint_ex(&self.audio_out_sync, |data| {
- data[0] = 0x00; // bRefresh
- data[1] = 0x00; // bSynchAddress
- Ok(2)
- })?;*/
-
- Ok(())
- }
-
- fn get_string(&self, _index: StringIndex, _lang_id: u16) -> Option<&str> {
- // TODO
- None
- }
-
- fn reset(&mut self) {
- // Start sending synchronization data.
- self.endpoint_in_complete(self.audio_out_sync.address());
- }
-
- fn control_out(&mut self, xfer: ControlOut<B>) {
- let req = xfer.request();
-
- if !(req.request_type == control::RequestType::Class
- && req.recipient == control::Recipient::Interface
- && req.index == u8::from(self.audio_control) as u16)
- {
- return;
- }
-
- match req.request {
- // TODO
- _ => {
- xfer.reject().ok();
- }
- };
- }
-
- fn control_in(&mut self, xfer: ControlIn<B>) {
- let req = xfer.request();
-
- if !(req.request_type == control::RequestType::Class
- && req.recipient == control::Recipient::Interface
- && req.index == u8::from(self.audio_control) as u16)
- {
- return;
- }
-
- match req.request {
- // TODO
- _ => {
- xfer.reject().ok();
- }
- };
- }
-
- fn endpoint_out(&mut self, addr: EndpointAddress) {
- if addr == self.audio_out.address() {
- if self.audio_out_buf.is_some() {
- // TODO: Write data into buffer, move buffer somewhere else.
- } else {
- // TODO
- }
- // TODO: Process incoming audio data.
- let mut buffer = [0u8; 256];
- self.audio_out.read(&mut buffer);
- }
- }
-
- fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
- if addr == self.audio_out_sync.address() {
- // Immediately write the next sync value.
- //self.audio_out_sync.write(&self.samples_per_frame).unwrap();
- }
- }
- }
-
- /*use usb_device::class_prelude::*;
- use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
- use usb_device::Result;
-
- /// This should be used as `device_class` when building the `UsbDevice`.
- pub const USB_INTERFACE_CLASS_AUDIO: u8 = 0x01;
-
- const USB_AUDIO_SUBCLASS_UNDEFINED: u8 = 0x0;
- const USB_AUDIO_SUBCLASS_AUDIOCONTROL: u8 = 0x01;
- const USB_AUDIO_SUBCLASS_AUDIOSTREAMING: u8 = 0x02;
- const USB_AUDIO_SUBCLASS_MIDISTREAMING: u8 = 0x03;
-
- const USB_CLASS_CDC_DATA: u8 = 0x0a;
- const CDC_SUBCLASS_ACM: u8 = 0x02;
- const USB_AUDIO_PROTOCOL_NONE: u8 = 0x00;
-
- const CS_DEVICE: u8 = 0x21;
- const CS_CONFIGURATION: u8 = 0x22;
- const CS_STRING: u8 = 0x23;
- const CS_INTERFACE: u8 = 0x24;
- const CS_ENDPOINT: u8 = 0x25;
-
- const EP_GENERAL: u8 = 0x1;
-
- const AC_DESC_TYPE_HEADER: u8 = 0x1;
- const AC_DESC_TYPE_INPUT_TERMINAL: u8 = 0x2;
- const AC_DESC_TYPE_OUTPUT_TERMINAL: u8 = 0x3;
- const AC_DESC_TYPE_MIXER_UNIT: u8 = 0x4;
- const AC_DESC_TYPE_SELECTOR_UNIT: u8 = 0x5;
- const AC_DESC_TYPE_FEATURE_UNIT: u8 = 0x6;
- const AC_DESC_TYPE_PROCESSING_UNIT: u8 = 0x7;
- const AC_DESC_TYPE_EXTENSION_UNIT: u8 = 0x8;
-
- const AC_DESC_ST_GENERAL: u8 = 0x1;
- const AC_DESC_ST_FORMAT_TYPE: u8 = 0x2;
- const AC_DESC_ST_FORMAT_SPECIFIC: u8 = 0x3;
-
- const AUDIO_SUB_TYPE_HEADER: u8 = 0x01;
- const AUDIO_SUB_TYPE_INPUT_TERMINAL: u8 = 0x02;
- const AUDIO_SUB_TYPE_FEATURE_UNIT: u8 = 0x06;
- const AUDIO_SUB_TYPE_OUTPUT_TERMINAL: u8 = 0x03;
- const AUDIO_SUB_TYPE_AS_GENERAL: u8 = 0x01;
- const AUDIO_SUB_TYPE_FORMAT_TYPE: u8 = 0x02;
-
- pub struct UsbAudioClass<'a, B: UsbBus> {
- audio_control_if: InterfaceNumber,
- audio_stream: InterfaceNumber,
- alt_audio_stream: InterfaceNumber,
- audio_in_ep: EndpointIn<'a, B>,
- }
-
- impl<B: UsbBus> UsbAudioClass<'_, B> {
- /// Creates a new UsbAudioClass with the provided UsbBus and max_packet_size in bytes. For
- /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
- pub fn new(alloc: &UsbBusAllocator<B>, max_packet_size: u16) -> UsbAudioClass<'_, B> {
- UsbAudioClass {
- audio_control_if: alloc.interface(),
- audio_stream: alloc.interface(),
- alt_audio_stream: alloc.interface(),
- audio_in_ep: alloc.isochronous(
- IsochronousSynchronizationType::Synchronous,
- IsochronousUsageType::Data,
- max_packet_size,
- 4,
- ),
- }
- }
-
- /// Gets the maximum packet size in bytes.
- pub fn max_packet_size(&self) -> u16 {
- self.audio_in_ep.max_packet_size()
- }
-
- /// Writes a single packet into the IN endpoint.
- pub fn write_packet(&mut self, data: &[u8]) -> Result<usize> {
- //defmt::info!("write_packet");
- self.audio_in_ep.write(data)
- }
-
- /// Gets the address of the IN endpoint.
- pub(crate) fn write_ep_address(&self) -> EndpointAddress {
- self.audio_in_ep.address()
- }
- }
-
- impl<B: UsbBus> UsbClass<B> for UsbAudioClass<'_, B> {
- fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
- writer.iad(
- self.audio_control_if,
- 3,
- 0x0, // device defined at interface level
- 0x0, // subclass unused
- USB_AUDIO_PROTOCOL_NONE,
- )?;
-
- writer.interface(
- self.audio_control_if,
- USB_INTERFACE_CLASS_AUDIO,
- USB_AUDIO_SUBCLASS_AUDIOCONTROL,
- USB_AUDIO_PROTOCOL_NONE,
- )?;
-
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_HEADER, // bDescriptorSubtype
- 0x00,
- 0x1, // bcdADC (1.0),
- 43,
- 0, // wTotalLength (Compute this!)
- 0x01, // bInCollection (1 streaming interface)
- 0x01, // baInterfaceNr (Interface 1 is stream)
- ],
- )?;
-
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_INPUT_TERMINAL, // bDescriptorSubtype
- 0x01, // bTerminalID 1,
- 0x10,
- 0x07, // wTerminalType (radio receiver)
- 0x00, // bAssocTerminal (none)
- 0x02, // bNrChannels - 2 for I and Q
- 0x03,
- 0x00, // wChannelConfig (left, right)
- 0x00, // iChannelNames (none)
- 0x00, // iTerminal (none)
- ],
- )?;
-
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_FEATURE_UNIT, // bDescriptorSubtype
- 0x02, // bUnitID,
- 0x01, // bSourceID (input terminal 1)
- 0x02, // bControlSize (2 bytes)
- 0x01,
- 0x00, // Master controls
- 0x00,
- 0x00, // Channel 0 controls
- 0x00,
- 0x00, // Channel 1 controls
- 0x00, // iFeature (none)
- ],
- )?;
-
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_OUTPUT_TERMINAL, // bDescriptorSubtype
- 0x03, // bTerminalID,
- 0x01,
- 0x01, // wTerminalType (USB Streaming)
- 0x00, // bAssocTerminal (none)
- 0x02, // bSourceID (feature unit 2)
- 0x00, // iTerminal (none)
- ],
- )?;
-
- writer.interface(
- self.audio_stream,
- USB_INTERFACE_CLASS_AUDIO,
- USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
- USB_AUDIO_PROTOCOL_NONE,
- )?;
-
- //alternate audio stream
- /*writer.interface_alt(
- self.alt_audio_stream,
- 1,
- USB_INTERFACE_CLASS_AUDIO,
- USB_AUDIO_SUBCLASS_AUDIOSTREAMING,
- USB_AUDIO_PROTOCOL_NONE,
- None,
- )?;*/
-
- // Audio Stream Audio Class Descriptor
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_AS_GENERAL, // bDescriptorSubtype
- 0x03, // bTerminalID,
- 0x00, // bDelay
- 0x01,
- 0x00, // wFormatTag (PCM Format)
- ],
- )?;
-
- // Format Type Audio Descriptor
- writer.write(
- CS_INTERFACE,
- &[
- AUDIO_SUB_TYPE_FORMAT_TYPE, // bDescriptorSubtype
- 0x01, // bFormatType (TYPE_I)
- 0x02, // bNrChannels (2)
- 0x02, // bSubFrameSize (2)
- 0x10, // bBitResolution (16 bits)
- 0x01, // bSamFreqType (1 sample frequency)
- 0x80, // 8*2 = 16 KHz byte 0
- 0x3E, // 8*2 = 16 KHz byte 1
- 0x00, // 8*2 = 16 KHz byte 2
- ],
- )?;
-
- // TODO: Set the necessary flags for Isochronous
- writer.endpoint(&self.audio_in_ep)?;
-
- // Isochronous endpoint Audio Class descriptor
- writer.write(
- CS_ENDPOINT,
- &[
- EP_GENERAL, // bDescriptorSubtype
- 0x00, // bmAttributes (none)
- 0x02, // bLockDelayUnits (PCM Samples)
- 0x00, 0x00, // wLockDelay (0) - should be zero for asynchronous
- ],
- )?;
- Ok(())
- }
-
- fn reset(&mut self) {}
-
- fn control_in(&mut self, xfer: ControlIn<B>) {
- let req = xfer.request();
-
- if !(req.request_type == control::RequestType::Class
- && req.recipient == control::Recipient::Interface
- && req.index == u8::from(self.audio_control_if) as u16)
- {
- return;
- }
-
- //defmt::info!("control_in - req : {:?}", req.request);
- match req.request {
- /*
- REQ_GET_LINE_CODING if req.length == 7 => {
- xfer.accept(|data| {
- data[0..4].copy_from_slice(&self.line_coding.data_rate.to_le_bytes());
- data[4] = self.line_coding.stop_bits as u8;
- data[5] = self.line_coding.parity_type as u8;
- data[6] = self.line_coding.data_bits;
-
- Ok(7)
- }).ok();
- },
- */
- _ => {
- xfer.reject().ok();
- }
- }
- }
-
- fn control_out(&mut self, xfer: ControlOut<B>) {
- let req = xfer.request();
-
- if !(req.request_type == control::RequestType::Class
- && req.recipient == control::Recipient::Interface
- && req.index == u8::from(self.audio_control_if) as u16)
- {
- return;
- }
-
- match req.request {
- /*
- REQ_SEND_ENCAPSULATED_COMMAND => {
- // We don't actually support encapsulated commands but pretend we do for standards
- // compatibility.
- xfer.accept().ok();
- },*/
- _ => {
- xfer.reject().ok();
- }
- };
- }
- }*/
|