uint8_tconst*p_desc;// Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
#if CFG_TUD_AUDIO_EPSIZE_IN
uint8_tep_in;// Outgoing (out of uC) audio data EP.
uint8_tep_in_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
#endif
#if CFG_TUD_AUDIO_EPSIZE_OUT
uint8_tep_out;// Incoming (into uC) audio data EP.
uint8_tep_out_as_intf_num;// Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint8_tep_fb;// Feedback EP.
#endif
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint8_tep_int_ctr;// Audio control interrupt EP.
#endif
#if CFG_TUD_AUDIO_N_AS_INT
uint8_taltSetting[CFG_TUD_AUDIO_N_AS_INT];
#endif
/*------------- From this point, data is not cleared by bus reset -------------*/
// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_USE_TX_FIFO = 0.
// Currently the return value has to effect so far. The return value finally is discarded in tud_task(void) in usbd.c - we just incorporate that for later use
// TODO: Find a way to find end of current audio function and avoid necessity of tud_audio_desc_lengths - since now max_length is available we could do this surely somehow
uint16_tdrv_len=tud_audio_desc_lengths[i]-TUD_AUDIO_DESC_IAD_LEN;// - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor
// 1. Find the audio driver interface which was assigned to the given interface which is to be set
// Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors.
// The audio driver interface is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching
// 2. Close EPs which are currently open
// To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them
// 3. Open new EP
uint8_tconstitf=tu_u16_low(p_request->wIndex);
uint8_tconstalt=tu_u16_low(p_request->wValue);
// Find index of audio streaming interface and index of interface
// Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
if(tu_edpt_dir(ep_addr)==TUSB_DIR_IN&&((tusb_desc_endpoint_tconst*)p_desc)->bmAttributes.usage==0x10)// Check if usage is implicit data feedback
{
_audiod_itf[idxDriver].ep_fb=ep_addr;
}
#endif
#endif
foundEPs+=1;
}
p_desc=tu_desc_next(p_desc);
}
// We are done - abort loop
break;
}
// Increase index, bytes read, and pointer
p_desc=tu_desc_next(p_desc);
}
// Check for nothing found - we can rely on this since EP descriptors are never the last descriptors, there are always also class specific EP descriptors following!
TU_VERIFY(p_desc<p_desc_end);
// Conduct audio driver function specific stuff
// HERE DO WHAT YOU HAVE TO DO - E.G. START ADC OR SO
//#error Implementation specific setInterface code required here!
// Data transmission of control interrupt finished
if(_audiod_itf[idxDriver].ep_int_ctr==ep_addr)
{
// According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
// In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
// In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ???
// There is no data left to send, a ZLP should be sent if
// xferred_bytes is multiple of EP size and not zero
returnusbd_edpt_xfer(rhport,ep_addr,NULL,0);
}
}
#endif
#if CFG_TUD_AUDIO_EPSIZE_IN
// Data transmission of audio packet finished
if(_audiod_itf[idxDriver].ep_in==ep_addr)
{
// USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
// That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
// This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP.
// Check if there is data to load into EPs buffer - if not load it with ZLP
// Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before!
// This is the only place where we can fill something into the EPs buffer!
//// In order that this function works the following is mandatory:
// // - An IAD descriptor is required and has to be placed directly before the Standard AC Interface Descriptor (4.7.1) ALSO if no Audio Streaming interfaces are used!
// // - The Standard AC Interface Descriptor (4.7.1) has to be the first interface listed (required by UAC2 specification)
// // - The alternate interfaces of the Standard AS Interface Descriptor(4.9.1) must be listed in increasing order and alternate 0 must have zero EPs
// // Alternate setting MUST be zero - this check can be omitted
// TU_VERIFY(itf_desc->bAlternateSetting == 0);
//
// // Since checks are successful we get the number of interfaces we have to process by exploiting the fact that an IAD descriptor has to be provided directly before this AC descriptor
// // We do not get this value delivered by the stack so we need to hack a little bit - the number of interfaces to be processed is listed in the IAD descriptor with an offset of exactly 5
// uint8_t nItfs = *(((uint8_t const *) itf_desc) - 5) - 1; // -1 since we already process the (included) AC interface
//
// // Notify caller we have read Standard AC Interface Descriptor (4.7.1)
// (*p_length) = sizeof(tusb_desc_interface_t);
//
// // Go to next descriptor which has to be a Class-Specific AC Interface Header Descriptor(4.7.2) - always present
// // We do not check the Audio Function Category Codes
//
// // We do not check all the following Clock Source, Unit and Terminal descriptors
//
// // We do not check the latency control
//
// // We jump over all the following descriptor to the next following interface (which should be a Standard AS Interface Descriptor(4.9.1) if nItfs > 0)
// (*p_length) += p_desc_cs_ac->wTotalLength; // Notify caller of read bytes
// // From this point on we have nItfs packs of audio streaming interfaces (consisting of multiple descriptors always starting with a Standard AS Interface Descriptor(4.9.1))
//
// uint8_t cnt;
// uint8_t nEPs;
// audio_format_type_t formatType;
// uint8_t intNum;
// uint8_t altInt;
//
// for (cnt = 0; cnt < nItfs; cnt++)
// {
//
// // Here starts an unknown number of alternate interfaces - the art here is to find the end of this interface pack. We do not have the total number of descriptor bytes available (not provided by tinyUSB stack for .open() function) so we try to find the end of this interface pack by deducing it from the order and content of the descriptor pack
// while(1)
// {
// // At first this should be a Standard AS Interface Descriptor(4.9.1) - this check can be omitted
// // It is possible now that the following interface is again a Standard AS Interface Descriptor(4.9.1) (in case the related terminal has more than zero EPs at all and this is the following alternative interface > 0 - the alternative (that this is not a Standard AS Interface Descriptor(4.9.1) but a Class-Specific AS Interface Descriptor(4.9.2)) could be in case the related terminal has no EPs at all e.g. SPDIF connector
// if (tu_desc_type((uint8_t const *) itf_desc) == TUSB_DESC_INTERFACE)
// {
// // It is not possible, that a Standard AS Interface Descriptor(4.9.1) ends without a Class-Specific AS Interface Descriptor(4.9.2)
// // hence the next interface has to be an alternative interface with regard to the one we started above - continue
// continue;
// }
//
// // Second, this interface has to be a Class-Specific AS Interface Descriptor(4.9.2) - this check can be omitted
// // Every Class-Specific AS Interface Descriptor(4.9.2) defines a format type and thus a format type descriptor e.g. Type I Format Type Descriptor(2.3.1.6 - Audio Formats) should follow - only if the format type is undefined no format type descriptor follows
// if (formatType != AUDIO_FORMAT_TYPE_UNDEFINED)
// {
// // We do not need any information from this descriptor - we simply advance
// // Now there might be an encoder/decoder interface - i found no clue if this interface is mandatory (although examples found by google never use this descriptor) or if there is any way to determine if this descriptor is reliably present or not. Problem here: Since we need to find the end of this interface pack and we do not have the total amount of descriptor bytes available here (not given by the tinyUSB stack for the .open() function), we have to make a speculative check if the following is an encoder/decoder interface or not.
// // It could be possible that we ready over the total length of all descriptor bytes here - we simply hope that the combination of descriptor length, type, and sub type does not occur randomly in memory here. The only way to make this check waterproof is to know how many bytes we can read at all but this would be an information we need to be given by tinyUSB!
// // Here we can find information about our EPs address etc. but in the initialization process we do not set anything, we have to wait for the host to send a setInterface request where the EPs etc. are set up according
// // Okay we processed a complete pack - now we have to make a speculative check if the next interface is an alternate interface belonging to the ones processed before - since it is speculative we check a lot to reduce the chances we go wrong and hope for the best