I'm working on a simple USB audio input device based on the Microchip/Atmel ATSAMD21. The descriptors identify it as a single channel microphone with a single feature unit for volume control. As I understood the feedback endpoint is not mandatory so I have not implemented the feedback/synchronization mechanism yet.
typedef struct ConfigDesc {
USB_ConfigurationDescriptor Config;
USB_InterfaceDescriptor AUDIO_control_interface;
AUDIO_HeaderDescriptor AUDIO_header;
AUDIO_InputTerminalDescriptor AUDIO_input_terminal_descriptor;
AUDIO_FeatureUnit_1CH AUDIO_feature_unit_1;
AUDIO_OutputTerminalDescriptor AUDIO_output_terminal_descriptor;
/*AUDIO_ControlSelectorUnit AUDIO_control_selector_unit;*/
USB_InterfaceDescriptor AUDIO_audio_streaming_interface_1;
USB_InterfaceDescriptor AUDIO_audio_streaming_interface_2;
AUDIO_GeneralDescriptor AUDIO_mic_general;
AUDIO_MicType1Descriptor AUDIO_mic_type1;
USB_ISocEndpointDescriptor AUDIO_mic_endpoint;
AUDIO_IsocDataEndpoint AUDIO_mic_isoc;
} __attribute__((packed)) ConfigDesc;
(Detailed descriptors at the bottom) I have implemented the functions to handle class specific requests (Only the GET/SET requests for the FeatureUnit but after debugging and logging I didn't come across any other class specific requests.) For As soon as the device gets a request to SET_INTERFACE interface-1, alternate interface-1, it starts to transmit a buffer of 64 bytes (32 PCM16 values) continuously. When connected to a Windows 10 PC, the device enumerates as a microphone without any issue (shows up under recording devices) and I was able to record a snippet of audio using the ksstudio. But every attempt to open from any high level application failed. Audacity, for an example gives an error -9999-Unanticipated host error.
__attribute__((__aligned__(4))) const ConfigDesc configuration_descriptor = {
.Config = {
.bLength = sizeof(USB_ConfigurationDescriptor),
.bDescriptorType = USB_DTYPE_Configuration,
.wTotalLength = sizeof(ConfigDesc),
.bNumInterfaces = 2,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = USB_CONFIG_ATTR_BUSPOWERED,
.bMaxPower = USB_CONFIG_POWER_MA(500)
},
.AUDIO_control_interface = {
.bLength = 9,//sizeof(USB_InterfaceDescriptor),
.bDescriptorType = 0x04,//USB_DTYPE_Interface,
.bInterfaceNumber = 0,//INTERFACE_AUDIO_CONTROL,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0x01,//AUDIO_INTERFACE_CLASS, //Audio
.bInterfaceSubClass = 0x01,//AUDIO_INTERFACE_SUBCLASS_CONTROL, //Audio
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.AUDIO_header =
{
.bLength = 9,//sizeof(AUDIO_HeaderDescriptor),
.bDescriptorType = 0x24,//USB_DTYPE_CSInterface,
.bDescriptorSubType = 1, //HEDADER subtype,
.bcdADC = 0x0100,//**
.wTotalLength = 55, //43//Total size of class specific descriptors
.bInCollction = 0x01, //Number of streaming interfaces
.baInterfaceNr = 0x01,//INTERFACE_AUDIO_STREAMING, //AudioStreaming interface 1 belongs tothis AudioControl interface.
},
.AUDIO_input_terminal_descriptor =
{
.bLength = 0x0c, //sizeof(AUDIO_InputTerminalDescriptor),
.bDescriptorType = 0x24, //USB_DTYPE_CSInterface,
.bDescriptorSubType = 0x02,//USB_AUDIO_DType_INPUT_TERMINAL,
.bTerminalID = 0x01,
.wTerminalType = 0x0201, //Microphone
.bAssocTerminal = 0,
.bNrChannels = 1,
.wChannelConfig = 0x0001,
.iChannelNames = 0,
.iTerminal = 0
},
.AUDIO_output_terminal_descriptor =
{
.bLength = 0x09, //sizeof(AUDIO_OutputTerminalDescriptor),
.bDescriptorType = 0x24,//USB_DTYPE_CSInterface,
.bDescriptorSubType = 0x03, //USB_AUDIO_DType_OUTPUT_TERMINAL,
.bTerminalID = 3,
.wTerminalType = 0x0101, //USB Streaming
.bAssocTerminal = 0,
.bSourceID = 2, //input terminal
.iTerminal = 0,
},
/*
.AUDIO_control_selector_unit =
{
.bLength = 0x7,
.bDescriptorType = 0x24,
.bDescriptorSubType = 0x05,
.bUnitID = 0x08,
.bNrInPins = 0x01,
.baSourceID_1 = 0x0A,
.iSelector = 0x00
},
*/
.AUDIO_feature_unit_1 =
{
.bLength = 0x09, //sizeof(AUDIO_FeatureUnit_1CH),
.bDescriptorType = 0x24,//USB_DTYPE_CSInterface,
.bDescriptorSubType = 0x06, //USB_AUDIO_DType_FEATURE_UNIT,
.bUnitID = 0x02,
.bSourceID = 0x01,
.bControlSize = 0x01,
.bmaControlsMaster = 0x02, //supports volume controls
.bmaControls_0 = 0x2,
.iFeature = 0,
},
.AUDIO_audio_streaming_interface_1 =
{
.bLength = 0x09,//sizeof(USB_InterfaceDescriptor),
.bDescriptorType = 0x04,//USB_DTYPE_Interface,
.bInterfaceNumber = 0x01,//INTERFACE_AUDIO_STREAMING,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0x01,//AUDIO_INTERFACE_CLASS,
.bInterfaceSubClass = 0x02,//AUDIO_INTERFACE_SUBCLASS_STREAMING,
.bInterfaceProtocol = 0,
.iInterface = 0
},
.AUDIO_audio_streaming_interface_2 =
{
.bLength = 0x09,//sizeof(USB_InterfaceDescriptor),
.bDescriptorType = 0x04,//USB_DTYPE_Interface,
.bInterfaceNumber = 0x01,//INTERFACE_AUDIO_STREAMING,
.bAlternateSetting = 1,
.bNumEndpoints = 1,
.bInterfaceClass = 0x01,//AUDIO_INTERFACE_CLASS,
.bInterfaceSubClass = 0x02,//AUDIO_INTERFACE_SUBCLASS_STREAMING,
.bInterfaceProtocol = 0,
.iInterface = 0
},
.AUDIO_mic_general =
{
.bLength = 0x07,// sizeof(AUDIO_GeneralDescriptor),
.bDescriptorType = 0x24,//USB_DTYPE_CSInterface,
.bDescriptorSubType = 1,
.bTerminalLink = 0x03,
.bDelay = 1,
.wFormatTag = 0x0001, //PCM
},
.AUDIO_mic_type1 =
{
.bLength = sizeof(AUDIO_MicType1Descriptor),
.bDescriptorType = 0x24,//USB_DTYPE_CSInterface,
.bDescriptorSubType = 0x02, //FORMAT_TYPE subtype
.bFormatType = 0x01, //FORMAT_TYPE_1
.bNrChannels = 1,
.bSubFrameSize = 0x02, //2bytes per audio subframe
.bBitResolution = 16, //16 bits per sample,
.bSamFreqType = 0x01, //1 sampling freq supported
//.tSamFreq1 = {0x40, 0x1f, 0x00}, //8000Hz
.tSamFreq1 = {0x80, 0xbb, 0x00}, //48000Hz
},
.AUDIO_mic_endpoint =
{
.bLength = 0x09, //sizeof(USB_ISocEndpointDescriptor),
.bDescriptorType = 0x05, //USB_DTYPE_Endpoint,
.bEndpointAddress = USB_EP_AUDIO_MIC,
.bmAttributes = 9, //Isochronous, not shared
.wMaxPacketSize = USB_MIC_EP_SIZE,
.bInterval = 1,
.bRefresh = 0,
.bSyncAddress = 0,
},
.AUDIO_mic_isoc =
{
.bLength = 0x07,//sizeof (AUDIO_IsocDataEndpoint),
.bDescriptorType = 0x25,// USB_AUDIO_DType_CS_ENDPOINT,
.bDescriptorSubType = 0x01,
.bmAttributes = 1,
.bLockDelayUnits=0,
.wLockDelay = 0
},
};
Is there any other information I need to provide in the descriptors in order for the high level applications to use this device? Or any requests I might not be handling?
Update: I tried the same device on MacOS, I was able to open the device like a normal microphone on Audacity/Voice recorder and record a snippet of data. It seems like the windows usbaudio.sys behaves differently. Any pointers would be helpful.
Update 2: I made some changes to the device. Made it USB2 compliant, added a CDC class in addition to the Audio and used InterfaceAssociationDescriptors to precede those descriptors. I can't point as to why, but this solved the issue of not being opened from high level applications; I can now open and record from audacity.