blob: f3f32d761f13d600c69424ba0a71117d536e9be6 [file] [log] [blame]
/******************************************************************************
*
* Copyright (c) 2014 The Android Open Source Project
* Copyright (C) 2009-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/************************************************************************************
*
* Filename: btif_hf_client.c
*
* Description: Handsfree Profile (HF role) Bluetooth Interface
*
*
***********************************************************************************/
#define LOG_TAG "bt_btif_hfc"
#include <stdlib.h>
#include <string.h>
#include <hardware/bluetooth.h>
#include <hardware/bt_hf_client.h>
#include "bt_utils.h"
#include "bta_hf_client_api.h"
#include "btcore/include/bdaddr.h"
#include "btif_common.h"
#include "btif_profile_queue.h"
#include "btif_util.h"
#include "osi/include/osi.h"
#include "osi/include/properties.h"
/************************************************************************************
* Constants & Macros
***********************************************************************************/
#ifndef BTIF_HF_CLIENT_SERVICE_NAME
#define BTIF_HF_CLIENT_SERVICE_NAME ("Handsfree")
#endif
#ifndef BTIF_HF_CLIENT_SECURITY
#define BTIF_HF_CLIENT_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
#endif
#ifndef BTIF_HF_CLIENT_FEATURES
#define BTIF_HF_CLIENT_FEATURES \
(BTA_HF_CLIENT_FEAT_ECNR | BTA_HF_CLIENT_FEAT_3WAY | \
BTA_HF_CLIENT_FEAT_CLI | BTA_HF_CLIENT_FEAT_VREC | BTA_HF_CLIENT_FEAT_VOL | \
BTA_HF_CLIENT_FEAT_ECS | BTA_HF_CLIENT_FEAT_ECC | BTA_HF_CLIENT_FEAT_CODEC)
#endif
/************************************************************************************
* Local type definitions
***********************************************************************************/
/************************************************************************************
* Static variables
***********************************************************************************/
static bthf_client_callbacks_t* bt_hf_client_callbacks = NULL;
static uint32_t btif_hf_client_features = 0;
char btif_hf_client_version[PROPERTY_VALUE_MAX];
#define CHECK_BTHF_CLIENT_INIT() \
do { \
if (bt_hf_client_callbacks == NULL) { \
BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \
return BT_STATUS_NOT_READY; \
} else { \
BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \
} \
} while (0)
#define CHECK_BTHF_CLIENT_SLC_CONNECTED() \
do { \
if (bt_hf_client_callbacks == NULL) { \
BTIF_TRACE_WARNING("BTHF CLIENT: %s: not initialized", __func__); \
return BT_STATUS_NOT_READY; \
} else if (btif_hf_client_cb.state != \
BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED) { \
BTIF_TRACE_WARNING("BTHF CLIENT: %s: SLC connection not up. state=%s", \
__func__, \
dump_hf_conn_state(btif_hf_client_cb.state)); \
return BT_STATUS_NOT_READY; \
} else { \
BTIF_TRACE_EVENT("BTHF CLIENT: %s", __func__); \
} \
} while (0)
/* BTIF-HF control block to map bdaddr to BTA handle */
typedef struct {
uint16_t handle;
bt_bdaddr_t connected_bda;
bthf_client_connection_state_t state;
bthf_client_vr_state_t vr_state;
tBTA_HF_CLIENT_PEER_FEAT peer_feat;
tBTA_HF_CLIENT_CHLD_FEAT chld_feat;
} btif_hf_client_cb_t;
static btif_hf_client_cb_t btif_hf_client_cb;
/************************************************************************************
* Static functions
***********************************************************************************/
/*******************************************************************************
*
* Function btif_in_hf_client_generic_evt
*
* Description Processes generic events to be sent to JNI that are not
* triggered from the BTA.
* Always runs in BTIF context
*
* Returns void
*
******************************************************************************/
static void btif_in_hf_client_generic_evt(uint16_t event,
UNUSED_ATTR char *p_param) {
BTIF_TRACE_EVENT("%s: event=%d", __func__, event);
switch (event) {
case BTIF_HF_CLIENT_CB_AUDIO_CONNECTING: {
HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
(bthf_client_audio_state_t)BTHF_AUDIO_STATE_CONNECTING,
&btif_hf_client_cb.connected_bda);
} break;
default: {
BTIF_TRACE_WARNING("%s : Unknown event 0x%x", __func__, event);
} break;
}
}
/************************************************************************************
* Externs
***********************************************************************************/
/************************************************************************************
* Functions
***********************************************************************************/
static void clear_state(void) {
memset(&btif_hf_client_cb, 0, sizeof(btif_hf_client_cb_t));
}
static bool is_connected(bt_bdaddr_t* bd_addr) {
if (((btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_CONNECTED) ||
(btif_hf_client_cb.state ==
BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED)) &&
((bd_addr == NULL) ||
(bdcmp(bd_addr->address, btif_hf_client_cb.connected_bda.address) == 0)))
return true;
return false;
}
/*****************************************************************************
* Section name (Group of functions)
****************************************************************************/
/*****************************************************************************
*
* btif hf api functions (no context switch)
*
****************************************************************************/
/*******************************************************************************
*
* Function btif_hf_client_init
*
* Description initializes the hf interface
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t init(bthf_client_callbacks_t* callbacks) {
BTIF_TRACE_EVENT("%s", __func__);
bt_hf_client_callbacks = callbacks;
btif_enable_service(BTA_HFP_HS_SERVICE_ID);
clear_state();
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function connect
*
* Description connect to audio gateway
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t connect_int(bt_bdaddr_t* bd_addr, uint16_t uuid) {
if (is_connected(bd_addr)) return BT_STATUS_BUSY;
btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTING;
bdcpy(btif_hf_client_cb.connected_bda.address, bd_addr->address);
BTA_HfClientOpen(btif_hf_client_cb.handle,
btif_hf_client_cb.connected_bda.address,
BTIF_HF_CLIENT_SECURITY);
return BT_STATUS_SUCCESS;
}
static bt_status_t connect(bt_bdaddr_t* bd_addr) {
BTIF_TRACE_EVENT("HFP Client version is %s", btif_hf_client_version);
CHECK_BTHF_CLIENT_INIT();
return btif_queue_connect(UUID_SERVCLASS_HF_HANDSFREE, bd_addr, connect_int);
}
/*******************************************************************************
*
* Function disconnect
*
* Description disconnect from audio gateway
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t disconnect(bt_bdaddr_t* bd_addr) {
CHECK_BTHF_CLIENT_INIT();
if (is_connected(bd_addr)) {
BTA_HfClientClose(btif_hf_client_cb.handle);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function connect_audio
*
* Description create an audio connection
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t connect_audio(bt_bdaddr_t* bd_addr) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (is_connected(bd_addr)) {
if ((BTIF_HF_CLIENT_FEATURES & BTA_HF_CLIENT_FEAT_CODEC) &&
(btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_CODEC)) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BCC, 0,
0, NULL);
} else {
BTA_HfClientAudioOpen(btif_hf_client_cb.handle);
}
/* Inform the application that the audio connection has been initiated
* successfully */
btif_transfer_context(btif_in_hf_client_generic_evt,
BTIF_HF_CLIENT_CB_AUDIO_CONNECTING, (char*)bd_addr,
sizeof(bt_bdaddr_t), NULL);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function disconnect_audio
*
* Description close the audio connection
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t disconnect_audio(bt_bdaddr_t* bd_addr) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (is_connected(bd_addr)) {
BTA_HfClientAudioClose(btif_hf_client_cb.handle);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_FAIL;
}
/*******************************************************************************
*
* Function start_voice_recognition
*
* Description start voice recognition
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t start_voice_recognition() {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 1,
0, NULL);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_UNSUPPORTED;
}
/*******************************************************************************
*
* Function stop_voice_recognition
*
* Description stop voice recognition
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t stop_voice_recognition() {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_VREC) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BVRA, 0,
0, NULL);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_UNSUPPORTED;
}
/*******************************************************************************
*
* Function volume_control
*
* Description volume control
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t volume_control(bthf_client_volume_type_t type, int volume) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
switch (type) {
case BTHF_CLIENT_VOLUME_TYPE_SPK:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGS,
volume, 0, NULL);
break;
case BTHF_CLIENT_VOLUME_TYPE_MIC:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VGM,
volume, 0, NULL);
break;
default:
return BT_STATUS_UNSUPPORTED;
}
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function dial
*
* Description place a call
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t dial(const char* number) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (number) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD, 0, 0,
number);
} else {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BLDN, 0,
0, NULL);
}
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function dial_memory
*
* Description place a call with number specified by location (speed dial)
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t dial_memory(int location) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATD,
location, 0, NULL);
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function handle_call_action
*
* Description handle specified call related action
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t handle_call_action(bthf_client_call_action_t action,
int idx) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
switch (action) {
case BTHF_CLIENT_CALL_ACTION_CHLD_0:
if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_REL) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
0, 0, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_1:
// CHLD 1 is mandatory for 3 way calling
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
1, 0, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_2:
// CHLD 2 is mandatory for 3 way calling
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_FEAT_3WAY) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
2, 0, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_3:
if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
3, 0, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_4:
if (btif_hf_client_cb.chld_feat & BTA_HF_CLIENT_CHLD_MERGE_DETACH) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
4, 0, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_1x:
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) {
if (idx < 1) {
return BT_STATUS_FAIL;
}
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
1, idx, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_CHLD_2x:
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECC) {
if (idx < 1) {
return BT_STATUS_FAIL;
}
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHLD,
2, idx, NULL);
break;
}
return BT_STATUS_UNSUPPORTED;
case BTHF_CLIENT_CALL_ACTION_ATA:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_ATA, 0,
0, NULL);
break;
case BTHF_CLIENT_CALL_ACTION_CHUP:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CHUP, 0,
0, NULL);
break;
case BTHF_CLIENT_CALL_ACTION_BTRH_0:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 0,
0, NULL);
break;
case BTHF_CLIENT_CALL_ACTION_BTRH_1:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 1,
0, NULL);
break;
case BTHF_CLIENT_CALL_ACTION_BTRH_2:
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BTRH, 2,
0, NULL);
break;
default:
return BT_STATUS_FAIL;
}
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function query_current_calls
*
* Description query list of current calls
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t query_current_calls(void) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_ECS) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CLCC, 0,
0, NULL);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_UNSUPPORTED;
}
/*******************************************************************************
*
* Function query_current_operator_name
*
* Description query current selected operator name
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t query_current_operator_name(void) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_COPS, 0, 0,
NULL);
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function retieve_subscriber_info
*
* Description retrieve subscriber number information
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t retrieve_subscriber_info(void) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_CNUM, 0, 0,
NULL);
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function send_dtmf
*
* Description send dtmf
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t send_dtmf(char code) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_VTS, code,
0, NULL);
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function request_last_voice_tag_number
*
* Description Request number from AG for VR purposes
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t request_last_voice_tag_number(void) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_VTAG) {
BTA_HfClientSendAT(btif_hf_client_cb.handle, BTA_HF_CLIENT_AT_CMD_BINP, 1,
0, NULL);
return BT_STATUS_SUCCESS;
}
return BT_STATUS_UNSUPPORTED;
}
/*******************************************************************************
*
* Function cleanup
*
* Description Closes the HF interface
*
* Returns bt_status_t
*
******************************************************************************/
static void cleanup(void) {
BTIF_TRACE_EVENT("%s", __func__);
if (bt_hf_client_callbacks) {
btif_disable_service(BTA_HFP_HS_SERVICE_ID);
bt_hf_client_callbacks = NULL;
}
}
/*******************************************************************************
*
* Function send_at_cmd
*
* Description Send requested AT command to rempte device.
*
* Returns bt_status_t
*
******************************************************************************/
static bt_status_t send_at_cmd(int cmd, int val1, int val2, const char* arg) {
CHECK_BTHF_CLIENT_SLC_CONNECTED();
BTIF_TRACE_EVENT("%s Cmd %d val1 %d val2 %d arg %s", __func__, cmd, val1,
val2, (arg != NULL) ? arg : "<null>");
BTA_HfClientSendAT(btif_hf_client_cb.handle, cmd, val1, val2, arg);
return BT_STATUS_SUCCESS;
}
static const bthf_client_interface_t bthfClientInterface = {
sizeof(bthf_client_interface_t),
.init = init,
.connect = connect,
.disconnect = disconnect,
.connect_audio = connect_audio,
.disconnect_audio = disconnect_audio,
.start_voice_recognition = start_voice_recognition,
.stop_voice_recognition = stop_voice_recognition,
.volume_control = volume_control,
.dial = dial,
.dial_memory = dial_memory,
.handle_call_action = handle_call_action,
.query_current_calls = query_current_calls,
.query_current_operator_name = query_current_operator_name,
.retrieve_subscriber_info = retrieve_subscriber_info,
.send_dtmf = send_dtmf,
.request_last_voice_tag_number = request_last_voice_tag_number,
.cleanup = cleanup,
.send_at_cmd = send_at_cmd,
};
static void process_ind_evt(tBTA_HF_CLIENT_IND* ind) {
switch (ind->type) {
case BTA_HF_CLIENT_IND_CALL:
HAL_CBACK(bt_hf_client_callbacks, call_cb,
(bthf_client_call_t)ind->value);
break;
case BTA_HF_CLIENT_IND_CALLSETUP:
HAL_CBACK(bt_hf_client_callbacks, callsetup_cb,
(bthf_client_callsetup_t)ind->value);
break;
case BTA_HF_CLIENT_IND_CALLHELD:
HAL_CBACK(bt_hf_client_callbacks, callheld_cb,
(bthf_client_callheld_t)ind->value);
break;
case BTA_HF_CLIENT_IND_SERVICE:
HAL_CBACK(bt_hf_client_callbacks, network_state_cb,
(bthf_client_network_state_t)ind->value);
break;
case BTA_HF_CLIENT_IND_SIGNAL:
HAL_CBACK(bt_hf_client_callbacks, network_signal_cb, ind->value);
break;
case BTA_HF_CLIENT_IND_ROAM:
HAL_CBACK(bt_hf_client_callbacks, network_roaming_cb,
(bthf_client_service_type_t)ind->value);
break;
case BTA_HF_CLIENT_IND_BATTCH:
HAL_CBACK(bt_hf_client_callbacks, battery_level_cb, ind->value);
break;
default:
break;
}
}
/*******************************************************************************
*
* Function btif_hf_client_upstreams_evt
*
* Description Executes HF CLIENT UPSTREAMS events in btif context
*
* Returns void
*
******************************************************************************/
static void btif_hf_client_upstreams_evt(uint16_t event, char* p_param) {
tBTA_HF_CLIENT* p_data = (tBTA_HF_CLIENT*)p_param;
bdstr_t bdstr;
BTIF_TRACE_DEBUG("%s: event=%s (%u)", __func__, dump_hf_client_event(event),
event);
switch (event) {
case BTA_HF_CLIENT_ENABLE_EVT:
case BTA_HF_CLIENT_DISABLE_EVT:
break;
case BTA_HF_CLIENT_REGISTER_EVT:
btif_hf_client_cb.handle = p_data->reg.handle;
break;
case BTA_HF_CLIENT_OPEN_EVT:
if (p_data->open.status == BTA_HF_CLIENT_SUCCESS) {
bdcpy(btif_hf_client_cb.connected_bda.address, p_data->open.bd_addr);
btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_CONNECTED;
btif_hf_client_cb.peer_feat = 0;
btif_hf_client_cb.chld_feat = 0;
// clear_phone_state();
} else if (btif_hf_client_cb.state ==
BTHF_CLIENT_CONNECTION_STATE_CONNECTING) {
btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
} else {
BTIF_TRACE_WARNING(
"%s: HF CLient open failed, but another device connected. "
"status=%d state=%d connected device=%s",
__func__, p_data->open.status, btif_hf_client_cb.state,
bdaddr_to_string(&btif_hf_client_cb.connected_bda, bdstr,
sizeof(bdstr)));
break;
}
HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
btif_hf_client_cb.state, 0, 0,
&btif_hf_client_cb.connected_bda);
if (btif_hf_client_cb.state == BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED)
bdsetany(btif_hf_client_cb.connected_bda.address);
if (p_data->open.status != BTA_HF_CLIENT_SUCCESS) btif_queue_advance();
break;
case BTA_HF_CLIENT_CONN_EVT:
btif_hf_client_cb.peer_feat = p_data->conn.peer_feat;
btif_hf_client_cb.chld_feat = p_data->conn.chld_feat;
btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_SLC_CONNECTED;
HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
btif_hf_client_cb.state, btif_hf_client_cb.peer_feat,
btif_hf_client_cb.chld_feat, &btif_hf_client_cb.connected_bda);
/* Inform the application about in-band ringtone */
if (btif_hf_client_cb.peer_feat & BTA_HF_CLIENT_PEER_INBAND) {
HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
}
btif_queue_advance();
break;
case BTA_HF_CLIENT_CLOSE_EVT:
btif_hf_client_cb.state = BTHF_CLIENT_CONNECTION_STATE_DISCONNECTED;
HAL_CBACK(bt_hf_client_callbacks, connection_state_cb,
btif_hf_client_cb.state, 0, 0,
&btif_hf_client_cb.connected_bda);
bdsetany(btif_hf_client_cb.connected_bda.address);
btif_hf_client_cb.peer_feat = 0;
btif_hf_client_cb.chld_feat = 0;
btif_queue_advance();
break;
case BTA_HF_CLIENT_IND_EVT:
process_ind_evt(&p_data->ind);
break;
case BTA_HF_CLIENT_MIC_EVT:
HAL_CBACK(bt_hf_client_callbacks, volume_change_cb,
BTHF_CLIENT_VOLUME_TYPE_MIC, p_data->val.value);
break;
case BTA_HF_CLIENT_SPK_EVT:
HAL_CBACK(bt_hf_client_callbacks, volume_change_cb,
BTHF_CLIENT_VOLUME_TYPE_SPK, p_data->val.value);
break;
case BTA_HF_CLIENT_VOICE_REC_EVT:
HAL_CBACK(bt_hf_client_callbacks, vr_cmd_cb,
(bthf_client_vr_state_t)p_data->val.value);
break;
case BTA_HF_CLIENT_OPERATOR_NAME_EVT:
HAL_CBACK(bt_hf_client_callbacks, current_operator_cb,
p_data->operator_name.name);
break;
case BTA_HF_CLIENT_CLIP_EVT:
HAL_CBACK(bt_hf_client_callbacks, clip_cb, p_data->number.number);
break;
case BTA_HF_CLIENT_BINP_EVT:
HAL_CBACK(bt_hf_client_callbacks, last_voice_tag_number_callback,
p_data->number.number);
break;
case BTA_HF_CLIENT_CCWA_EVT:
HAL_CBACK(bt_hf_client_callbacks, call_waiting_cb, p_data->number.number);
break;
case BTA_HF_CLIENT_AT_RESULT_EVT:
HAL_CBACK(bt_hf_client_callbacks, cmd_complete_cb,
(bthf_client_cmd_complete_t)p_data->result.type,
p_data->result.cme);
break;
case BTA_HF_CLIENT_CLCC_EVT:
HAL_CBACK(bt_hf_client_callbacks, current_calls_cb, p_data->clcc.idx,
p_data->clcc.inc ? BTHF_CLIENT_CALL_DIRECTION_INCOMING
: BTHF_CLIENT_CALL_DIRECTION_OUTGOING,
(bthf_client_call_state_t)p_data->clcc.status,
p_data->clcc.mpty ? BTHF_CLIENT_CALL_MPTY_TYPE_MULTI
: BTHF_CLIENT_CALL_MPTY_TYPE_SINGLE,
p_data->clcc.number_present ? p_data->clcc.number : NULL);
break;
case BTA_HF_CLIENT_CNUM_EVT:
if (p_data->cnum.service == 4) {
HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
p_data->cnum.number, BTHF_CLIENT_SERVICE_VOICE);
} else if (p_data->cnum.service == 5) {
HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
p_data->cnum.number, BTHF_CLIENT_SERVICE_FAX);
} else {
HAL_CBACK(bt_hf_client_callbacks, subscriber_info_cb,
p_data->cnum.number, BTHF_CLIENT_SERVICE_UNKNOWN);
}
break;
case BTA_HF_CLIENT_BTRH_EVT:
if (p_data->val.value <= BTRH_CLIENT_RESP_AND_HOLD_REJECT) {
HAL_CBACK(bt_hf_client_callbacks, resp_and_hold_cb,
(bthf_client_resp_and_hold_t)p_data->val.value);
}
break;
case BTA_HF_CLIENT_BSIR_EVT:
if (p_data->val.value != 0) {
HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
BTHF_CLIENT_IN_BAND_RINGTONE_PROVIDED);
} else {
HAL_CBACK(bt_hf_client_callbacks, in_band_ring_tone_cb,
BTHF_CLIENT_IN_BAND_RINGTONE_NOT_PROVIDED);
}
break;
case BTA_HF_CLIENT_AUDIO_OPEN_EVT:
HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
BTHF_CLIENT_AUDIO_STATE_CONNECTED,
&btif_hf_client_cb.connected_bda);
break;
case BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT:
HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
BTHF_CLIENT_AUDIO_STATE_CONNECTED_MSBC,
&btif_hf_client_cb.connected_bda);
break;
case BTA_HF_CLIENT_AUDIO_CLOSE_EVT:
HAL_CBACK(bt_hf_client_callbacks, audio_state_cb,
BTHF_CLIENT_AUDIO_STATE_DISCONNECTED,
&btif_hf_client_cb.connected_bda);
break;
case BTA_HF_CLIENT_RING_INDICATION:
HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb);
break;
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
break;
}
}
/*******************************************************************************
*
* Function bte_hf_client_evt
*
* Description Switches context from BTE to BTIF for all HF Client events
*
* Returns void
*
******************************************************************************/
static void bte_hf_client_evt(tBTA_HF_CLIENT_EVT event,
tBTA_HF_CLIENT* p_data) {
bt_status_t status;
/* switch context to btif task context (copy full union size for convenience)
*/
status = btif_transfer_context(btif_hf_client_upstreams_evt, (uint16_t)event,
(char*)p_data, sizeof(*p_data), NULL);
/* catch any failed context transfers */
ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
}
/*******************************************************************************
*
* Function btif_hf_client_execute_service
*
* Description Initializes/Shuts down the service
*
* Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
*
******************************************************************************/
bt_status_t btif_hf_client_execute_service(bool b_enable) {
BTIF_TRACE_EVENT("%s enable:%d", __func__, b_enable);
osi_property_get("ro.bluetooth.hfp.ver", btif_hf_client_version, "1.5");
if (b_enable) {
/* Enable and register with BTA-HFClient */
BTA_HfClientEnable(bte_hf_client_evt);
if (strcmp(btif_hf_client_version, "1.6") == 0) {
BTIF_TRACE_EVENT("Support Codec Nego. %d ", BTIF_HF_CLIENT_FEATURES);
BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, BTIF_HF_CLIENT_FEATURES,
BTIF_HF_CLIENT_SERVICE_NAME);
} else {
BTIF_TRACE_EVENT("No Codec Nego Supported");
btif_hf_client_features = BTIF_HF_CLIENT_FEATURES;
btif_hf_client_features =
btif_hf_client_features & (~BTA_HF_CLIENT_FEAT_CODEC);
BTIF_TRACE_EVENT("btif_hf_client_features is %d",
btif_hf_client_features);
BTA_HfClientRegister(BTIF_HF_CLIENT_SECURITY, btif_hf_client_features,
BTIF_HF_CLIENT_SERVICE_NAME);
}
} else {
BTA_HfClientDeregister(btif_hf_client_cb.handle);
BTA_HfClientDisable();
}
return BT_STATUS_SUCCESS;
}
/*******************************************************************************
*
* Function btif_hf_get_interface
*
* Description Get the hf callback interface
*
* Returns bthf_interface_t
*
******************************************************************************/
const bthf_client_interface_t* btif_hf_client_get_interface(void) {
BTIF_TRACE_EVENT("%s", __func__);
return &bthfClientInterface;
}