A2DP

This manual describes the Advanced Audio Distribution Profile API definition. A2DP defines the protocols and procedures that realize distribution of audio content of high-quality in mono or stereo on ACL channels.

Terminology and Concepts

A2DP Roles

The following roles are defined for devices that implement this profile:

  • SOURCE (SRC) - A device is the SRC when it acts as a source of a digital audio stream that is delivered to the SNK of the piconet.

  • SINK (SNK) - A device is the SNK when it acts as a sink of a digital audio stream delivered from the SRC on the same piconet.

A2DP SDP Record

A2DP local record a2dp_sdp_record should be registered by bt_sdp_record_add().

static const uint8_t a2dp_sdp_record[] =
{
    SDP_DATA_ELEM_SEQ_HDR,
    0x39,//0x55,
    //attribute SDP_ATTR_SRV_CLASS_ID_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_SRV_CLASS_ID_LIST >> 8),
    (uint8_t)SDP_ATTR_SRV_CLASS_ID_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_AUDIO_SINK >> 8),
    (uint8_t)(UUID_AUDIO_SINK),

    //attribute SDP_ATTR_PROTO_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROTO_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROTO_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x10,
    SDP_DATA_ELEM_SEQ_HDR,
    0x06,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_L2CAP >> 8),
    (uint8_t)(UUID_L2CAP),
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(PSM_AVDTP >> 8),
    (uint8_t)(PSM_AVDTP),
    SDP_DATA_ELEM_SEQ_HDR,
    0x06,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_AVDTP >> 8),
    (uint8_t)(UUID_AVDTP),
    SDP_UNSIGNED_TWO_BYTE,
    0x01,
    0x03,

    //attribute SDP_ATTR_BROWSE_GROUP_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_BROWSE_GROUP_LIST >> 8),
    (uint8_t)SDP_ATTR_BROWSE_GROUP_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x03,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_PUBLIC_BROWSE_GROUP >> 8),
    (uint8_t)(UUID_PUBLIC_BROWSE_GROUP),
    /*
        //attribute SDP_ATTR_LANG_BASE_ATTR_ID_LIST
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_ATTR_LANG_BASE_ATTR_ID_LIST >> 8),
        (uint8_t)SDP_ATTR_LANG_BASE_ATTR_ID_LIST,
        SDP_DATA_ELEM_SEQ_HDR,
        0x09,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_LANG_ENGLISH >> 8),
        (uint8_t)SDP_LANG_ENGLISH,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_CHARACTER_UTF8 >> 8),
        (uint8_t)SDP_CHARACTER_UTF8,
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)(SDP_BASE_LANG_OFFSET >> 8),
        (uint8_t)SDP_BASE_LANG_OFFSET,
    */
    //attribute SDP_ATTR_PROFILE_DESC_LIST
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_PROFILE_DESC_LIST >> 8),
    (uint8_t)SDP_ATTR_PROFILE_DESC_LIST,
    SDP_DATA_ELEM_SEQ_HDR,
    0x08,
    SDP_DATA_ELEM_SEQ_HDR,
    0x06,
    SDP_UUID16_HDR,
    (uint8_t)(UUID_ADVANCED_AUDIO_DISTRIBUTION >> 8),
    (uint8_t)(UUID_ADVANCED_AUDIO_DISTRIBUTION),
    SDP_UNSIGNED_TWO_BYTE,
    0x01,//version 1.4
    0x04,

    //attribute SDP_ATTR_SUPPORTED_FEATURES
    SDP_UNSIGNED_TWO_BYTE,
    (uint8_t)(SDP_ATTR_SUPPORTED_FEATURES >> 8),
    (uint8_t)SDP_ATTR_SUPPORTED_FEATURES,
    SDP_UNSIGNED_TWO_BYTE,
    0x00,
    0x03
    /*
        //attribute SDP_ATTR_SRV_NAME
        SDP_UNSIGNED_TWO_BYTE,
        (uint8_t)((SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET) >> 8),
        (uint8_t)(SDP_ATTR_SRV_NAME + SDP_BASE_LANG_OFFSET),
        SDP_STRING_HDR,
        0x09,
        0x61, 0x32, 0x64, 0x70, 0x5f, 0x73, 0x69, 0x6e, 0x6b //a2dp_sink
    */
};

Feature Set

The functions provided by A2DP APIs are as below.

  1. Connecting and Disconnecting: Including functions to connect/disconnect A2DP.

  2. Streaming: Including functions to send stream data, etc.

Provided APIs

This figure shows the relationship between applications and A2DP and Bluetooth Host. Above the horizon line is developed by the applications. Below the horizon line is developed by Realtek.

../../../../../_images/bt_a2dp_struct.png

A2DP Struct

The table below shows a simple description of A2DP APIs. A2DP related APIs are provided in the sdk\inc\framework\bt\bt_a2dp.h.

A2DP API

Header File

Description

API Reference

bt_a2dp.h

Connect A2DP, send stream data etc.

Bluetooth A2DP Profile

Functions

A2DP Init

A2DP initialization procedure involves profile initialization and stream endpoint registration.

Initialize A2DP profile, and configure the maximum number of remote devices and A2DP latency. A2DP latency is used to enable.
Add A2DP stream end point. An A/V stream on a Bluetooth link is sent or received by Bluetooth devices via an abstract stream end point. A device can discover the SEPs of the remote device by the stream end point discovery procedure, which is done by framework. The application registers its SEPs in order to allow other devices to discover and connect to them. The SEP with sbc codec shall always be registered.
Delete A2DP stream end point. Stream end point must be deleted when all A2DP profile links were disconnected.
void app_a2dp_init(void)
{
    if (app_cfg_const.supported_profile_mask & A2DP_PROFILE_MASK)
    {
        bt_sdp_record_add((void *)a2dp_sdp_record);

        bt_a2dp_init(app_cfg_const.a2dp_link_number, A2DP_LATENCY_MS);
        if (app_cfg_const.a2dp_codec_type_sbc)
        {
            T_BT_A2DP_STREAM_END_POINT sep;

            sep.codec_type = BT_A2DP_CODEC_TYPE_SBC;
            sep.u.codec_sbc.sampling_frequency_mask = app_cfg_const.sbc_sampling_frequency;
            sep.u.codec_sbc.channel_mode_mask = app_cfg_const.sbc_channel_mode;
            sep.u.codec_sbc.block_length_mask = app_cfg_const.sbc_block_length;
            sep.u.codec_sbc.subbands_mask = app_cfg_const.sbc_subbands;
            sep.u.codec_sbc.allocation_method_mask = app_cfg_const.sbc_allocation_method;
            sep.u.codec_sbc.min_bitpool = app_cfg_const.sbc_min_bitpool;
            sep.u.codec_sbc.max_bitpool = app_cfg_const.sbc_max_bitpool;
            bt_a2dp_stream_endpoint_add(sep);
        }

        if (app_cfg_const.a2dp_codec_type_aac)
        {
            T_BT_A2DP_STREAM_END_POINT sep;

            sep.codec_type = BT_A2DP_CODEC_TYPE_AAC;
            sep.u.codec_aac.object_type_mask = app_cfg_const.aac_object_type;
            sep.u.codec_aac.sampling_frequency_mask = app_cfg_const.aac_sampling_frequency;
            sep.u.codec_aac.channel_number_mask = app_cfg_const.aac_channel_number;
            sep.u.codec_aac.vbr_supported = app_cfg_const.aac_vbr_supported;
            sep.u.codec_aac.bit_rate = app_cfg_const.aac_bit_rate;
            bt_a2dp_stream_endpoint_add(sep);
        }

        bt_mgr_cback_register(app_a2dp_bt_cback);
    }
}

A2DP Connect

Initiate an A2DP connection to a remote device, as shown below.
../../../../../_images/A2DP_connect_request.png

A2DP Connect Request

Request an A2DP disconnection, as shown below.
../../../../../_images/A2DP_disconnect_request.png

A2DP Disconnect Request

Accept or reject the incoming connection from the remote device, as shown below.
../../../../../_images/A2DP_connect_confirm.png

A2DP Connect Confirm

static void app_a2dp_bt_cback(T_BT_EVENT event_type, void *event_buf, uint16_t buf_len)
{
    T_BT_EVENT_PARAM *param = event_buf;
    T_APP_BR_LINK *p_link;

    switch (event_type)
    {
    case BT_EVENT_A2DP_CONN_IND:
        {
            p_link = app_find_br_link(param->bt_a2dp_conn_ind.bd_addr);
            if (p_link != NULL)
            {
                bt_a2dp_connect_cfm(p_link->bd_addr, true);
            }
        }
        break;

    case BT_EVENT_A2DP_CONN_CMPL:
        break;

    case BT_EVENT_A2DP_CONN_FAIL:
        /*If both devices initiate a connection at the same time, both channels shall be closed and BT_EVENT_A2DP_CONN_FAIL will be received.
          Each device shall wait a random time (not more than 1s and not less than 100ms) and then try to initiate the A2DP connection again. */
        break;

    case BT_EVENT_A2DP_CONFIG_CMPL:
        {
            p_link = app_find_br_link(param->bt_a2dp_config_cmpl.bd_addr);
            if (p_link != NULL)
            {
                T_BT_EVENT_PARAM_A2DP_CONFIG_CMPL *cfg = &param->bt_a2dp_config_cmpl;
                p_link->a2dp_codec_type = param->bt_a2dp_config_cmpl.codec_type;

                if (p_link->a2dp_codec_type == BT_A2DP_CODEC_TYPE_SBC)
                {
                    p_link->a2dp_codec_info.sbc.sampling_frequency = cfg->codec_info.sbc.sampling_frequency;
                    p_link->a2dp_codec_info.sbc.channel_mode = cfg->codec_info.sbc.channel_mode;
                    p_link->a2dp_codec_info.sbc.block_length = cfg->codec_info.sbc.block_length;
                    p_link->a2dp_codec_info.sbc.subbands = cfg->codec_info.sbc.subbands;
                    p_link->a2dp_codec_info.sbc.allocation_method = cfg->codec_info.sbc.allocation_method;
                    p_link->a2dp_codec_info.sbc.min_bitpool = cfg->codec_info.sbc.min_bitpool;
                    p_link->a2dp_codec_info.sbc.max_bitpool = cfg->codec_info.sbc.max_bitpool;
                }
                else if (p_link->a2dp_codec_type == BT_A2DP_CODEC_TYPE_AAC)
                {
                    p_link->a2dp_codec_info.aac.object_type = cfg->codec_info.aac.object_type;
                    p_link->a2dp_codec_info.aac.sampling_frequency = cfg->codec_info.aac.sampling_frequency;
                    p_link->a2dp_codec_info.aac.channel_number = cfg->codec_info.aac.channel_number;
                    p_link->a2dp_codec_info.aac.vbr_supported = cfg->codec_info.aac.vbr_supported;
                    p_link->a2dp_codec_info.aac.allocation_method = cfg->codec_info.aac.allocation_method;
                    p_link->a2dp_codec_info.aac.bit_rate = cfg->codec_info.aac.bit_rate;
                }
                else
                {
                    memcpy(p_link->a2dp_codec_info.vendor.info, cfg->codec_info.vendor.info, 12);
                }
            }
        }
        break;

    case BT_EVENT_A2DP_DISCONN_CMPL:
        break;
    }
}

A2DP Streaming

Connect a streaming channel to the remote device, as shown below.
../../../../../_images/A2DP_stream_open_request.png

A2DP Stream Open Request

Request to start streaming audio data over a streaming channel, as shown below.

Note

  • bt_avrcp_play() is recommended to start music.

../../../../../_images/A2DP_stream_start_request.png

A2DP Stream Start Request

Accept or reject the incoming start streaming request from a remote device, as shown below.
../../../../../_images/A2DP_stream_start_confirm.png

A2DP Stream Start Confirm

Request to close a streaming channel, as shown below.
../../../../../_images/A2DP_stream_close_request.png

A2DP Stream Close Request

Request to cease the streaming of audio data over a streaming channel, as shown below.

Note

  • bt_avrcp_pause() is recommended to stop music.

../../../../../_images/A2DP_stream_susupend_request.png

A2DP Stream Susupend Request

Request to abort the streaming channel.
Request to set A2DP stream latency. This enables synchronous playback of audio and video.
Set an active A2DP stream link for A2DP multi-link.
Send A2DP stream data when role is Source.
static void app_a2dp_src_send_data(void)
{
    //get media data

    if (a2dp_credits > 0)
    {
        if (bt_a2dp_stream_data_send(a2dp_sink_addr, frame_num, p_data, length))
        {
            a2dp_credits--;
        }
        else
        {
            APP_PRINT_ERROR0("app_a2dp_src_send_data: send a2dp media pkt failed");
        }
    }
}

Sample Projects

SDK provides a corresponding demo application for developers’ reference in development. The BR/EDR Audio gives a simple example on how to use A2DP.