USB Libraries Help > USB Device Libraries > USB Audio 2.0 Device Library > How the Library Works > Event Handling
MPLAB Harmony USB Stack
Event Handling
Registering a Audio 2.0 Function Driver Callback Function

While creating a USB Audio 2.0 Device application, an event handler must be registered with the Device Layer (the Device Layer Event Handler) and every Audio 2.0 Function Driver instance (Audio 2.0 Function Driver Event Handler). The application needs to register the event handler with the Audio 2.0 Function Driver:

  • For receiving Audio 2.0 Control Requests from Host like Volume Control, Mute Control, etc.
  • For handling other events from USB Audio 2.0 Device Driver (e.g., Data Write Complete or Data Read Complete)

The event handler should be registered before the USB device layer_acknowledges the SET CONFIGURATION request from the USB Host. To ensure this, the callback function should be set in the USB_DEVICE_EVENT_CONFIGURED event that is generated by the device_layer. The following code example shows how this can be done.

/* This a sample Application Device Layer Event Handler
 * Note how the USB Audio 2.0 Device Driver callback function
 * USB_DEVICE_AUDIO_2_0_EventHandlerSet()
 * is registered in the USB_DEVICE_EVENT_CONFIGURED event.  */

void APP_UsbDeviceEventCallBack( USB_DEVICE_EVENT event, void * pEventData, uintptr_t context )
{
    uint8_t * configuredEventData;
    switch( event )
    {
        case USB_DEVICE_EVENT_RESET:
            break;
        case USB_DEVICE_EVENT_DECONFIGURED:
            // USB device is reset or device is de-configured.
            // This means that USB device layer is about to de-initialize
            // all function drivers. So close handles to previously opened
            // function drivers.
            break;

        case USB_DEVICE_EVENT_CONFIGURED:
            /* check the configuration */
             /* Initialize the Application */
            configuredEventData = pEventData;
            if(*configuredEventData == 1)
            {
                USB_DEVICE_AUDIO_V2_EventHandlerSet
                (
                    0,
                    APP_USBDeviceAudioEventHandler ,
                    (uintptr_t)NULL
                );
                /* mark that set configuration is complete */
                appData.isConfigured = true;
            }
            break;

        case USB_DEVICE_EVENT_SUSPENDED:
            break;

        case USB_DEVICE_EVENT_POWER_DETECTED:
            /* Attach the device */
            USB_DEVICE_Attach (appData.usbDevHandle);
            break;

        case USB_DEVICE_EVENT_POWER_REMOVED:
                /* VBUS is not available. We can detach the device */
                USB_DEVICE_Detach(appData.usbDevHandle);
                break;

        case USB_DEVICE_EVENT_RESUMED:
        case USB_DEVICE_EVENT_ERROR:
        default:
            break;
    }
}
Event Handling

The Audio 2.0 Function Driver provides events to the application through the event handler function registered by the application. These events indicate:

  • Completion of a read or a write data transfer
  • Audio 2.0 Control Interface requests
  • Completion of data and the status stages of Audio 2.0 Control Interface related control transfer

The Audio 2.0 Control Interface Request events and the related control transfer events typically require the application to respond with the Device Layer Control Transfer routines to complete the control transfer. Based on the generated event, the application may be required to:

The following table shows the Audio 2.0 Function Driver Control Transfer related events and the required application control transfer actions.

Audio 2.0 Function Driver Control Transfer Event 
Required Application Action 
USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED 
Identify the control type using the associated event data. If a data stage is expected, use the USB_DEVICE_ControlReceive function to receive expected data. If a data stage is not required or if the request is not supported, use the USB_DEVICE_ControlStatus function to Acknowledge or Stall the request. 
USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS
_RECEIVED 
Identify the control type using the associated event data. If a data stage is expected, use the USB_DEVICE_ControlReceive function to receive expected data. If a data stage is not required or if the request is not supported, use the USB_DEVICE_ControlStatus function to Acknowledge or Stall the request. 
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER
_DATA_RECEIVED 
Acknowledge or stall using the USB_DEVICE_ControlStatus function. 
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER
_DATA_SENT 
Action not required. 

The application must analyze the wIndex field of the event data (received with the control transfer event) to identify the entity that is being addressed. The application must be aware of all entities included in the application and their IDs. Once identified, the application can then type cast the event data to entity type the specific control request type. For example, if the Host sends a control request to set the clock source for the Audio 2.0 device, the following occurs in this order:

  1. The Audio 2.0 Function Driver will generate a USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED event.
  2. The application must type cast the event data to a USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST type and check the entityID field.
  3. The entityID field will be identified by the application as a Clock Source.
  4. The application must now type cast the event data type as a USB_AUDIO_V2_CLOCKSOURCE_CONTROL_REQUEST data type and check the controlSelector field.
  5. If the controlSelector field is AUDIO_V2_CS_SAM_FREQ_CONTROL, the application can then call the USB_DEVICE_ControlReceive function to receive the clock source.

Based on the type of event, the application should analyze the event data parameter of the event handler. This data member should be type cast to an event specific data type. The following table shows the event and the data type to use while type casting. Note that the event data member is not required for all events.

Audio 2.0 Function Driver Event 
Related Event Data Type 
USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED 
USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* 
USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS
_RECEIVED
 
USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* 
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER
_DATA_RECEIVED 
NULL 
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER
_DATA_SENT 
NULL 
USB_DEVICE_AUDIO_V2_EVENT_INTERFACE_SETTING_CHANGED 
USB_DEVICE_AUDIO_V2_EVENT_READ_COMPLETE 
USB_DEVICE_AUDIO_V2_EVENT_WRITE_COMPLETE 
Handling Audio Control Requests:

When the Audio 2.0 Function Driver receives an Audio 2.0 Class Specific Control Transfer Request, it passes this control transfer to the application as a Audio 2.0 Function Driverevent. The following code example shows how to handle an Audio 2.0 Control request.

void APP_USBDeviceAudioEventHandler
(
    USB_DEVICE_AUDIO_V2_INDEX iAudio ,
    USB_DEVICE_AUDIO_V2_EVENT event ,
    void * pData,
    uintptr_t context
)
{
    USB_DEVICE_AUDIO_V2_EVENT_DATA_SET_ALTERNATE_INTERFACE * interfaceInfo;
    USB_DEVICE_AUDIO_V2_EVENT_DATA_READ_COMPLETE * readEventData;
    USB_DEVICE_AUDIO_V2_EVENT_DATA_WRITE_COMPLETE * writeEventData;
   USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* controlRequest;
    if ( iAudio == 0 )
    {
        switch (event)
        {
            case USB_DEVICE_AUDIO_V2_EVENT_READ_COMPLETE:
                readEventData = (USB_DEVICE_AUDIO_V2_EVENT_DATA_READ_COMPLETE *)pData;
                //We have received an audio frame from the Host.
                //Now send this audio frame to Audio Codec for Playback.

            break;

            case USB_DEVICE_AUDIO_V2_EVENT_WRITE_COMPLETE:

            break;

            case USB_DEVICE_AUDIO_V2_EVENT_INTERFACE_SETTING_CHANGED:
                //We have received a request from USB host to change the Interface-
                //Alternate setting.
                interfaceInfo = (USB_DEVICE_AUDIO_V2_EVENT_DATA_SET_ALTERNATE_INTERFACE *)pData;
                appData.activeInterfaceAlternateSetting = interfaceInfo->interfaceAlternateSetting;
                appData.state = APP_USB_INTERFACE_ALTERNATE_SETTING_RCVD;

            break;
            case USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED:
                controlRequest = (USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST*) setupPkt;
    USB_AUDIO_V2_CLOCKSOURCE_CONTROL_REQUEST* clockSourceRequest;

        switch(controlRequest->entityID)
        {
       case APP_ID_CLOCK_SOURCE:
          clockSourceRequest = (USB_AUDIO_V2_CLOCKSOURCE_CONTROL_REQUEST*) controlRequest;
                     switch(clockSourceRequest->controlSelector)
                    {
                          case AUDIO_V2_CS_SAM_FREQ_CONTROL:
                         {
                        if ((controlRequest->bmRequestType & 0x80) == 0)
                        {
                            //A control write transfer received from Host. Now receive data from Host.
                           USB_DEVICE_ControlReceive(appData.usbDevHandle, (void *) &(appData.clockSource), 4 );
                           appData.currentAudioControl = APP_USB_AUDIO_CLOCKSOURCE_CONTROL;
                                   }
                              else
                              {
                        /*Handle Get request*/
                        USB_DEVICE_ControlSend(appData.usbDevHandle, (void *)&(appData.clockSource), 4 );
                        appData.currentAudioControl = APP_USB_CONTROL_NONE;
                                }
                       }

}
                break;

            case USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS_RECEIVED:

                break;

            case USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:
                USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK );
                switch (appData.currentAudioControl)
                {
                    case APP_USB_AUDIO_MUTE_CONTROL:
                    {
                        appData.state = APP_MUTE_AUDIO_PLAYBACK;
                        appData.currentAudioControl = APP_USB_CONTROL_NONE;
                    }
                    break;
                    case APP_USB_AUDIO_CLOCKSOURCE_CONTROL:
                    {
                        // Handle Clock Source Control here.
                        appData.state = APP_CLOCKSOURCE_SET;
                        appData.currentAudioControl = APP_USB_CONTROL_NONE;
                    }
                    break;
                    case APP_USB_AUDIO_CLOCKSELECT_CONTROL:
                    {
                        // Handle Clock Source Control here.
                        appData.currentAudioControl = APP_USB_CONTROL_NONE;

                    }
                    break;
                }
            break;
            case  USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER_DATA_SENT:
            break;
            default:
                SYS_ASSERT ( false , "Invalid callback" );
            break;
        } //end of switch ( callback )
    }//end of if  if ( iAudio == 0 )
}//end of function APP_AudioEventCallback