HAP
The purpose of the Hearing Access Profile (HAP) is to define the requirements for an interoperable experience for users of hearing aids and complementary products in the hearing aid ecosystem that use Bluetooth Low Energy (LE) Audio technology with the Isochronous Channels feature.
This document will introduce the usage of HAP-related APIs to help users develop hearing aid products.
Terminology and Concepts
HAP defines the following profile roles:
Hearing Aid (HA): The HA role is implemented in a hearing aid.
Hearing Aid Unicast Client (HAUC): The HAUC role is implemented in a device capable of sending and optionally receiving unicast audio data to/from a hearing aid in the HA role.
Hearing Aid Remote Controller (HARC): The HARC role is implemented in a device that controls volume levels of the different audio sources, mute state of a microphone, and presets of a hearing aid in the HA role.
The table below shows the conformance requirements for HAP roles with HAS Client role and HAS Server role.
Profile Role |
HA |
HAUC |
HARC |
---|---|---|---|
HAS Client |
X |
X |
Mandatory |
HAS Server |
Mandatory |
X |
X |
Provided APIs
The table below shows a simple description of HAP APIs.
Header File |
Description |
API Reference |
---|---|---|
|
HAP related definitions. |
|
|
HAS client related definitions and APIs. |
|
|
HAS server related definitions and APIs. |
The HAP related definitions are provided in the inc\bluetooth\leaudio\has_def.h
.
The HAS client related definitions and APIs are provided in the inc\bluetooth\leaudio\has_client.h
.
The HAS server related definitions and APIs are provided in the inc\bluetooth\leaudio\has_mgr.h
.
Initialization and Configurations
This chapter describes the initialization and configurations of HAP profile roles. The initialization of HAS client is described in the HAS Client Initialization.
HAS Client Initialization
has_client_init() is used to initialize the HAS client. APP can call the API ble_audio_cback_register() to register HAS client callback function to handle HAS client messages.
void app_lea_profile_init(void)
{
ble_audio_cback_register(has_client_ts_handle_msg);
has_client_init();
}
Functions
HAP’s functions are mainly divided into HAP client role and HAP server role. The functionality of the HAP client role is primarily introduced in chapter HAS Client.
HAS Client
This chapter describes the HAS client related functions, including:
Configure the CCCD
has_cfg_cccd() is used to configure HAS service CCCD value.
When handling the message LE_AUDIO_MSG_HAS_CLIENT_DIS_DONE, APP can get the features that the remote HAS server supports. According to the features, APP can configure the CCCD by calling this API.
void app_lea_profile_init(void)
{
ble_audio_cback_register(has_client_ts_handle_msg);
has_client_init();
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_DIS_DONE:
{
T_HAS_CLIENT_DIS_DONE *p_data = (T_HAS_CLIENT_DIS_DONE *)buf;
if (p_data->is_found)
{
uint16_t cfg_flags = 0;
if (p_data->is_ha_features_notify_support)
{
cfg_flags |= HAS_HEARING_AID_FEATURE_FLAG;
}
if (p_data->is_ha_cp_exist)
{
cfg_flags |= HAS_HEARING_AID_PRESET_CP_FLAG;
cfg_flags |= HAS_ACTIVE_PRESET_IDX_FLAG;
}
has_cfg_cccd(p_data->conn_handle, cfg_flags, true);
}
}
break;
default:
break;
}
}
Read Procedures
HAS client provides APIs for APP to read HAS service characteristic values.
Read Hearing Aid Features
has_read_ha_features() is used to read the hearing aid features. If the read procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_READ_HA_FEATURES_RESULT will be sent to APP.
void test(uint16_t conn_handle)
{
has_read_ha_features(conn_handle);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_READ_HA_FEATURES_RESULT:
{
T_HAS_CLIENT_READ_HA_FEATURES_RESULT *p_data = (T_HAS_CLIENT_READ_HA_FEATURES_RESULT *)buf;
APP_PRINT_INFO3("LE_AUDIO_MSG_HAS_CLIENT_READ_HA_FEATURES_RESULT: hearing aid features 0x%x, conn_handle 0x%x, cause 0x%x",
p_data->has_feature, p_data->conn_handle, p_data->cause);
}
break;
default:
break;
}
}
Read Active Preset Index
has_read_active_preset_idx() is used to read the active preset index. If the read procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_READ_ACTIVE_PRESET_IDX_RESULT will be sent to APP.
void test(uint16_t conn_handle)
{
has_read_active_preset_idx(conn_handle);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_READ_ACTIVE_PRESET_IDX_RESULT:
{
T_HAS_CLIENT_READ_ACTIVE_PRESET_IDX_RESULT *p_data = (T_HAS_CLIENT_READ_ACTIVE_PRESET_IDX_RESULT *)
buf;
APP_PRINT_INFO3("LE_AUDIO_MSG_HAS_CLIENT_READ_ACTIVE_PRESET_IDX_RESULT: conn_handle 0x%x, cause 0x%x, active preset idx 0x%x",
p_data->conn_handle,
p_data->cause,
p_data->active_preset_idx);
}
break;
default:
break;
}
}
Control Point
HAS client provides APIs for APP to trigger the ‘Hearing Aid Control Point’ characteristic operations.
Read Presets Operation
has_cp_read_presets() is used to write the ‘Hearing Aid Control Point’ characteristic value with ‘Read Presets Request’ opcode.
If the write procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT will be sent to APP. Then, the HAS server will send read preset response notifications or indications to HAS client. When HAS client receives these notifications or indications, the message LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA will be sent to APP with the opcode HAS_CP_OP_READ_PRESET_RSP.
void test(uint16_t conn_handle, uint8_t start_preset_idx, uint8_t preset_num)
{
has_cp_read_presets(conn_handle, start_preset_idx, preset_num);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT:
{
T_HAS_CLIENT_CP_RESULT *p_data = (T_HAS_CLIENT_CP_RESULT *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x",
p_data->conn_handle, p_data->cause);
}
break;
case LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA:
{
T_HAS_CLIENT_CP_NOTIFY_IND_DATA *p_data = (T_HAS_CLIENT_CP_NOTIFY_IND_DATA *)buf;
if (p_data->notify)
{
APP_PRINT_INFO0("LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA: has send cp notification");
}
else
{
APP_PRINT_INFO0("LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA: has send cp indication");
}
if (p_data->cp_data.cp_op == HAS_CP_OP_READ_PRESET_RSP)
{
APP_PRINT_INFO4("HAS_CP_OP_READ_PRESET_RSP: is_last 0x%x, idx 0x%x, properties 0x%x, name %s",
p_data->cp_data.is_last,
p_data->cp_data.preset.index,
p_data->cp_data.preset.properties,
TRACE_STRING(p_data->cp_data.preset.p_name));
}
}
break;
default:
break;
}
}
Write Preset Name Operation
has_cp_write_preset_name() is used to write the ‘Hearing Aid Control Point’ characteristic value with ‘Write Preset Name’ opcode.
If the write procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT will be sent to APP. Then, the HAS server will send preset changed notification or indication to HAS client. When HAS client receives the preset changed notification or indication, the message LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA will be sent to APP with the opcode HAS_CP_OP_PRESET_CHANGED.
void test(uint16_t conn_handle, uint8_t preset_idx,
uint8_t name_len, char *p_name)
{
has_cp_write_preset_name(conn_handle, preset_idx, name_len, p_name);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT:
{
T_HAS_CLIENT_CP_RESULT *p_data = (T_HAS_CLIENT_CP_RESULT *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x",
p_data->conn_handle, p_data->cause);
}
break;
case LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA:
{
T_HAS_CLIENT_CP_NOTIFY_IND_DATA *p_data = (T_HAS_CLIENT_CP_NOTIFY_IND_DATA *)buf;
if (p_data->notify)
{
APP_PRINT_INFO0("LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA: has send cp notification");
}
else
{
APP_PRINT_INFO0("LE_AUDIO_MSG_HAS_CLIENT_CP_NOTIFY_IND_DATA: has send cp indication");
}
if (p_data->cp_data.cp_op == HAS_CP_OP_PRESET_CHANGED)
{
switch (p_data->cp_data.change_id)
{
case GENERIC_UPDATE:
{
APP_PRINT_INFO6("HAS_CP_OP_PRESET_CHANGED: change_id 0x%x, is_last 0x%x, pre_idx 0x%x, idx 0x%x, properties 0x%x, name %s",
p_data->cp_data.change_id,
p_data->cp_data.is_last,
p_data->cp_data.pre_idx,
p_data->cp_data.preset.index,
p_data->cp_data.preset.properties,
TRACE_STRING(p_data->cp_data.preset.p_name));
}
break;
case PRESET_RECORD_DELETED:
case PRESET_RECORD_AVAILABLE:
case PRESET_RECORD_UNAVAILABLE:
{
APP_PRINT_INFO3("HAS_CP_OP_PRESET_CHANGED: change_id 0x%x, is_last 0x%x, idx 0x%x",
p_data->cp_data.change_id,
p_data->cp_data.is_last,
p_data->cp_data.preset.index);
}
break;
default:
break;
}
}
}
break;
default:
break;
}
}
Set Active Preset Operation
has_cp_set_active_preset() is used to set the active preset.
If the parameter is_sync_local
is false, the ‘Set Active Preset’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic. Otherwise, the ‘Set Active Preset - Synchronized Locally’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic.
If the write procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT will be sent to APP.
If this operation causes the value of the ‘Active Preset Index’ characteristic to change, the HAS server will send an active preset index notification to the HAS client. When the HAS client receives the active preset index notification, the message LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY will be sent to APP.
void test(uint16_t conn_handle, uint8_t preset_idx, bool is_sync_local)
{
has_cp_set_active_preset(conn_handle, preset_idx, is_sync_local);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT:
{
T_HAS_CLIENT_CP_RESULT *p_data = (T_HAS_CLIENT_CP_RESULT *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x",
p_data->conn_handle, p_data->cause);
}
break;
case LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY:
{
T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *p_data = (T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY: conn_handle 0x%x, active_preset_idx 0x%x",
p_data->conn_handle,
p_data->active_preset_idx);
}
break;
default:
break;
}
}
Set Next Preset Operation
has_cp_set_next_preset() is used to set the next preset record in the server’s list of preset records as the active preset.
If the parameter is_sync_local
is false, the ‘Set Next Preset’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic. Otherwise, the ‘Set Next Preset - Synchronized Locally’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic.
If the write procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT will be sent to APP.
If this operation causes the value of the ‘Active Preset Index’ characteristic to change, the HAS server will send an active preset index notification to the HAS client. When the HAS client receives the active preset index notification, the message LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY will be sent to APP.
void test(uint16_t conn_handle, bool is_sync_local)
{
has_cp_set_next_preset(conn_handle, is_sync_local);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT:
{
T_HAS_CLIENT_CP_RESULT *p_data = (T_HAS_CLIENT_CP_RESULT *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x",
p_data->conn_handle, p_data->cause);
}
break;
case LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY:
{
T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *p_data = (T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY: conn_handle 0x%x, active_preset_idx 0x%x",
p_data->conn_handle,
p_data->active_preset_idx);
}
break;
default:
break;
}
}
Set Previous Preset Operation
has_cp_set_previous_preset() is used to set the previous preset record in the server’s list of preset records as the active preset.
If the parameter is_sync_local
is false, the ‘Set Previous Preset’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic. Otherwise, the ‘Set Previous Preset - Synchronized Locally’ opcode will be written to the ‘Hearing Aid Preset Control Point’ characteristic.
If the write procedure is completed, the message LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT will be sent to APP.
If this operation causes the value of the ‘Active Preset Index’ characteristic to change, the HAS server will send active preset index notification to HAS client. When HAS client receives the active preset index notification, the message LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY will be sent to APP.
void test(uint16_t conn_handle, bool is_sync_local)
{
has_cp_set_previous_preset(conn_handle, is_sync_local);
}
uint16_t has_client_ts_handle_msg(T_LE_AUDIO_MSG msg, void *buf)
{
uint16_t cb_result = BLE_AUDIO_CB_RESULT_SUCCESS;
switch (msg)
{
case LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT:
{
T_HAS_CLIENT_CP_RESULT *p_data = (T_HAS_CLIENT_CP_RESULT *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_CP_RESULT: conn_handle 0x%x, cause 0x%x",
p_data->conn_handle, p_data->cause);
}
break;
case LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY:
{
T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *p_data = (T_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY *)buf;
APP_PRINT_INFO2("LE_AUDIO_MSG_HAS_CLIENT_ACTIVE_PRESET_IDX_NOTIFY: conn_handle 0x%x, active_preset_idx 0x%x",
p_data->conn_handle,
p_data->active_preset_idx);
}
break;
default:
break;
}
}