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.
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:
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 macroAPP_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:
Configurable Item |
Value |
---|---|
LE Link Number |
≥ |
LE Master Link Num |
≥ |
CCCD Count |
64 |
CCCD Per Link Count |
32 |
LE Bond Device number |
≥ |
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:
Open
rtl87x3e_lea_cap_initiator.uvprojx
.Choose the build target
lea_cap_initiator_4M_bank0
.Build the target.
After a successful compilation, the sample bin file
lea_cap_initiator_bank0_MP-v0.0.0.0-xxx.bin
will be generated in the directorybin\rtl87x3e\flash_4M_dualbank\bank0
.Download the sample bin into the EVB board.
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
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.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
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
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
}
-
Initialize GAP and set link number.
-
Initialize
gap_utils.lib
. -
Configure device name with the parameter
GAP_PARAM_DEVICE_NAME
.Configure appearance with the parameter
GAP_PARAM_APPEARANCE
.Configure the sample to use LE Advertising Extensions with the parameter
GAP_PARAM_USE_EXTENDED_ADV
.
gap_set_param()
andle_bond_set_param()
Initialize GAP pairing parameters.
le_register_app_cb()
andgap_register_app_cb()
Register the GAP message callback function
app_gap_callback()
and GAP common message callback functionapp_gap_common_callback()
, and all GAP callback messages will be handled in these callbacks.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(¶m); gap_vendor_le_set_host_feature(0, 1); }
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();
}
-
Initialize the GATT service module and service number in the LE manager library.
gattc_tbl_storage_init()
Initialize the GATT client service table storage function.
-
Initialize LE audio parameters.
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); }
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); }
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(®_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; } }
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, ¶m); } }
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);
}
If
APP_LEA_EATT_SUPPORT
is enabled, the CAP initiator sample will callapp_lea_ecfc_conn()
to create an ECFC connection when receivingGAP_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; } }
The CAP initiator sample will call
app_lea_start_discovery()
to start the service discovery procedure when receivingGAP_AUTHEN_STATE_COMPLETE
with causeGAP_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; } }
-
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:
LE_AUDIO_MSG_CSIS_CLIENT_DIS_DONE
LE Audio Manager will send this message to inform whether CSIS is found.
Discovery and Connect Acceptor Role Device with CSIS
Discovery and connect Acceptor Role device with CSIS flow is shown below:
LE_AUDIO_MSG_CSIS_CLIENT_READ_RESULT
LE Audio Manager will send this message when the CSIS read procedure is completed.
LE_AUDIO_MSG_CSIS_CLIENT_SET_MEM_FOUND
When the sample calls
set_coordinator_cfg_discover()
to enter discovery mode. LE Audio Manager will send this message when the Set Member is found.LE_AUDIO_MSG_CSIS_CLIENT_SEARCH_DONE
When the timer times out or all the Set members are found, the LE Audio Manager will exit discovery mode. Then the LE Audio Manager will send this message to inform.
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:
-
LE Audio Manager will send this message when the BAP discovery procedure is completed. The BAP discovery procedure includes reading ASCS, PACS, and BASS.
-
LE Audio Manager will send this message when the CAP discovery procedure is completed. This message will inform whether to find CAS, VCS, and MICS.
-
LE Audio Manager will send this message when the BAP state changes.
AUDIO_GROUP_MSG_BAP_SETUP_DATA_PATH
LE Audio Manager will send this message when the setup data path procedure is completed.
AUDIO_GROUP_MSG_BAP_REMOVE_DATA_PATH
LE Audio Manager will send this message when the remove data path procedure is completed.
Broadcast Audio Start Procedure
The broadcast audio start procedure is shown as below:
MSG_BROADCAST_SOURCE_STATE_CHANGE
LE Audio Manager will send this message when the Broadcast Source state changes.
MSG_BROADCAST_SOURCE_SETUP_DATA_PATH
LE Audio Manager will send this message when the setup data path procedure is completed.
Broadcast Audio Reception Start and Stop Flow
Broadcast audio reception start and stop are shown as below:
LE_AUDIO_MSG_BASS_CLIENT_SYNC_INFO_REQ
LE Audio Manager will send this message when the server sends a SyncInfo Request.
LE_AUDIO_MSG_BASS_CLIENT_BRS_DATA
LE Audio Manager will send this message when the BASS Broadcast Receive State characteristic value of the remote device changes.
Capture and Rendering Control Procedures
Capture and rendering control procedures are shown as below:
-
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.