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

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

  • For receiving Audio Control Requests from Host like Volume Control, Mute Control, etc.
  • For handling other events from USB Audio 1.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 1.0 Device Driver callback function
 * USB_DEVICE_AUDIO_EventHandlerSet()
 * is registered in the USB_DEVICE_EVENT_CONFIGURED event.  */

void APP_USBDeviceEventHandler( USB_DEVICE_EVENT event,
                                void * pEventData, uintptr_t context )
{
    switch ( event )
    {
        case USB_DEVICE_EVENT_RESET:
        case USB_DEVICE_EVENT_DECONFIGURED:

            // USB device is reset or device is deconfigured.
            // This means that USB device layer is about to deinitialize
            // all function drivers.

            break;

        case USB_DEVICE_EVENT_CONFIGURED:

            /* check the configuration */
            if ( ((USB_DEVICE_EVENT_DATA_CONFIGURED *)
                  (eventData))->configurationValue == 1)
            {

                USB_DEVICE_AUDIO_EventHandlerSet
                     ( USB_DEVICE_AUDIO_INDEX_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_RESUMED:
        case USB_DEVICE_EVENT_POWER_DETECTED:
        /* VBUS has been detected */
        USB_DEVICE_Attach(appData.usbDeviceHandle);
    break;
        case USB_DEVICE_EVENT_POWER_REMOVED:
        /*VBUS is not available anymore. */
        USB_DEVICE_Detach(appData.usbDeviceHandle);
    break;
        case USB_DEVICE_EVENT_ERROR:
        default:
            break;
    }
}
Event Handling

The Audio 1.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 Control Interface requests
  • Completion of data and the status stages of Audio Control Interface related control transfer

The Audio 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 CDC Function Driver Control Transfer related events and the required application control transfer actions.

Audio 1.0 Function Driver Control Transfer Event 
Required Application Action 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_CUR
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MIN
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MAX
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_RES
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MEM 
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_EVENT_CONTROL_GET_CUR
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MIN
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MAX
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_RES
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MEM 
Identify the control type using the associated event data. Use the USB_DEVICE_ControlSend function to send the expected data. If the request is not supported, use the USB_DEVICE_ControlStatus function to Stall the request. 
USB_DEVICE_AUDIO_EVENT_ENTITY_GET_STAT 
Identify the entity type using the associated event data. Use the USB_DEVICE_ControlSend function to send the expected data. If the request is not supported, use the USB_DEVICE_ControlStatus function to Stall the request. 
USB_DEVICE_AUDIO_CONTROL_TRANSFER_DATA_RECEIVED 
Acknowledge or stall using the USB_DEVICE_ControlStatus function. 
USB_DEVICE_AUDIO_CONTROL_TRANSFER_DATA_SENT 
Action not required. 
USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_UNKNOWN 
Interpret the setup packet and use the Device layer Control transfer functions to complete the transfer. 

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 volume of the Audio device, the following occurs in this order:

  1. The Audio 1.0 Function Driver will generate a USB_DEVICE_AUDIO_EVENT_CONTROL_SET_CUR event.
  2. The application must type cast the event data to a USB_DEVICE_AUDIO_EVENT_DATA_CONTROL_SET_CUR type and check the entityID field.
  3. The entityID field will be identified by the application as a Feature Unit.
  4. The application must now type cast the event data type as a USB_AUDIO_FEATURE_UNIT_CONTROL_REQUEST data type and check the controlSelector field.
  5. If the controlSelector field is a USB_AUDIO_VOLUME_CONTROL, the application can then call the USB_DEVICE_AUDIO_ControlReceive function to receive the new volume settings.

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 1.0 Function Driver Event 
Related Event Data Type 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_CUR 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MIN 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_SET_MIN * 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MAX 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_SET_MAX * 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_RES 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_SET_RES * 
USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MEM 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_SET_MEM * 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_CUR 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_GET_CUR * 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MIN 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_GET_MIN * 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MAX 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_GET_MAX * 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_RES 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_RES 
USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MEM 
USB_DEVICE_AUDIO_EVENT_ DATA_CONTROL_GET_MEM * 
USB_DEVICE_AUDIO_EVENT_ENTITY_GET_STAT 
USB_DEVICE_AUDIO_EVENT_ DATA_ENTITY_GET_STAT * 
USB_DEVICE_AUDIO_CONTROL_TRANSFER_DATA_RECEIVED 
NULL 
USB_DEVICE_AUDIO_CONTROL_TRANSFER_DATA_SENT 
NULL 
USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_UNKNOWN 
USB_SETUP_PACKET * 
USB_DEVICE_AUDIO_EVENT_WRITE_COMPLETE 
USB_DEVICE_AUDIO_EVENT_READ_COMPLETE 
USB_DEVICE_AUDIO_EVENT_ DATA_READ_COMPLETE * 
USB_DEVICE_AUDIO_EVENT_INTERFACE_SETTING_CHANGED 
USB_DEVICE_AUDIO_EVENT_ DATA_INTERFACE_SETTING_CHANGED * 
Handling Audio Control Requests:

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

// This code example shows handling Audio Control requests. The following code
// handles a Mute request (both SET and GET) received from a USB Host.

void APP_USBDeviceAudioEventHandler
(
    USB_DEVICE_AUDIO_INDEX iAudio ,
    USB_DEVICE_AUDIO_EVENT event ,
    void * pData,
    uintptr_t context
)
{
    USB_DEVICE_AUDIO_EVENT_DATA_INTERFACE_SETTING_CHANGED *interfaceInfo;
    USB_DEVICE_AUDIO_EVENT_DATA_READ_COMPLETE *readEventData;
    uint8_t entityID;
    uint8_t controlSelector;
    if ( iAudio == 0 )
    {
        switch (event)
        {
            case USB_DEVICE_AUDIO_EVENT_INTERFACE_SETTING_CHANGED:

                /* We have received a request from USB host to change the
                 * Interface-Alternate setting. The application should be aware
                 * of the association between alternate settings and the device
                 * features to be enabled.*/

                interfaceInfo = (USB_DEVICE_AUDIO_EVENT_DATA_INTERFACE_SETTING_CHANGED *)pData;
                appData.activeInterfaceAlternateSetting = interfaceInfo->interfaceAlternateSetting;
                appData.state = APP_USB_INTERFACE_ALTERNATE_SETTING_RCVD;
                break;

            case USB_DEVICE_AUDIO_EVENT_READ_COMPLETE:
                /* We have received an audio frame from the Host.
                   Now send this audio frame to Audio Codec for Playback. */
                break;

            case USB_DEVICE_AUDIO_EVENT_WRITE_COMPLETE:
                break;

            case USB_DEVICE_AUDIO_EVENT_CONTROL_SET_CUR:

                /* This is an example of handling Audio control request. In this
                 * case the control request is targeted to the Mute Control in
                 * a feature unit entity. This event indicates that the current
                 * value needs to be set. */

                entityID = ((USB_AUDIO_CONTROL_INTERFACE_REQUEST*)pData)->entityID;
                if (entityID == APP_ID_FEATURE_UNIT)
                {
                    controlSelector = ((USB_AUDIO_FEATURE_UNIT_CONTROL_REQUEST*)pData)->controlSelector;
                    if (controlSelector == USB_AUDIO_MUTE_CONTROL)
                    {
                        /* It is confirmed that this request is targeted to the
                         * mute control. We schedule a control transfer receive
                         * to get data from the host. */

                        USB_DEVICE_ControlReceive(appData.usbDevHandle, (void *) &(appData.dacMute), 1 );
                        appData.currentAudioControl = APP_USB_AUDIO_MUTE_CONTROL;
                    }
                }
                break;

            case USB_DEVICE_AUDIO_EVENT_CONTROL_GET_CUR:

                /* This event occurs when the host is requesting a current
                 * status of control */

                entityID = ((USB_AUDIO_CONTROL_INTERFACE_REQUEST*)pData)->entityID;
                if (entityID == APP_ID_FEATURE_UNIT)
                {
                    controlSelector = ((USB_AUDIO_FEATURE_UNIT_CONTROL_REQUEST*)pData)->controlSelector;
                    if (controlSelector == USB_AUDIO_MUTE_CONTROL)
                    {
                        /* Use the control send function to send the status of
                         * the control to the host */
                        USB_DEVICE_ControlSend(appData.usbDevHandle, (void *)&(appData.dacMute), 1 );
                    }
                }
                break;

            case USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MIN:
            case USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MIN:
            case USB_DEVICE_AUDIO_EVENT_CONTROL_SET_MAX:
            case USB_DEVICE_AUDIO_EVENT_CONTROL_GET_MAX:
            case USB_DEVICE_AUDIO_EVENT_CONTROL_SET_RES:
            case USB_DEVICE_AUDIO_EVENT_CONTROL_GET_RES:
            case USB_DEVICE_AUDIO_EVENT_ENTITY_GET_MEM:

                /* In this example, all of these control requests are not
                 * supported. So these are stalled. */
                USB_DEVICE_ControlStatus (appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_ERROR);
                break;

            case USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

                /* This event occurs when data has been received in a control
                 * transfer */

                USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK );
                if (appData.currentAudioControl == APP_USB_AUDIO_MUTE_CONTROL)
                {
                    appData.state = APP_MUTE_AUDIO_PLAYBACK;
                    appData.currentAudioControl = APP_USB_CONTROL_NONE;
                }
                break;

            case  USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_DATA_SENT:
                break;
            default:
                break;
        }
    }
}