LE Audio CAP Initiator

The purpose of this document is to give an overview of the LE audio CAP initiator sample. The LE audio CAP initiator sample implements a very simple LE audio CAP initiator device and it can be used as a framework to develop many different CAP initiator-role applications.

../../../_images/ini_architecture.png

The sample uses LE host, LE manager, and LE audio module. The above figure shows the relationships between several modules in the sample.

More information about these modules can be found in the LE Host, LE Manager and LE Audio Manager documentation.

Requirements

The sample supports the following development kits:

Development Kits

Hardware Platforms

Board Name

Build Target

RTL87x3E HDK

RTL87x3E EVB

lea_cap_initiator_4M_bank0

lea_cap_initiator_16M_bank0

RTL87x3EP HDK

RTL87x3EP EVB

lea_cap_initiator_4M_bank0

lea_cap_initiator_16M_bank0

RTL87x3D HDK

RTL87x3D EVB

lea_cap_initiator_8M_bank0

lea_cap_initiator_16M_bank0

lea_cap_initiator_cs_16M_bank0

This sample project can be found under board\evb\lea_cap_initiator in SDK folder structure. Developers can choose the project according to the Board Name and choose the Build Target according to the flash map.

When built for an xxx_4M_xxx build target, the sample is configured to build and run with a 4M flash map.

When built for an xxx_8M_xxx build target, the sample is configured to build and run with an 8M flash map.

When built for a xxx_16M_xxx build target, the sample is configured to build and run with a 16M flash map.

For more requirements, please refer to Quick Start.

Wiring

The sample requires support for user command interface. For specific wiring instructions, please refer to Data UART Connection in User Command Interface.

Configurations

The configurations for the sample include Configurable Items and Generating System Config File.

Configurable Items

The sample’s configurable functions are defined in src\sample\lea_samples\lea_cap_initiator\app_lea_cap_ini_flags.h:

  • LE link number

    The LE link number is configured by the macro definition APP_MAX_BLE_LINK_NUM.

    /**
     * @brief Config APP LE link number
     *
     */
    #define APP_MAX_BLE_LINK_NUM 2
    
  • Input audio data test

    If the macro definition APP_LEA_INPUT_AUDIO_DATA_TEST is enabled, the sample will test the ISO data send procedure.

    #define APP_LEA_INPUT_AUDIO_DATA_TEST 1 /**< Input (Host to Controller).*/
    
  • EATT support

    EATT is configured by the macro definition APP_LEA_EATT_SUPPORT. If the macro APP_LEA_EATT_SUPPORT is enabled, the sample will support EATT.

    /** @brief  Config EATT: 0-Disable EATT, 1-Enable EATT */
    #define APP_LEA_EATT_SUPPORT 0
    
  • GATT client service table storage

    The macro definition GATTC_TBL_STORAGE_SUPPORT is used to configure the sample to support GATT discovery result storage.

    • 0 - Do not store GATT discovery result.

    • 1 - Store GATT discovery result to FTL.

    #define GATTC_TBL_STORAGE_SUPPORT 1
    
  • CAP role

    Define the CAP role that the sample will support.

    #define CAP_ROLE      (CAP_COMMANDER_ROLE|CAP_INITIATOR_ROLE)
    
  • CAP role component

    //CAP role component
    #define BAP_UNICAST_CLIENT       1
    #define BAP_UNICAST_SERVER       0
    #define BAP_BROADCAST_SOURCE     1
    #define BAP_BROADCAST_SINK       0
    #define BAP_BROADCAST_ASSISTANT  1
    #define BAP_SCAN_DELEGATOR       0
    #define VCP_VOLUME_CONTROLLER    1
    #define VCP_VOLUME_RENDERER      0
    #define MICP_MIC_CONTROLLER      1
    #define MICP_MIC_DEVICE          0
    #define CCP_CALL_CONTROL_SERVER  1
    #define CCP_CALL_CONTROL_CLIENT  0
    #define MCP_MEDIA_CONTROL_SERVER 1
    #define MCP_MEDIA_CONTROL_CLIENT 0
    #define CSIP_SET_COORDINATOR     1
    #define CSIP_SET_MEMBER          0
    

Generating System Config File

Developers shall configure the following items through MCUConfig Tool:

MCUConfig Tool Configuration

Configurable Item

Value

LE Link Number

APP_MAX_BLE_LINK_NUM

LE Master Link Num

APP_MAX_BLE_LINK_NUM

CCCD Count

64

CCCD Per Link Count

32

LE Bond Device number

APP_MAX_BLE_LINK_NUM

Support LE Isochronous

Enable

LE CIG number

2

LE CIS number

4

LE BIG number

2

LE BIS number

4

Support LE PA

Enable

LE PA number

2

For more information about MCUConfig Tool Configuration, please refer to MCUConfig Tool.

Building and Downloading

Take the project rtl87x3e_lea_cap_initiator.uvprojx and target lea_cap_initiator_4M_bank0 as an example, to build and run the sample with the Keil development environment, follow the steps listed below:

  1. Open rtl87x3e_lea_cap_initiator.uvprojx.

  2. Choose the build target lea_cap_initiator_4M_bank0.

    ../../../_images/chose_build_target6.png
  3. Build the target.

    ../../../_images/building6.png

    After a successful compilation, the sample bin file lea_cap_initiator_bank0_MP-v0.0.0.0-xxx.bin will be generated in the directory bin\rtl87x3e\flash_4M_dualbank\bank0.

  4. Download the sample bin into the EVB board.

  5. Press the reset button on the EVB board and it will start running.

Experimental Verification

After downloading the sample bin to the EVB board, developers can test it either by using another kit that is running the LE Audio CAP Acceptor sample.

Testing with Another Kit

Prepare two development boards named DUT and Tester respectively, and use Debug Analyzer tool to get the logs. For more information, please refer to Debug Analyzer.

Preparation Phase

  1. Use MCUConfig Tool to set DUT address to [00:11:22:33:44:80], and then build the LE audio CAP initiator sample, and download images into DUT. Developers can enter the user command in the serial port assistant tool in PC. Please refer to How to Use Commands in User Command Interface.

  2. Use MCUConfig Tool to set Tester address to [00:11:22:33:44:85], and then build the LE audio CAP acceptor sample, and download images into Tester. Developers can enter the user command in the serial port assistant tool in PC. Please refer to How to Use Commands in User Command Interface.

    For more information, please refer to the chapter Building and Downloading in LE Audio CAP Acceptor.

For details about how to change the Bluetooth Address, please refer to MCUConfig Tool.

Testing Phase

  1. Press the reset button on DUT and developers can enter the user commands in serial port assistant tool on PC.

    If the DUT successfully boots up and the serial port assistant tool configuration is successful, the log will be shown as below. The serial port assistant tool will display the local address. If developers don’t see the following log, please check if the software and hardware environment is configured correctly.

    >> Command Parse Init (CAP Initiator) <<
    local bd addr: 0xXX:XX:XX:XX:XX:XX
    
  2. Press the reset button on Tester and developers can enter the user commands in serial port assistant tool on PC.

    If the Tester successfully boots up and the serial port assistant tool configuration is successful, the log will be shown as below. The serial port assistant tool will display the local address. If developers don’t see the following log, please check if the software and hardware environment is configured correctly.

    Tester will show the following logs when inputting the reg 0 command.

    >> Command Parse Init (le_audio) <<
    reg 0
    local bd addr: 0xXX:XX:XX:XX:XX:XX
    adv start
    

    The test flow is shown as below:

    Step

    DUT User Command

    Tester User Command

    Description

    Log

    1

    bondclear

    reg 0

    DUT: Clear all the bond information.

    Tester: Register LE audio profiles, make Bluetooth Host ready, but not register CSIS.

    2

    leascan

    DUT: Start scan, the advertising report will be filtered by UUID ASCS, CAS and BASS.

    DUT serial port assistant tool shows:

    lea scan start

    Add RemoteBd[dev_idx]: [Dev_ACC_NO_CSIS]

    3

    leastopscan

    DUT: Stop scan, when the Tester address is shown on the serial port assistant tool in the scan device list.

    DUT serial port assistant tool shows:

    Add RemoteBd[dev_idx]: [Dev_ACC_NO_CSIS]

    4

    condev [dev_idx]

    DUT: Create connection with Tester. The dev_idx needs to be written according to the scanned device list log printed before.

    DUT serial port assistant tool shows:

    Connected success conn_id 0

    Pair success

    Add Group[0]: group_handle 0xXXXXXXXX, set_mem_size 0

    5

    startmedia 0

    DUT: Start media stream after the log Add Group[0] is shown. After inputting this user command, check the BAP state is switched to 4, and the cfg_type is 1.

    DUT serial port assistant tool shows:

    BAP state: 4

    DUT Debug Analyzer shows:

    [PROTOCOL] !**bap_unicast_audio_cfg: handle 0xXXXXXXXX, cfg_type 1, dev_num 1

    6

    gvcsvolume 0 20

    DUT: Set the volume_setting to 20.

    Tester serial port assistant tool shows:

    vcs: volume_setting 20, mute 0

    7

    releasestream 0

    DUT: Release media stream, check the BAP state is switched to 1.

    DUT serial port assistant tool shows:

    BAP state: 1

    8

    startconvo 0

    DUT: Start conversational stream after the log Add Group[0] is shown. After inputting this user command, check the BAP state is switched to 4, and the cfg_type is 3.

    DUT serial port assistant tool shows:

    BAP state: 4

    DUT Debug Analyzer shows:

    [PROTOCOL] !**bap_unicast_audio_cfg: handle 0xXXXXXXXX, cfg_type 3, dev_num 1

    9

    stopstream 0

    DUT: Stop conversational stream, check the BAP state is switched to 2.

    DUT serial port assistant tool shows:

    BAP state: 2

    10

    releasestream 0

    DUT: Release conversational stream, check the BAP state is switched to 1.

    DUT serial port assistant tool shows:

    BAP state: 1

Code Overview

The main purpose of this chapter is to help sample developers become familiar with the development process related to the CAP initiator role. LE audio CAP initiator sample code overview will be introduced according to the following parts:

  • LE audio CAP initiator sample project overview will be introduced in chapter Source Code Directory.

  • For CAP initiator-related parameters and Bluetooth Host initialization, please refer to the chapter Initialization.

  • For CAP initiator-related GAP message handler, please refer to the chapter GAP Message Handler.

  • For CAP initiator-related callback handler, please refer to the chapter Callback Message Handler.

  • For CAP initiator-related test flow, please refer to the chapter LE Audio Flow.

Source Code Directory

This section describes the project directory and project structure. Reference files directory is as follows:

  • Project directory: board\evb\lea_cap_initiator.

  • Project source code directory: src\sample\lea_samples\lea_cap_initiator.

Source files in the sample project are currently categorized into several groups as below:

└── lea_cap_initiator_4M_bank0
    ├── include                  ROM UUID header files. Developers do not need to modify it.
    ├── lib                      The protocol stack and GAP library file. Developers do not need to modify it.
        ├── gap_utils.lib
        ├── ROM.lib
        ├── upperstack_4M.lib
        ├── hal_utils.lib
        ├── ble_mgr.lib
        ├── leaudio.lib
        └── sysm.lib

    ├── cmsis                    The cmsis source code. Developers do not need to modify it.
    ├── APP                      The sample source code.
        ├── data_uart.c
        ├── user_cmd_parse.c
        ├── bt_ext_ftl.c                   GATT discovery result storage
        ├── gattc_tbl_storage.c
        ├── app_lea_cap_ini_main.c         Main entry
        ├── app_lea_cap_ini_gap.c          LE GAP initialize and message handler
        ├── app_lea_cap_ini_profile.c      LE audio profile initialize
        ├── app_lea_cap_ini_link.c         LE link utility
        ├── app_lea_cap_ini_user_cmd.c     User Command
        ├── app_lea_cap_ini_scan.c         Scan manager
        ├── app_lea_cap_ini_csis.c         CSIS message handler
        ├── app_lea_cap_ini_bap_bsrc.c     BAP Broadcast Source
        ├── app_lea_cap_ini_bap.c          BAP message handler
        ├── app_lea_cap_ini_cap.c          CAP message handler
        ├── app_lea_cap_ini_audio_data.c   Audio data test code
        ├── app_lea_cap_ini_mcp.c          MCP message handler
        ├── app_lea_cap_ini_ccp.c          CCP message handler
        └── app_lea_cap_ini_ecfc.c         ECFC message handler

    └── io_hal

Initialization

The main() function is invoked when the board is powered on or the chip boots up, and it performs the following initialization functions:

int main(void)
{
   app_msg_init();
   board_init();
   app_gap_init();
   framework_init();
#if APP_LEA_INPUT_AUDIO_DATA_TEST
   app_init_timer(app_evt_queue_handle, MAX_NUMBER_OF_APP_TIMER_MODULE);
#endif
   app_lea_profile_init();
   pwr_mgr_init();
   task_init();
   os_sched_start();

   return 0;
}

GAP Parameter Initialization

The app_gap_init() function is used to initialize the GAP parameters. Developers can easily customize the sample by modifying the following parameter values:

void app_gap_init(void)
{
   le_gap_init(APP_MAX_BLE_LINK_NUM);
   gap_lib_init();

   /* Device name and device appearance */
   uint8_t  device_name[GAP_DEVICE_NAME_LEN] = {0};
   uint16_t appearance = GAP_GATT_APPEARANCE_UNKNOWN;

   memcpy(device_name, device_name_le, strlen(device_name_le));

   le_set_gap_param(GAP_PARAM_DEVICE_NAME, GAP_DEVICE_NAME_LEN, device_name);
   le_set_gap_param(GAP_PARAM_APPEARANCE, sizeof(appearance), &appearance);

   /* Use LE Advertising Extensions */
   uint8_t use_extended = true;
   le_set_gap_param(GAP_PARAM_USE_EXTENDED_ADV, sizeof(use_extended), &use_extended);

   /* GAP Bond Manager parameters */
   uint8_t  auth_pair_mode = GAP_PAIRING_MODE_PAIRABLE;
   uint16_t auth_flags = GAP_AUTHEN_BIT_BONDING_FLAG | GAP_AUTHEN_BIT_SC_FLAG;
   uint8_t  auth_io_cap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT;
   uint8_t  auth_oob = false;
   uint8_t  auth_use_fix_passkey = false;
   uint32_t auth_fix_passkey = 0;
   uint8_t  auth_sec_req_enable = true;
   uint16_t auth_sec_req_flags = GAP_AUTHEN_BIT_BONDING_FLAG | GAP_AUTHEN_BIT_SC_FLAG;
   uint8_t  irk_auto = true;

   gap_set_param(GAP_PARAM_BOND_PAIRING_MODE, sizeof(auth_pair_mode), &auth_pair_mode);
   gap_set_param(GAP_PARAM_BOND_AUTHEN_REQUIREMENTS_FLAGS, sizeof(auth_flags), &auth_flags);
   gap_set_param(GAP_PARAM_BOND_IO_CAPABILITIES, sizeof(auth_io_cap), &auth_io_cap);
   gap_set_param(GAP_PARAM_BOND_OOB_ENABLED, sizeof(auth_oob), &auth_oob);
   le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY, sizeof(auth_fix_passkey), &auth_fix_passkey);
   le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY_ENABLE, sizeof(auth_use_fix_passkey),
                     &auth_use_fix_passkey);
   le_bond_set_param(GAP_PARAM_BOND_SEC_REQ_ENABLE, sizeof(auth_sec_req_enable), &auth_sec_req_enable);
   le_bond_set_param(GAP_PARAM_BOND_SEC_REQ_REQUIREMENT, sizeof(auth_sec_req_flags),
                     &auth_sec_req_flags);
   le_bond_set_param(GAP_PARAM_BOND_GEN_LOCAL_IRK_AUTO, sizeof(uint8_t), &irk_auto);

   /* register gap message callback */
   le_register_app_cb(app_gap_callback);
   /* register gap common message callback */
   gap_register_app_cb(app_gap_common_callback);

   /* ble manager module initialize*/
   app_ble_mgr_lib_init();
#if APP_LEA_EATT_SUPPORT
   app_lea_ecfc_init();
#endif
}
  1. le_gap_init()

    Initialize GAP and set link number.

  2. gap_lib_init()

    Initialize gap_utils.lib.

  3. le_set_gap_param()

  4. gap_set_param() and le_bond_set_param()

    Initialize GAP pairing parameters.

  5. le_register_app_cb() and gap_register_app_cb()

    Register the GAP message callback function app_gap_callback() and GAP common message callback function app_gap_common_callback(), and all GAP callback messages will be handled in these callbacks.

  6. app_ble_mgr_lib_init()

    Initialize the LE manager library. More information can be found in the chapter LE Manager Initialization of LE Manager.

    void app_ble_mgr_lib_init(void)
    {
       BLE_MGR_PARAMS param = {0};
    #if BAP_BROADCAST_SOURCE
       param.ble_ext_adv.enable = true;
       param.ble_ext_adv.adv_num = 1;
    #endif
       param.ble_scan.enable = true;
       param.ble_conn.enable = true;
       param.ble_conn.link_num = APP_MAX_BLE_LINK_NUM;
       ble_mgr_init(&param);
    
       gap_vendor_le_set_host_feature(0, 1);
    }
    
  7. app_lea_ecfc_init()

    Initialize ECFC if the sample enables APP_LEA_EATT_SUPPORT.

    void app_lea_ecfc_init(void)
    {
       gap_ecfc_init(1);
       gap_ecfc_reg_proto(PSM_EATT, app_lea_ecfc_callback, true, &app_ecfc_le_proto_id,
                          GAP_ECFC_DATA_PATH_GATT);
    }
    

More information on LE GAP initialization and startup flow can be found in the GAP Parameters Initialization chapter of the LE Host.

LE Audio Profile Initialization

The app_lea_profile_init() function is used to initialize the LE audio profiles parameters. Developers can easily customize the sample by modifying the following parameter values:

void app_lea_profile_init(void)
{
#if (CCP_CALL_CONTROL_SERVER || MCP_MEDIA_CONTROL_SERVER)
   gatt_svc_init(GATT_SVC_USE_EXT_SERVER, MAX_BLE_SRV_NUM);
#endif

#if GATTC_TBL_STORAGE_SUPPORT
   gattc_tbl_storage_init();
#endif
   T_BLE_AUDIO_PARAMS ble_audio_param = {0};
   ble_audio_param.evt_queue_handle = app_evt_queue_handle;
   ble_audio_param.io_queue_handle = app_io_queue_handle;
#if APP_LEA_EATT_SUPPORT
   ble_audio_param.bt_gatt_client_init = (GATT_CLIENT_DISCOV_MODE_REG_SVC_BIT |
                                          GATT_CLIENT_DISCOV_MODE_CCCD_STORAGE_BIT |
                                          GATT_CLIENT_DISCOV_MODE_USE_EXT_CLIENT |
                                          GATT_CLIENT_DISCOV_MODE_GATT_SVC);
   gatt_client_cfg_client_supported_feature(GATT_SVC_CLIENT_SUPPORTED_FEATURES_EATT_BEARER_BIT);
#else
   ble_audio_param.bt_gatt_client_init = (GATT_CLIENT_DISCOV_MODE_REG_SVC_BIT |
                                          GATT_CLIENT_DISCOV_MODE_CCCD_STORAGE_BIT |
                                          GATT_CLIENT_DISCOV_MODE_USE_EXT_CLIENT);
#endif
   ble_audio_param.acl_link_num = APP_MAX_BLE_LINK_NUM;
   ble_audio_param.io_event_type = IO_MSG_TYPE_LE_AUDIO;
   ble_audio_init(&ble_audio_param);
   app_lea_ini_bap_init();
   app_lea_ini_cap_init();
#if MCP_MEDIA_CONTROL_SERVER
   app_lea_ini_mcp_init();
#endif
#if CCP_CALL_CONTROL_SERVER
   app_lea_ini_ccp_init();
#endif
   app_lea_audio_data_init();
}
  1. gatt_svc_init()

    Initialize the GATT service module and service number in the LE manager library.

  2. gattc_tbl_storage_init()

    Initialize the GATT client service table storage function.

  3. ble_audio_init()

    Initialize LE audio parameters.

  4. app_lea_ini_bap_init()

    Initialize the LE audio BAP role.

    void app_lea_ini_bap_init(void)
    {
       T_BAP_ROLE_INFO role_info = {0};
    
       ble_audio_cback_register(app_lea_ini_bap_handle_msg);
    #if BAP_UNICAST_CLIENT
       app_db.bap_role |= BAP_UNICAST_CLT_SRC_ROLE;
       app_db.bap_role |= BAP_UNICAST_CLT_SNK_ROLE;
       role_info.isoc_cig_max_num = APP_ISOC_CIG_MAX_NUM;
       role_info.isoc_cis_max_num = APP_ISOC_CIS_MAX_NUM;
    #endif
    #if BAP_BROADCAST_ASSISTANT
       app_db.bap_role |= BAP_BROADCAST_ASSISTANT_ROLE;
    #endif
    #if BAP_BROADCAST_SOURCE
       app_db.bap_role |= BAP_BROADCAST_SOURCE_ROLE;
       role_info.pa_adv_num = APP_MAX_PA_ADV_SET_NUM;
       role_info.isoc_big_broadcaster_num = APP_ISOC_BROADCASTER_MAX_BIG_HANDLE_NUM;
       role_info.isoc_bis_broadcaster_num = APP_ISOC_BROADCASTER_MAX_BIS_NUM;
    #endif
       role_info.role_mask = app_db.bap_role;
       role_info.init_gap = true;
       bap_role_init(&role_info);
    }
    
  5. app_lea_ini_cap_init()

    Initialize LE audio CAP related parameters.

    void app_lea_ini_cap_init(void)
    {
       T_CAP_INIT_PARAMS cap_init_param = {0};
    
       ble_audio_cback_register(app_lea_ini_cap_handle_msg);
       app_db.cap_role = CAP_ROLE;
       cap_init_param.cap_role = app_db.cap_role;
       cap_init_param.cas_client = true;
    #if CSIP_SET_COORDINATOR
       app_lea_ini_csis_init(&cap_init_param);
    #endif
    #if VCP_VOLUME_CONTROLLER
       cap_init_param.vcp_micp.vcp_vcs_client = true;
    #endif
    #if MICP_MIC_CONTROLLER
       cap_init_param.vcp_micp.micp_mic_controller = true;
    #endif
    #if MCP_MEDIA_CONTROL_SERVER
       app_lea_ini_mcp_init_cap(&cap_init_param);
    #endif
    #if CCP_CALL_CONTROL_SERVER
       app_lea_ini_ccp_init_cap(&cap_init_param);
    #endif
       cap_init(&cap_init_param);
    }
    
  6. app_lea_ini_mcp_init()

    Initialize LE audio MCP related parameters.

    void app_lea_ini_mcp_init(void)
    {
       T_MCP_SERVER_REG_SRV_PARAM reg_srv_param = {0};
    
       reg_srv_param.gmcs = true;
       reg_srv_param.char_media_control_point.support = true;
       reg_srv_param.char_track_duration.optional_property_notify = true;
       reg_srv_param.char_track_position.optional_property_notify = true;
       app_db.mcp_db.gmcs_id = mcp_server_reg_srv(&reg_srv_param);
       if (app_db.mcp_db.gmcs_id != 0xFF)
       {
          T_MCP_SERVER_SET_PARAM set_param = {0};
    
          set_param.char_uuid = MCS_UUID_CHAR_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED;
          set_param.param.media_control_point_opcodes_supported =
              (MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_PLAY |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_PAUSE |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_FAST_REWIND |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_FAST_FORWARD |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_STOP |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_PREVIOUS_TRACK |
               MCS_MEDIA_CONTROL_POINT_OPCODES_SUPPORTED_CHAR_BIT_VALUE_NEXT_TRACK);
          mcp_server_set_param(app_db.mcp_db.gmcs_id, &set_param);
    
          set_param.char_uuid = MCS_UUID_CHAR_MEDIA_STATE;
          set_param.param.media_state = MCS_MEDIA_STATE_PAUSED;
    
          mcp_server_set_param(app_db.mcp_db.gmcs_id, &set_param);
    
          app_db.mcp_db.media_state = MCS_MEDIA_STATE_PAUSED;
          app_db.mcp_db.track_duration = MCS_TRACK_DURATION_CHAR_VALUE_UNKNOWN;
          app_db.mcp_db.track_position = MCS_TRACK_POSITION_CHAR_VALUE_UNAVAILABLE;
       }
    }
    
  7. app_lea_ini_ccp_init()

    Initialize LE audio CCP related parameters.

    void app_lea_ini_ccp_init(void)
    {
       T_CCP_SERVER_REG_SRV_PARAM p_gtbs_param = {0};
    
       p_gtbs_param.gtbs = true;
       p_gtbs_param.char_incoming_call_target_bearer_uri.support = true;
    
       app_db.ccp_db.gtbs_id = ccp_server_reg_srv(&p_gtbs_param);
       if (app_db.ccp_db.gtbs_id != 0xFF)
       {
          T_CCP_SERVER_SET_PARAM param = {0};
    
          param.char_uuid = TBS_UUID_CHAR_CALL_CONTROL_POINT_OPTIONAL_OPCODES;
    #if APP_LEA_TBS_LOCAL_HOLD_SUPPORT
          param.param.call_control_point_optional_opcodes =
              (1 << TBS_CALL_CONTROL_POINT_OPTIONAL_OPCODES_CHAR_BIT_LOCAL_HOLD);
    #endif
          ccp_server_set_param(app_db.ccp_db.gtbs_id, &param);
       }
    }
    
  8. app_lea_audio_data_init()

    Initialize the LE audio data test code.

    void app_lea_audio_data_init(void)
    {
       os_queue_init(&app_db.iso_input_queue);
       os_queue_init(&app_db.iso_output_queue);
       gap_register_direct_cb(app_lea_data_direct_cb);
    }
    

More information can be found in the LE Audio Manager.

GAP Message Handler

The app_handle_gap_msg() function is invoked whenever a GAP message is received from the GAP. More information on GAP messages can be found in the Bluetooth LE GAP Message chapter of the LE Host.

void app_handle_gap_msg(T_IO_MSG *p_gap_msg)
{
   T_LE_GAP_MSG gap_msg;

   memcpy(&gap_msg, &p_gap_msg->u.param, sizeof(p_gap_msg->u.param));
   ble_mgr_handle_gap_msg(p_gap_msg->subtype, &gap_msg);
   APP_PRINT_TRACE1("app_handle_gap_msg: subtype %d", p_gap_msg->subtype);
   switch (p_gap_msg->subtype)
   {
   case GAP_MSG_LE_DEV_STATE_CHANGE:
      {
         app_handle_dev_state_evt(gap_msg.msg_data.gap_dev_state_change.new_state,
                                  gap_msg.msg_data.gap_dev_state_change.cause);
      }
      break;

   case GAP_MSG_LE_CONN_STATE_CHANGE:
      {
         app_handle_conn_state_evt(gap_msg.msg_data.gap_conn_state_change.conn_id,
                                   (T_GAP_CONN_STATE)gap_msg.msg_data.gap_conn_state_change.new_state,
                                   gap_msg.msg_data.gap_conn_state_change.disc_cause);
      }
      break;

   case GAP_MSG_LE_AUTHEN_STATE_CHANGE:
     {
         app_handle_authen_state_evt(gap_msg.msg_data.gap_authen_state.conn_id,
                                     gap_msg.msg_data.gap_authen_state.new_state,
                                     gap_msg.msg_data.gap_authen_state.status);
     }
     break;
   ......
   }
   ble_audio_handle_gap_msg(p_gap_msg->subtype, gap_msg);
}
  1. If APP_LEA_EATT_SUPPORT is enabled, the CAP initiator sample will call app_lea_ecfc_conn() to create an ECFC connection when receiving GAP_CONN_STATE_CONNECTED.

    void app_handle_conn_state_evt(uint8_t conn_id, T_GAP_CONN_STATE new_state, uint16_t disc_cause)
    {
       T_APP_LE_LINK *p_link;
    
       APP_PRINT_INFO3("app_handle_conn_state_evt: conn_id %d, new_state %d, disc_cause 0x%x",
                       conn_id, new_state, disc_cause);
    
       p_link = app_link_find_le_link_by_conn_id(conn_id);
    
       switch (new_state)
       {
       ......
       case GAP_CONN_STATE_CONNECTED:
          if (p_link != NULL)
          {
             p_link->conn_handle = le_get_conn_handle(conn_id);
             p_link->state = GAP_CONN_STATE_CONNECTED;
             le_get_conn_param(GAP_PARAM_CONN_MTU_SIZE, &p_link->mtu_size, conn_id);
             le_get_conn_addr(conn_id, p_link->bd_addr,
                              &p_link->bd_type);
             data_uart_print("Connected success conn_id %d\r\n", conn_id);
    #if APP_LEA_EATT_SUPPORT
             app_lea_ecfc_conn(conn_id);
    #endif
          }
          break;
    
       default:
          break;
    
       }
    }
    
  2. The CAP initiator sample will call app_lea_start_discovery() to start the service discovery procedure when receiving GAP_AUTHEN_STATE_COMPLETE with cause GAP_SUCCESS.

    void app_handle_authen_state_evt(uint8_t conn_id, uint8_t new_state, uint16_t cause)
    {
       APP_PRINT_INFO2("app_handle_authen_state_evt:conn_id %d, cause 0x%x", conn_id, cause);
    
       switch (new_state)
       {
       ......
       case GAP_AUTHEN_STATE_COMPLETE:
           {
               T_APP_LE_LINK *p_link;
    
               p_link = app_link_find_le_link_by_conn_id(conn_id);
               if (p_link)
               {
                   if (cause == GAP_SUCCESS)
                   {
                       data_uart_print("Pair success\r\n");
                       APP_PRINT_INFO0("app_handle_authen_state_evt: GAP_AUTHEN_STATE_COMPLETE pair success");
                       p_link->auth_cmpl = true;
                       app_lea_start_discovery(p_link);
                   }
                   else
                   {
                       data_uart_print("Pair failed: cause 0x%x\r\n", cause);
                       APP_PRINT_INFO0("app_handle_authen_state_evt: GAP_AUTHEN_STATE_COMPLETE pair failed");
                       p_link->auth_cmpl = false;
                   }
               }
           }
           break;
    
       default:
           {
               APP_PRINT_ERROR1("app_handle_authen_state_evt: unknown new_state %d", new_state);
           }
           break;
       }
    }
    
  3. ble_audio_handle_gap_msg()

    LE audio library handles GAP messages.

Callback Message Handler

When the CAP initiator sample handles GAP callbacks, the ble_mgr_handle_gap_cb() and ble_audio_handle_gap_cb() will be called to handle the GAP callback messages.

If the GATTC_TBL_STORAGE_SUPPORT is enabled, the CAP initiator sample will call gattc_tbl_storage_handle_bond_modify() when receiving GAP_MSG_LE_BOND_MODIFY_INFO. If the bond information of the remote device is deleted, the GATT service table of the same remote device will be removed together.

T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
{
   T_APP_RESULT result = APP_RESULT_SUCCESS;
   T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;

   ble_mgr_handle_gap_cb(cb_type, p_cb_data);
   ble_audio_handle_gap_cb(cb_type, p_cb_data);

   switch (cb_type)
   {
   case GAP_MSG_LE_CONN_UPDATE_IND:
      APP_PRINT_INFO5("GAP_MSG_LE_CONN_UPDATE_IND: conn_id %d, conn_interval_max 0x%x, conn_interval_min 0x%x, conn_latency 0x%x,supervision_timeout 0x%x",
                      p_data->p_le_conn_update_ind->conn_id,
                      p_data->p_le_conn_update_ind->conn_interval_max,
                      p_data->p_le_conn_update_ind->conn_interval_min,
                      p_data->p_le_conn_update_ind->conn_latency,
                      p_data->p_le_conn_update_ind->supervision_timeout);
      /* if reject the proposed connection parameter from peer device, use APP_RESULT_REJECT. */
      result = APP_RESULT_ACCEPT;
      break;

   case GAP_MSG_LE_BOND_MODIFY_INFO:
      APP_PRINT_INFO1("GAP_MSG_LE_BOND_MODIFY_INFO: type 0x%x",
                      p_data->p_le_bond_modify_info->type);
#if GATTC_TBL_STORAGE_SUPPORT
      gattc_tbl_storage_handle_bond_modify(p_data->p_le_bond_modify_info);
#endif
      break;

   default:
      //APP_PRINT_ERROR1("app_gap_callback: unhandled cb_type 0x%x", cb_type);
      break;
   }
   return result;
}

LE Audio Flow

This chapter describes the LE audio flows related to the Initiator Role:

Discovery and Connect Acceptor Role Device without CSIS

Discovery and connect acceptor role device without CSIS flow is shown below:

../../../_images/ini_discovery_acc1.png

Discovery and Connect Acceptor Role Device with CSIS

Discovery and connect Acceptor Role device with CSIS flow is shown below:

../../../_images/ini_discovery_acc2.png

Unicast Audio Start and Stop Flow

An Initiator acting in the role of BAP Unicast Client uses this procedure to start and stop one or more unicast Audio Streams. Unicast audio start and stop procedures are shown as below:

../../../_images/ini_bap_unicast.png

Broadcast Audio Start Procedure

The broadcast audio start procedure is shown as below:

../../../_images/ini_bap_bsrc.png

Broadcast Audio Reception Start and Stop Flow

Broadcast audio reception start and stop are shown as below:

../../../_images/ini_bap_ba.png

Capture and Rendering Control Procedures

Capture and rendering control procedures are shown as below:

../../../_images/ini_vcp_micp.png
  • LE_AUDIO_MSG_CAP_DIS_DONE

    LE Audio Manager will send this message when the CAP discovery procedure is completed. This message will inform whether CAS, VCS, and MICS are found.