nRF5 SDK v13.0.0
USB audio class module
This information applies to the nRF52840 SoC only.

This module allows to create and handle USB audio class instances. For detailed information on the USB audio class, refer to these specification documents:

Defining audio class descriptors

A typical audio class has one control interface and one streaming interface. Before you can declare a class instance, you must first properly define the audio class descriptors. These must be defined as a raw uint8_t array.

Example 1: Layout of headphone descriptors in a raw array:

AUDIO_CONTROL_INTERFACE
AUDIO_CONTROL_HEADER
INPUT_TERMINAL
FEATURE_UNIT
OUTPUT_TERMINAL
AUDIO_STREAMING_INTERFACE_ALTERNATE0
AUDIO_STREAMING_INTERFACE_ALTERNATE1
AS_FORMAT_III
EP_GENERAL
ISO_EP_OUT

Example 2: Layout of microphone descriptors in a raw array:

AUDIO_CONTROL_INTERFACE
AUDIO_CONTROL_HEADER
INPUT_TERMINAL
FEATURE_UNIT
OUTPUT_TERMINAL
AUDIO_STREAMING_INTERFACE_ALTERNATE0
AUDIO_STREAMING_INTERFACE_ALTERNATE1
AS_FORMAT_III
EP_GENERAL
ISO_EP_IN

The difference between headphones and microphone descriptors is in the direction of the isochronous endpoint descriptor. Microphone has the IN direction defined (from the USB device to the host). For headphones, the isochronous endpoint direction is set to OUT (from the host to the USB device). Both of these classes have two audio streaming descriptors:

Example: Raw uint8_t descriptors for an audio class (Headphones: 2 channels, Fs = 48KHz, Format 16bit PCM):

static const uint8_t m_hp_audio_class_descriptors[] = {
/* Audio control interface descriptor: 0
+ descriptors defined by AUDIO_CONTROL_DSC_LIST */
APP_USBD_AUDIO_CONTROL_DSC(0, HP_AUDIO_CONTROL_DSC_LIST(), (1))
/* Audio streaming interface descriptor: 1, setting: 0 */
/* Audio streaming interface descriptor: 1, setting: 1 */
/* Audio class-specific interface descriptor */
/* Audio class-specific format I descriptor */
/* Audio class-specific endpoint general descriptor */
/* Standard ISO endpoint descriptor */
};

Defining audio classes

When all descriptors are correctly defined, you can define the audio class:

#define HP_INTERFACES_CONFIG() APP_USBD_AUDIO_CONFIG_OUT(0, 1)
APP_USBD_AUDIO_GLOBAL_DEF(m_app_audio_headphone,
HP_INTERFACES_CONFIG(),
hp_audio_user_ev_handler,
m_hp_audio_class_descriptors
);

You can pass an event handler function to the class instance definition. The following is an example of a correct audio class user event handler prototype:

void audio_user_ev_handler(app_usbd_class_inst_t const * p_inst,

Registering an audio class to the USBD library

After the function is defined, you must register the new class to the USBD library:

ret = app_usbd_init();
ASSERT(ret == NRF_SUCCESS);
app_usbd_class_inst_t const * class_inst_hp = app_usbd_audio_class_inst_get(&m_app_audio_headphone);
ret = app_usbd_controller_class_append(class_inst_hp);
ASSERT(ret == NRF_SUCCESS);

Events defined by app_usbd_audio_user_event_t are passed to the user event handler. Requests defined for the audio class trigger the APP_USBD_AUDIO_USER_EVT_CLASS_REQ event. Access to the class request data is obtained by the app_usbd_audio_class_request_get function. Isochronous transfers trigger two types of events:

The library client must set up buffers for isochronous transfers:

Size of these transfer buffers must be the same as the endpoint size defined in raw descriptors. Example: After registering the headphones example presented above, the following buffer is set up:

static int16_t m_rx_buffer[2 * 48];
...
app_usbd_audio_class_rx_buf_set(p_inst, m_rx_buffer, sizeof(m_rx_buffer));

Isochronous transfer buffer can be safely switched (or modified) only on the APP_USBD_AUDIO_USER_EVT_RX_DONE or APP_USBD_AUDIO_USER_EVT_RX_DONE events. Every isochronous transfer is synchronized with the Start of Frame event (SOF) and it is fired automatically when the transfer buffer is configured.


Documentation feedback | Developer Zone | Subscribe | Updated