Only Support single AG control block.
host/bluedroid/bta/av/include
host/bluedroid/bta/dm/include
host/bluedroid/bta/gatt/include
+ host/bluedroid/bta/hf_ag/include
host/bluedroid/bta/hf_client/include
host/bluedroid/bta/hh/include
host/bluedroid/bta/jv/include
"host/bluedroid/api/esp_gatt_common_api.c"
"host/bluedroid/api/esp_gattc_api.c"
"host/bluedroid/api/esp_gatts_api.c"
+ "host/bluedroid/api/esp_hf_ag_api.c"
"host/bluedroid/api/esp_hf_client_api.c"
"host/bluedroid/api/esp_spp_api.c"
"host/bluedroid/bta/ar/bta_ar.c"
"host/bluedroid/bta/jv/bta_jv_api.c"
"host/bluedroid/bta/jv/bta_jv_cfg.c"
"host/bluedroid/bta/jv/bta_jv_main.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_act.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_api.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_at.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_cfg.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_cmd.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_main.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_rfc.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_sco.c"
+ "host/bluedroid/bta/hf_ag/bta_ag_sdp.c"
"host/bluedroid/bta/hf_client/bta_hf_client_act.c"
"host/bluedroid/bta/hf_client/bta_hf_client_api.c"
"host/bluedroid/bta/hf_client/bta_hf_client_at.c"
"host/bluedroid/btc/profile/std/a2dp/btc_av.c"
"host/bluedroid/btc/profile/std/avrc/btc_avrc.c"
"host/bluedroid/btc/profile/std/avrc/bta_avrc_co.c"
+ "host/bluedroid/btc/profile/std/hf_ag/bta_ag_co.c"
+ "host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c"
"host/bluedroid/btc/profile/std/hf_client/btc_hf_client.c"
"host/bluedroid/btc/profile/std/hf_client/bta_hf_client_co.c"
"host/bluedroid/btc/profile/std/gap/btc_gap_ble.c"
#if (BTC_SPP_INCLUDED == TRUE)
#include "btc_spp.h"
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
+#if BTC_HF_INCLUDED
+#include "btc_hf_ag.h"
+#endif/* #if BTC_HF_INCLUDED */
#if BTC_HF_CLIENT_INCLUDED
#include "btc_hf_client.h"
#endif /* #if BTC_HF_CLIENT_INCLUDED */
#if (BTC_SPP_INCLUDED == TRUE)
[BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler },
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
+#if BTC_HF_INCLUDED
+ [BTC_PID_HF] = {btc_hf_call_handler, btc_hf_cb_handler},
+#endif /* #if BTC_HF_INCLUDED */
#if BTC_HF_CLIENT_INCLUDED
[BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler},
#endif /* #if BTC_HF_CLIENT_INCLUDED */
BTC_PID_AVRC_CT,
BTC_PID_AVRC_TG,
BTC_PID_SPP,
+#if (BTC_HF_INCLUDED == TRUE)
+ BTC_PID_HF,
+#endif /* BTC_HF_INCLUDED */
#if (BTC_HF_CLIENT_INCLUDED == TRUE)
BTC_PID_HF_CLIENT,
#endif /* BTC_HF_CLIENT_INCLUDED */
COMPONENT_PRIV_INCLUDEDIRS += host/bluedroid/bta/include \
host/bluedroid/bta/ar/include \
host/bluedroid/bta/av/include \
+ host/bluedroid/bta/hf_ag/include \
host/bluedroid/bta/hf_client/include \
host/bluedroid/bta/dm/include \
host/bluedroid/bta/gatt/include \
host/bluedroid/bta/ar \
host/bluedroid/bta/sys \
host/bluedroid/bta/jv \
+ host/bluedroid/bta/hf_ag \
host/bluedroid/bta/hf_client \
host/bluedroid/bta \
host/bluedroid/btif \
host/bluedroid/btc/profile/std/a2dp \
host/bluedroid/btc/profile/std/avrc \
host/bluedroid/btc/profile/std/spp \
+ host/bluedroid/btc/profile/std/hf_ag \
host/bluedroid/btc/profile/std/hf_client \
host/bluedroid/btc/profile \
host/bluedroid/stack/btm \
config BT_HFP_CLIENT_ENABLE
bool "Hands Free Unit"
+
+ config BT_HFP_AG_ENABLE
+ bool "Audio Gateway"
endchoice
choice BT_HFP_AUDIO_DATA_PATH
--- /dev/null
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "bt_common.h"
+#include "btc/btc_common.h"
+#include "btc/btc_dm.h"
+#include "btc_hf_ag.h"
+#include "btc/btc_profile_queue.h"
+#include "btc/btc_manage.h"
+#include "btc/btc_util.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_api.h"
+#include "common/bt_target.h"
+#include "common/bt_defs.h"
+#include "device/bdaddr.h"
+#include "esp_bt.h"
+#include "esp_hf_ag_api.h"
+#include "esp_err.h"
+#include "esp_bt_main.h"
+#include "osi/allocator.h"
+
+#if (BTC_HF_INCLUDED == TRUE)
+esp_err_t esp_bt_hf_register_callback(esp_hf_cb_t callback)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ if (callback == NULL) {
+ return ESP_FAIL;
+ }
+ btc_profile_cb_set(BTC_PID_HF, callback);
+ return ESP_OK;
+}
+
+esp_err_t esp_bt_hf_init(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_INIT_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.init), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_deinit(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_DEINIT_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.deinit), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_connect(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CONNECT_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.connect), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_disconnect(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_DISCONNECT_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.disconnect), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_connect_audio(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CONNECT_AUDIO_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.connect_audio), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_disconnect_audio(esp_bd_addr_t remote_addr)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_DISCONNECT_AUDIO_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.disconnect_audio), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_vra(esp_bd_addr_t remote_addr, esp_hf_vr_state_t value)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_VRA_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ arg.vra_rep.value = value;
+ memcpy(&(arg.volcon.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_volume_control(esp_bd_addr_t remote_addr, esp_hf_volume_control_target_t type, int volume)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_VOLUME_CONTROL_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ arg.volcon.target_type = type;
+ arg.volcon.volume = volume;
+ memcpy(&(arg.volcon.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_hf_unat_response(esp_bd_addr_t remote_addr, char *unat)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_UNAT_RESPONSE_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ arg.unat_rep.unat = unat;
+ memcpy(&(arg.unat_rep.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_cmee_response(esp_bd_addr_t remote_addr, esp_hf_at_response_code_t response_code, esp_hf_cme_err_t error_code)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CME_ERR_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ arg.ext_at.response_code = response_code;
+ arg.ext_at.error_code = error_code;
+ memcpy(&(arg.ext_at.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_indchange_notification(esp_bd_addr_t remote_addr,
+ esp_hf_call_status_t call_state,
+ esp_hf_call_setup_status_t call_setup_state,
+ esp_hf_network_state_t ntk_state, int signal)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_IND_NOTIFICATION_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.ind_change.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.ind_change.call_state = call_state;
+ arg.ind_change.call_setup_state = call_setup_state;
+ arg.ind_change.ntk_state = ntk_state;
+ arg.ind_change.signal = signal;
+
+ /* Switch to BTC context */
+ bt_status_t state = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (state == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_cind_response(esp_bd_addr_t remote_addr,
+ esp_hf_call_status_t call_state,
+ esp_hf_call_setup_status_t call_setup_state,
+ esp_hf_network_state_t ntk_state, int signal, esp_hf_roaming_status_t roam, int batt_lev,
+ esp_hf_call_held_status_t call_held_status)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CIND_RESPONSE_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.cind_rep.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.cind_rep.call_state = call_state;
+ arg.cind_rep.call_setup_state = call_setup_state;
+ arg.cind_rep.ntk_state = ntk_state;
+ arg.cind_rep.signal = signal;
+ arg.cind_rep.roam = roam;
+ arg.cind_rep.batt_lev = batt_lev;
+ arg.cind_rep.call_held_state = call_held_status;
+
+ /* Switch to BTC context */
+ bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_cops_response(esp_bd_addr_t remote_addr, char *name)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_COPS_RESPONSE_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.cops_rep.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.cops_rep.name = name; //deep_copy
+
+ /* Switch to BTC context */
+ bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_clcc_response(esp_bd_addr_t remote_addr, int index, esp_hf_current_call_direction_t dir,
+ esp_hf_current_call_status_t current_call_state, esp_hf_current_call_mode_t mode,
+ esp_hf_current_call_mpty_type_t mpty, char *number, esp_hf_call_addr_type_t type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CLCC_RESPONSE_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.clcc_rep.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ //mandatory args
+ arg.clcc_rep.index = index;
+ arg.clcc_rep.dir = dir;
+ arg.clcc_rep.current_call_state = current_call_state;
+ arg.clcc_rep.mode = mode;
+ arg.clcc_rep.mpty = mpty;
+ // option args
+ arg.clcc_rep.number = number; //deep_copy
+ arg.clcc_rep.type = type;
+
+ /* Switch to BTC context */
+ bt_status_t stat = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (stat == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_cnum_response(esp_bd_addr_t remote_addr, char *number, esp_hf_subscriber_service_type_t type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_CNUM_RESPONSE_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.cnum_rep), remote_addr, sizeof(esp_bd_addr_t));
+ arg.cnum_rep.number = number; //deep_copy
+ arg.cnum_rep.type = type;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_bsir(esp_bd_addr_t remote_addr, esp_hf_in_band_ring_state_t state)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_INBAND_RING_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.bsir.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.bsir.state = state;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_answer_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_AC_INCALL_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.phone.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.phone.num_active = num_active;
+ arg.phone.num_held = num_held;
+ arg.phone.call_state = call_state;
+ arg.phone.call_setup_state = call_setup_state;
+ arg.phone.number = number; //deep_copy
+ arg.phone.call_addr_type = call_addr_type;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_reject_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_RJ_INCALL_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.phone.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.phone.num_active = num_active;
+ arg.phone.num_held = num_held;
+ arg.phone.call_state = call_state;
+ arg.phone.call_setup_state = call_setup_state;
+ arg.phone.number = number; //deep_copy
+ arg.phone.call_addr_type = call_addr_type;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_end_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_END_CALL_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.phone.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.phone.num_active = num_active;
+ arg.phone.num_held = num_held;
+ arg.phone.call_state = call_state;
+ arg.phone.call_setup_state = call_setup_state;
+ arg.phone.number = number; //deep_copy
+ arg.phone.call_addr_type = call_addr_type;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_out_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_OUT_CALL_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ memcpy(&(arg.phone.remote_addr), remote_addr, sizeof(esp_bd_addr_t));
+ arg.phone.num_active = num_active;
+ arg.phone.num_held = num_held;
+ arg.phone.call_state = call_state;
+ arg.phone.call_setup_state = call_setup_state;
+ arg.phone.number = number; //deep_copy
+ arg.phone.call_addr_type = call_addr_type;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), btc_hf_arg_deep_copy);
+ return (status = BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+esp_err_t esp_bt_hf_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send)
+{
+ if (esp_bluedroid_get_status() != ESP_BLUEDROID_STATUS_ENABLED) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CALL;
+ msg.pid = BTC_PID_HF;
+ msg.act = BTC_HF_REGISTER_DATA_CALLBACK_EVT;
+
+ btc_hf_args_t arg;
+ memset(&arg, 0, sizeof(btc_hf_args_t));
+ arg.reg_data_cb.recv = recv;
+ arg.reg_data_cb.send = send;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, &arg, sizeof(btc_hf_args_t), NULL);
+ return (status == BT_STATUS_SUCCESS) ? ESP_OK : ESP_FAIL;
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+void esp_hf_outgoing_data_ready(void)
+{
+ BTA_AgCiData();
+}
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+#endif // BTC_HF_INCLUDED
\ No newline at end of file
--- /dev/null
+// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
+//
+// 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.
+
+#ifndef __ESP_HF_AG_API_H__
+#define __ESP_HF_AG_API_H__
+
+#include "esp_err.h"
+#include "esp_bt_defs.h"
+#include "esp_hf_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* features masks of HF AG */
+#define ESP_HF_PEER_FEAT_3WAY 0x01 /* Three-way calling */
+#define ESP_HF_PEER_FEAT_ECNR 0x02 /* Echo cancellation and/or noise reduction */
+#define ESP_HF_PEER_FEAT_VREC 0x04 /* Voice recognition */
+#define ESP_HF_PEER_FEAT_INBAND 0x08 /* In-band ring tone */
+#define ESP_HF_PEER_FEAT_VTAG 0x10 /* Attach a phone number to a voice tag */
+#define ESP_HF_PEER_FEAT_REJECT 0x20 /* Ability to reject incoming call */
+#define ESP_HF_PEER_FEAT_ECS 0x40 /* Enhanced Call Status */
+#define ESP_HF_PEER_FEAT_ECC 0x80 /* Enhanced Call Control */
+#define ESP_HF_PEER_FEAT_EXTERR 0x100 /* Extended error codes */
+#define ESP_HF_PEER_FEAT_CODEC 0x200 /* Codec Negotiation */
+
+/* CHLD feature masks of HF AG */
+#define ESP_HF_CHLD_FEAT_REL 0x01 /* 0 Release waiting call or held calls */
+#define ESP_HF_CHLD_FEAT_REL_ACC 0x02 /* 1 Release active calls and accept other waiting or held call */
+#define ESP_HF_CHLD_FEAT_REL_X 0x04 /* 1x Release specified active call only */
+#define ESP_HF_CHLD_FEAT_HOLD_ACC 0x08 /* 2 Active calls on hold and accept other waiting or held call */
+#define ESP_HF_CHLD_FEAT_PRIV_X 0x10 /* 2x Request private mode with specified call(put the rest on hold) */
+#define ESP_HF_CHLD_FEAT_MERGE 0x20 /* 3 Add held call to multiparty */
+#define ESP_HF_CHLD_FEAT_MERGE_DETACH 0x40 /* 4 Connect two calls and leave(disconnect from multiparty) */
+
+/// HF callback events
+typedef enum
+{
+ ESP_HF_CONNECTION_STATE_EVT = 0, /*!< Connection state changed event */
+ ESP_HF_AUDIO_STATE_EVT, /*!< Audio connection state change event */
+ ESP_HF_BVRA_EVT, /*!< Voice recognition state change event */
+ ESP_HF_VOLUME_CONTROL_EVT, /*!< Audio volume control command from HF Client, provided by +VGM or +VGS message */
+
+ ESP_HF_UNAT_RESPONSE_EVT, /*!< Unknown AT cmd Response*/
+ ESP_HF_CIND_RESPONSE_EVT, /*!< Call And Device Indicator Response*/
+ ESP_HF_COPS_RESPONSE_EVT, /*!< Current operator information */
+ ESP_HF_CLCC_RESPONSE_EVT, /*!< List of current calls notification */
+ ESP_HF_CNUM_RESPONSE_EVT, /*!< Subscriber information response from HF Client */
+ ESP_HF_VTS_RESPONSE_EVT, /*!< Enable or not DTMF */
+ ESP_HF_NREC_RESPONSE_EVT, /*!< Enable or not NREC */
+
+ ESP_HF_ATA_RESPONSE_EVT, /*!< Answer an Incoming Call */
+ ESP_HF_CHUP_RESPONSE_EVT, /*!< Reject an Incoming Call */
+ ESP_HF_DIAL_EVT, /*!< Origin an outgoing call with specific number or the dial the last number */
+ ESP_HF_BAC_RESPONSE_EVT, /*!< Codec Negotiation */
+ ESP_HF_BCS_RESPONSE_EVT, /*!< Codec Negotiation */
+} esp_hf_cb_event_t;
+
+// HF callback parameters of corresponding esp event in esp_hf_cb_event_t
+typedef union
+{
+ /**
+ * @brief ESP_HS_CONNECTION_STATE_EVT
+ */
+ struct hf_conn_stat_param {
+ esp_bd_addr_t remote_bda; /*!< remote bluetooth device address */
+ esp_hf_connection_state_t state; /*!< HF connection state */
+ uint32_t peer_feat; /*!< AG supported features */
+ uint32_t chld_feat; /*!< AG supported features on call hold and multiparty services */
+ } conn_stat; /*!< AG callback param of ESP_AG_CONNECTION_STATE_EVT */
+
+ /**
+ * @brief ESP_HF_AUDIO_STATE_EVT
+ */
+ struct hf_audio_stat_param {
+ esp_bd_addr_t remote_addr; /*!< remote bluetooth device address */
+ esp_hf_audio_state_t state; /*!< audio connection state */
+ } audio_stat; /*!< AG callback param of ESP_AG_AUDIO_STATE_EVT */
+
+ /**
+ * @brief ESP_HF_BVRA_EVT
+ */
+ struct hf_bvra_param {
+ esp_bd_addr_t remote_addr;
+ esp_hf_vr_state_t value; /*!< voice recognition state */
+ } vra_rep; /*!< AG callback param of ESP_AG_BVRA_EVT */
+
+ /**
+ * @brief ESP_HF_VOLUME_CONTROL_EVT
+ */
+ struct hf_volume_control_param {
+ esp_hf_volume_type_t type; /*!< volume control target, speaker or microphone */
+ int volume; /*!< gain, ranges from 0 to 15 */
+ } volume_control; /*!< AG callback param of ESP_AG_VOLUME_CONTROL_EVT */
+
+ /**
+ * @brief ESP_HF_UNAT_RESPOSNE_EVT
+ */
+ struct hf_unat_param {
+ char *unat;
+ }unat_rep;
+
+ /**
+ * @brief ESP_HF_AT_RESPONSE_EVT
+ */
+ struct hf_at_code_param {
+ esp_hf_at_response_code_t code; /*!< AT response code */
+ esp_hf_cme_err_t cme; /*!< Extended Audio Gateway Error Result Code */
+ } at; /*!< AG callback param of ESP_HF_EXT_AT_EVT */
+
+ /**
+ * @brief ESP_HF_CIND_CALL_EVT
+ */
+ struct hf_cind_param {
+ esp_hf_call_status_t call_status; /*!< call status indicator */
+ esp_hf_call_setup_status_t call_setup_status; /*!< call setup status indicator */
+ esp_hf_network_state_t svc; /*!< bluetooth proprietary call hold status indicator */
+ int signal_strength; /*!< bluetooth proprietary call hold status indicator */
+ esp_hf_roaming_status_t roam; /*!< bluetooth proprietary call hold status indicator */
+ int battery_level; /*!< battery charge value, ranges from 0 to 5 */
+ esp_hf_call_held_status_t call_held_status; /*!< bluetooth proprietary call hold status indicator */
+ } cind;
+
+ /**
+ * @brief ESP_HF_VTS_RESPOSNE_EVT
+ */
+ struct hf_vts_param {
+ char *code;
+ }vts_rep;
+
+ /**
+ * @brief ESP_HF_NREC_RESPOSNE_EVT
+ */
+ struct hf_nrec_param {
+ esp_hf_nrec_t state;
+ } nrec;
+
+ struct hf_outcall_param {
+ esp_bd_addr_t remote_addr;
+ char *num_or_loc;
+ } out_call;
+
+ /**
+ * @brief ESP_HF_BSIR_EVT
+ */
+ struct hf_bsir_param {
+ esp_bd_addr_t remote_addr;
+ esp_hf_in_band_ring_state_t state; /*!< setting state of in-band ring tone */
+ } bsir;
+
+ /**
+ * @brief ESP_HF_BCS_RESPONSE_EVT
+ */
+ struct hf_codec_param {
+ esp_hf_wbs_config_t mode;
+ } codec;
+
+} esp_hf_cb_param_t;
+
+/**
+ * @brief AG incoming data callback function, the callback is useful in case of
+ * Voice Over HCI.
+ * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
+ * buffer is allocated inside bluetooth protocol stack and will be released after
+ * invoke of the callback is finished.
+ * @param[in] len : size(in bytes) in buf
+ */
+typedef void (* esp_hf_incoming_data_cb_t)(const uint8_t *buf, uint32_t len);
+
+/**
+ * @brief AG outgoing data callback function, the callback is useful in case of
+ * Voice Over HCI. Once audio connection is set up and the application layer has
+ * prepared data to send, the lower layer will call this function to read data
+ * and then send. This callback is supposed to be implemented as non-blocking,
+ * and if data is not enough, return value 0 is supposed.
+ *
+ * @param[in] buf : pointer to incoming data(payload of HCI synchronous data packet), the
+ * buffer is allocated inside bluetooth protocol stack and will be released after
+ * invoke of the callback is finished.
+ * @param[in] len : size(in bytes) in buf
+ * @param[out] length of data successfully read
+ */
+typedef uint32_t (* esp_hf_outgoing_data_cb_t) (uint8_t *buf, uint32_t len);
+
+/**
+ * @brief HF AG callback function type
+ *
+ * @param event : Event type
+ *
+ * @param param : Pointer to callback parameter
+ */
+typedef void (* esp_hf_cb_t) (esp_hf_cb_event_t event, esp_hf_cb_param_t *param);
+
+/************************************************************************************
+** ESP HF API
+************************************************************************************/
+/**
+ * @brief Register application callback function to HFP client module. This function should be called
+ * only after esp_bluedroid_enable() completes successfully, used by HFP client
+ *
+ * @param[in] callback: HFP AG event callback function
+ *
+ * @return
+ * - ESP_OK: success
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: if callback is a NULL function pointer
+ *
+ */
+esp_err_t esp_bt_hf_register_callback(esp_hf_cb_t callback);
+
+/**
+ *
+ * @brief Initialize the bluetooth HF AG module. This function should be called
+ * after esp_bluedroid_enable() completes successfully
+ *
+ * @return
+ * - ESP_OK: if the initialization request is sent successfully
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_init(esp_bd_addr_t remote_addr);
+
+/**
+ *
+ * @brief De-initialize for HF AG module. This function
+ * should be called only after esp_bluedroid_enable() completes successfully
+ *
+ * @return
+ * - ESP_OK: success
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_deinit(esp_bd_addr_t remote_addr);
+
+/**
+ *
+ * @brief Connect to remote bluetooth HFP client device, must after esp_bt_hf_init()
+ *
+ * @param[in] remote_bda: remote bluetooth HFP client device address
+ *
+ * @return
+ * - ESP_OK: connect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_connect(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief Disconnect from the remote HFP client
+ *
+ * @param[in] remote_bda: remote bluetooth device address
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_disconnect(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief Create audio connection with remote HFP client. As a precondition to use this API,
+ * Service Level Connection shall exist between HF client and AG.
+ *
+ * @param[in] remote_bda: remote bluetooth device address
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_connect_audio(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief Release the established audio connection with remote HFP client.
+ *
+ * @param[in] remote_bda: remote bluetooth device address
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_disconnect_audio(esp_bd_addr_t remote_bda);
+
+/**
+ *
+ * @brief Response of Volume Recognition Command(AT+VRA) from HFP client. As a precondition to use this API,
+ * Service Level Connection shall exist with HFP client.
+ *
+ * @param[in] remote: volume control target, speaker or microphone
+ * @param[in] volume: gain of the speaker of microphone, ranges 0 to 15
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_vra(esp_bd_addr_t remote_bda, esp_hf_vr_state_t value);
+
+/**
+ *
+ * @brief Volume synchronization with HFP client. As a precondition to use this API,
+ * Service Level Connection shall exist with HFP client
+ *
+ * @param[in] type: volume control target, speaker or microphone
+ * @param[in] volume: gain of the speaker of microphone, ranges 0 to 15
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_volume_control(esp_bd_addr_t remote_bda, esp_hf_volume_control_target_t type, int volume);
+
+ /**
+ *
+ * @brief Handle Unknown AT command from HFP Client.
+ * As a precondition to use this API, Service Level Connection shall exist between AG and HF Client
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_hf_unat_response(esp_bd_addr_t remote_addr, char *unat);
+
+ /**
+ *
+ * @brief Unsolicited send extend AT error code to HFP Client.
+ * As a precondition to use this API, Service Level Connection shall exist between AG and HF Client
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_cmee_response(esp_bd_addr_t remote_bda, esp_hf_at_response_code_t response_code, esp_hf_cme_err_t error_code);
+
+ /**
+ *
+ * @brief Usolicited send device status notificationto HFP Client.
+ * As a precondition to use this API, Service Level Connection shall exist between AG and HF Client
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_indchange_notification(esp_bd_addr_t remote_addr, esp_hf_call_status_t call_state,
+ esp_hf_call_setup_status_t call_setup_state,
+ esp_hf_network_state_t ntk_state, int signal);
+
+ /**
+ *
+ * @brief Response to device individual indicatiors to HFP Client.
+ * As a precondition to use this API, Service Level Connection shall exist between AG and HF Client.
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_cind_response(esp_bd_addr_t remote_addr,
+ esp_hf_call_status_t call_state,
+ esp_hf_call_setup_status_t call_setup_state,
+ esp_hf_network_state_t ntk_state, int signal, esp_hf_roaming_status_t roam, int batt_lev,
+ esp_hf_call_held_status_t call_held_status);
+
+/**
+ *
+ * @brief Query the name of currently selected network operator in AG,
+ * As a precondition to use this API, Service Level Connection shall exist with HFP Client
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_cops_response(esp_bd_addr_t remote_addr, char *name);
+
+/**
+ *
+ * @brief Response to Query list of current calls from HFP Client (use AT+CLCC command),
+ * As a precondition to use this API, Service Level Connection shall exist between AG and HF Client
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_clcc_response(esp_bd_addr_t remote_addr, int index, esp_hf_current_call_direction_t dir,
+ esp_hf_current_call_status_t current_call_state, esp_hf_current_call_mode_t mode,
+ esp_hf_current_call_mpty_type_t mpty, char *number, esp_hf_call_addr_type_t type);
+
+/**
+ *
+ * @brief Get subscriber information number from HFP client(send AT+CNUM command),
+ * As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_cnum_response(esp_bd_addr_t remote_addr, char *number, esp_hf_subscriber_service_type_t type);
+
+/**
+ *
+ * @brief Inform HF Client of Provided or not Inband Ring Tone.
+ * As a precondition to use this API, Service Level Connection shall exist with AG
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_bsir(esp_bd_addr_t remote_addr, esp_hf_in_band_ring_state_t state);
+
+/**
+ *
+ * @brief Answer Incoming Call by AG or response to the AT+A command from Hands-Free Unit.
+ * As a precondition to use this API, Service Level Connection shall exist with AG.
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_answer_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type);
+
+/**
+ *
+ * @brief Reject Incoming Call by AG or response to the AT+CHUP command from Hands-Free Unit.
+ * As a precondition to use this API, Service Level Connection shall exist with AG.
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_reject_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type);
+
+/**
+ *
+ * @brief Reject Incoming Call by AG or response to the AT+CHUP command from Hands-Free Unit.
+ * As a precondition to use this API, Service Level Connection shall exist with AG.
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_out_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type);
+
+/**
+ *
+ * @brief Reject Incoming Call by AG or response to the AT+CHUP command from Hands-Free Unit.
+ * As a precondition to use this API, Service Level Connection shall exist with AG.
+ *
+ * @return
+ * - ESP_OK: disconnect request is sent to lower layer
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: others
+ *
+ */
+esp_err_t esp_bt_hf_end_call(esp_bd_addr_t remote_addr, int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t call_addr_type);
+
+/**
+ * @brief Register AG data output function; the callback is only used in
+ * the case that Voice Over HCI is enabled.
+ *
+ * @param[in] recv: HFP client incoming data callback function
+ * @param[in] send: HFP client outgoing data callback function
+ *
+ * @return
+ * - ESP_OK: success
+ * - ESP_INVALID_STATE: if bluetooth stack is not yet enabled
+ * - ESP_FAIL: if callback is a NULL function pointer
+ *
+ */
+esp_err_t esp_bt_hf_register_data_callback(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send);
+
+
+/**
+ * @brief Trigger the lower-layer to fetch and send audio data. This function is only
+ * only used in the case that Voice Over HCI is enabled. Precondition is that
+ * the HFP audio connection is connected. After this function is called, lower
+ * layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data
+ *
+ */
+void esp_hf_outgoing_data_ready(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__ESP_HF_AG_API_H__
\ No newline at end of file
* @brief ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT
*/
struct hf_client_service_availability_param {
- esp_hf_service_availability_status_t status; /*!< service availability status */
+ esp_hf_network_state_t status; /*!< service availability status */
} service_availability; /*!< HF callback param of ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT */
/**
extern "C" {
#endif
+#define ESP_BT_HF_NUMBER_LEN (32)
+#define ESP_BT_HF_OPERATOR_NAME_LEN (16)
+
+#ifndef BTC_HSAG_SERVICE_NAME
+#define BTC_HSAG_SERVICE_NAME ("Headset Gateway")
+#endif
+
+#ifndef BTC_HFAG_SERVICE_NAME
+#define BTC_HFAG_SERVICE_NAME ("Handsfree Gateway")
+#endif
+
+#ifndef BTC_HF_SERVICES
+#define BTC_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK )
+#endif
+
+#ifndef BTC_HF_SERVICE_NAMES
+#define BTC_HF_SERVICE_NAMES {BTC_HSAG_SERVICE_NAME , BTC_HFAG_SERVICE_NAME}
+#endif
+
+#ifndef BTC_HF_SECURITY
+#define BTC_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
+#endif
+
+#define BTC_HF_CALL_END_TIMEOUT 6
+
+#define BTC_HF_INVALID_IDX -1
+
+/// in-band ring tone state
+typedef enum {
+ ESP_HF_IN_BAND_RINGTONE_NOT_PROVIDED = 0,
+ ESP_HF_IN_BAND_RINGTONE_PROVIDED,
+} esp_hf_in_band_ring_state_t;
+
+/// voice recognition state
+typedef enum {
+ ESP_HF_VR_STATE_DISABLED = 0, /*!< voice recognition disabled */
+ ESP_HF_VR_STATE_ENABLED, /*!< voice recognition enabled */
+} esp_hf_vr_state_t;
/// Bluetooth HFP audio volume control target
typedef enum {
ESP_HF_VOLUME_CONTROL_TARGET_MIC, /*!< microphone */
} esp_hf_volume_control_target_t;
-/// +CIND roaming status indicator values
+/// Bluetooth HFP audio connection status
typedef enum {
- ESP_HF_ROAMING_STATUS_INACTIVE = 0, /*!< roaming is not active */
- ESP_HF_ROAMING_STATUS_ACTIVE, /*!< a roaming is active */
-} esp_hf_roaming_status_t;
+ ESP_HF_AUDIO_STATE_DISCONNECTED = 0, /*!< audio connection released */
+ ESP_HF_AUDIO_STATE_CONNECTING, /*!< audio connection has been initiated */
+ ESP_HF_AUDIO_STATE_CONNECTED, /*!< audio connection is established */
+ ESP_HF_AUDIO_STATE_CONNECTED_MSBC, /*!< mSBC audio connection is established */
+} esp_hf_audio_state_t;
+
+typedef enum {
+ ESP_HF_VOLUME_TYPE_SPK = 0,
+ ESP_HF_VOLUME_TYPE_MIC
+} esp_hf_volume_type_t;
+
+/// +CIND network service availability status
+typedef enum
+{
+ ESP_HF_NETWORK_STATE_NOT_AVAILABLE = 0,
+ ESP_HF_NETWORK_STATE_AVAILABLE
+} esp_hf_network_state_t;
+
+/** +CIEV Service type */
+typedef enum
+{
+ ESP_HF_SERVICE_TYPE_HOME = 0,
+ ESP_HF_SERVICE_TYPE_ROAMING
+} esp_hf_service_type_t;
/// +CIND call status indicator values
typedef enum {
/// +CIND call setup status indicator values
typedef enum {
- ESP_HF_CALL_SETUP_STATUS_NONE = 0, /*!< no call setup in progress */
+ ESP_HF_CALL_SETUP_STATUS_IDLE = 0, /*!< no call setup in progress */
ESP_HF_CALL_SETUP_STATUS_INCOMING = 1, /*!< incoming call setup in progress */
ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING = 2, /*!< outgoing call setup in dialing state */
ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING = 3, /*!< outgoing call setup in alerting state */
} esp_hf_call_setup_status_t;
+/// +CIND roaming status indicator values
+typedef enum {
+ ESP_HF_ROAMING_STATUS_INACTIVE = 0, /*!< roaming is not active */
+ ESP_HF_ROAMING_STATUS_ACTIVE, /*!< a roaming is active */
+} esp_hf_roaming_status_t;
+
/// +CIND call held indicator values
typedef enum {
ESP_HF_CALL_HELD_STATUS_NONE = 0, /*!< no calls held */
ESP_HF_CALL_HELD_STATUS_HELD = 2, /*!< call on hold, no active call*/
} esp_hf_call_held_status_t;
-/// +CIND network service availability status
-typedef enum {
- ESP_HF_SERVICE_AVAILABILITY_STATUS_UNAVAILABLE = 0, /*!< service not available */
- ESP_HF_SERVICE_AVAILABILITY_STATUS_AVAILABLE, /*!< service available */
-} esp_hf_service_availability_status_t;
-
/// +CLCC status of the call
typedef enum {
ESP_HF_CURRENT_CALL_STATUS_ACTIVE = 0, /*!< active */
ESP_HF_BTRH_CMD_REJECT = 2, /*!< reject a held incoming call */
} esp_hf_btrh_cmd_t;
-/// response indication codes for AT commands
+/* +NREC */
+typedef enum
+{
+ ESP_HF_NREC_STOP = 0,
+ ESP_HF_NREC_START
+} esp_hf_nrec_t;
+
+///+CCWA resposne status
typedef enum {
- ESP_HF_AT_RESPONSE_CODE_OK = 0, /*!< acknowledges execution of a command line */
- ESP_HF_AT_RESPONSE_CODE_ERR, /*!< command not accepted */
- ESP_HF_AT_RESPONSE_CODE_NO_CARRIER, /*!< connection terminated */
- ESP_HF_AT_RESPONSE_CODE_BUSY, /*!< busy signal detected */
- ESP_HF_AT_RESPONSE_CODE_NO_ANSWER, /*!< connection completion timeout */
- ESP_HF_AT_RESPONSE_CODE_DELAYED, /*!< delayed */
- ESP_HF_AT_RESPONSE_CODE_BLACKLISTED, /*!< blacklisted */
- ESP_HF_AT_RESPONSE_CODE_CME, /*!< CME error */
-} esp_hf_at_response_code_t;
+ ESP_HF_CALL_WAITING_INACTIVE,
+ ESP_HF_CALL_WAITING_ACTIVE,
+} esp_hf_call_waiting_status_t;
-/// voice recognition state
+/* WBS codec setting */
+typedef enum
+{
+ ESP_HF_WBS_NONE,
+ ESP_HF_WBS_NO,
+ ESP_HF_WBS_YES
+}esp_hf_wbs_config_t;
+
+/// Bluetooth HFP RFCOMM connection and service level connection status
typedef enum {
- ESP_HF_VR_STATE_DISABLED = 0, /*!< voice recognition disabled */
- ESP_HF_VR_STATE_ENABLED, /*!< voice recognition enabled */
-} esp_hf_vr_state_t;
+ ESP_HF_CONNECTION_STATE_DISCONNECTED = 0, /*!< RFCOMM data link channel released */
+ ESP_HF_CONNECTION_STATE_CONNECTING, /*!< connecting remote device on the RFCOMM data link*/
+ ESP_HF_CONNECTION_STATE_CONNECTED, /*!< RFCOMM connection established */
+ ESP_HF_CONNECTION_STATE_SLC_CONNECTED, /*!< service level connection established */
+ ESP_HF_CONNECTION_STATE_DISCONNECTING, /*!< disconnecting with remote device on the RFCOMM data link*/
+} esp_hf_connection_state_t;
/// AT+CHLD command values
typedef enum {
ESP_HF_CHLD_TYPE_PRIV_X, /*!< <2x>, request private consultation mode with specified call */
} esp_hf_chld_type_t;
+/* AT response code - OK/Error */
+typedef enum {
+ ESP_HF_AT_RESPONSE_CODE_OK = 0, /*!< acknowledges execution of a command line */
+ ESP_HF_AT_RESPONSE_CODE_ERR, /*!< command not accepted */
+ ESP_HF_AT_RESPONSE_CODE_NO_CARRIER, /*!< connection terminated */
+ ESP_HF_AT_RESPONSE_CODE_BUSY, /*!< busy signal detected */
+ ESP_HF_AT_RESPONSE_CODE_NO_ANSWER, /*!< connection completion timeout */
+ ESP_HF_AT_RESPONSE_CODE_DELAYED, /*!< delayed */
+ ESP_HF_AT_RESPONSE_CODE_BLACKLISTED, /*!< blacklisted */
+ ESP_HF_AT_RESPONSE_CODE_CME, /*!< CME error */
+} esp_hf_at_response_code_t;
+
+/* AT response code - OK/Error */
+typedef enum {
+ ESP_HF_AT_RESPONSE_ERROR = 0,
+ ESP_HF_AT_RESPONSE_OK
+} esp_hf_at_response_t;
+
/// Extended Audio Gateway Error Result Code Response
typedef enum {
ESP_HF_CME_AG_FAILURE = 0, /*!< ag failure */
ESP_HF_CME_NETWORK_NOT_ALLOWED = 32, /*!< network not allowed --emergency calls only */
} esp_hf_cme_err_t;
+/** Callback for connection state change.
+ * state will have one of the values from BtHfConnectionState
+ */
+typedef void (* esp_hf_connection_state_callback)(esp_hf_connection_state_t state, esp_bd_addr_t *bd_addr);
+
+/** Callback for audio connection state change.
+ * state will have one of the values from BtHfAudioState
+ */
+typedef void (* esp_hf_audio_state_callback)(esp_hf_audio_state_t state, esp_bd_addr_t *bd_addr);
+
+/** Callback for VR connection state change.
+ * state will have one of the values from BtHfVRState
+ */
+typedef void (* esp_hf_vr_cmd_callback)(esp_hf_vr_state_t state, esp_bd_addr_t *bd_addr);
+
+/** Callback for answer incoming call (ATA)
+ */
+typedef void (* esp_hf_answer_call_cmd_callback)(esp_bd_addr_t *bd_addr);
+
+/** Callback for disconnect call (AT+CHUP)
+ */
+typedef void (* esp_hf_hangup_call_cmd_callback)(esp_bd_addr_t *bd_addr);
+
+/** Callback for disconnect call (AT+CHUP)
+ * type will denote Speaker/Mic gain (BtHfVolumeControl).
+ */
+typedef void (* esp_hf_volume_cmd_callback)(esp_hf_volume_control_target_t type, int volume, esp_bd_addr_t *bd_addr);
+
+/** Callback for dialing an outgoing call
+ * If number is NULL, redial
+ */
+typedef void (* esp_hf_dial_call_cmd_callback)(char *number, esp_bd_addr_t *bd_addr);
+
+/** Callback for sending DTMF tones
+ * tone contains the dtmf character to be sent
+ */
+typedef void (* esp_hf_dtmf_cmd_callback)(char tone, esp_bd_addr_t *bd_addr);
+
+/** Callback for enabling/disabling noise reduction/echo cancellation
+ * value will be 1 to enable, 0 to disable
+ */
+typedef void (* esp_hf_nrec_cmd_callback)(esp_hf_nrec_t nrec, esp_bd_addr_t *bd_addr);
+
+/** Callback for AT+BCS and event from BAC
+ * WBS enable, WBS disable
+ */
+typedef void (* esp_hf_wbs_callback)(esp_hf_wbs_config_t wbs, esp_bd_addr_t *bd_addr);
+
+/** Callback for call hold handling (AT+CHLD)
+ * value will contain the call hold command (0, 1, 2, 3)
+ */
+typedef void (* esp_hf_chld_cmd_callback)(esp_hf_chld_type_t chld, esp_bd_addr_t *bd_addr);
+
+/** Callback for CNUM (subscriber number)
+ */
+typedef void (* esp_hf_cnum_cmd_callback)(esp_bd_addr_t *bd_addr);
+
+/** Callback for indicators (CIND)
+ */
+typedef void (* esp_hf_cind_cmd_callback)(esp_bd_addr_t *bd_addr);
+
+/** Callback for operator selection (COPS)
+ */
+typedef void (* esp_hf_cops_cmd_callback)(esp_bd_addr_t *bd_addr);
+
+/** Callback for call list (AT+CLCC)
+ */
+typedef void (* esp_hf_clcc_cmd_callback) (esp_bd_addr_t *bd_addr);
+
+/** Callback for unknown AT command recd from AG
+ * at_string will contain the unparsed AT string
+ */
+typedef void (* esp_hf_unknown_at_cmd_callback)(char *at_string, esp_bd_addr_t *bd_addr);
+
+/** Callback for keypressed (HSP) event.
+ */
+typedef void (* esp_hf_key_pressed_cmd_callback)(esp_bd_addr_t *bd_addr);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains action functions for the audio gateway.
+ *
+ ******************************************************************************/
+#include <string.h>
+#include "bta_ag_int.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_ag_co.h"
+#include "stack/port_api.h"
+#include "stack/l2c_api.h"
+#include "bta_dm_int.h"
+#include "bta/bta_sdp_api.h"
+#include "bta/utl.h"
+#include "common/bt_trace.h"
+#include "osi/allocator.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* maximum length of data to read from RFCOMM */
+#define BTA_AG_RFC_READ_MAX 512
+
+/* maximum AT command length */
+#define BTA_AG_CMD_MAX 512
+
+const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX] =
+{
+ UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+ UUID_SERVCLASS_AG_HANDSFREE
+};
+
+const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX] =
+{
+ BTM_SEC_SERVICE_HEADSET_AG,
+ BTM_SEC_SERVICE_AG_HANDSFREE
+};
+
+const tBTA_SERVICE_ID bta_ag_svc_id[BTA_AG_NUM_IDX] =
+{
+ BTA_HSP_SERVICE_ID,
+ BTA_HFP_SERVICE_ID
+};
+
+const tBTA_SERVICE_MASK bta_ag_svc_mask[BTA_AG_NUM_IDX] =
+{
+ BTA_HSP_SERVICE_MASK,
+ BTA_HFP_SERVICE_MASK
+};
+
+typedef void (*tBTA_AG_ATCMD_CBACK)(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+
+const tBTA_AG_ATCMD_CBACK bta_ag_at_cback_tbl[BTA_AG_NUM_IDX] =
+{
+ bta_ag_at_hsp_cback,
+ bta_ag_at_hfp_cback
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_cback_open
+**
+** Description Send open callback event to application.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cback_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data, tBTA_AG_STATUS status)
+{
+ tBTA_AG_OPEN open;
+ /* call app callback with open event */
+ open.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ open.hdr.app_id = p_scb->app_id;
+ open.status = status;
+ open.service_id = bta_ag_svc_id[p_scb->conn_service];
+ if (p_data) {
+ /* if p_data is provided then we need to pick the bd address from the open api structure */
+ bdcpy(open.bd_addr, p_data->api_open.bd_addr);
+ } else {
+ bdcpy(open.bd_addr, p_scb->peer_addr);
+ }
+ (*bta_ag_cb.p_cback)(BTA_AG_OPEN_EVT, (tBTA_AG *) &open);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_register
+**
+** Description This function initializes values of the AG cb and sets up
+** the SDP record for the services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_REGISTER reg;
+ /* initialize control block */
+ p_scb->reg_services = p_data->api_register.services;
+ p_scb->serv_sec_mask = p_data->api_register.sec_mask;
+ p_scb->features = p_data->api_register.features;
+ p_scb->app_id = p_data->api_register.app_id;
+ /* create SDP records */
+ bta_ag_create_records(p_scb, p_data);
+ /* start RFCOMM servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+ /* call app callback with register event */
+ reg.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ reg.hdr.app_id = p_scb->app_id;
+ reg.status = BTA_AG_SUCCESS;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) ®);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_deregister
+**
+** Description This function removes the sdp records, closes the RFCOMM
+** servers, and deallocates the service control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* set dealloc */
+ p_scb->dealloc = TRUE;
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+ /* remove rfcomm servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+ /* dealloc */
+ bta_ag_scb_dealloc(p_scb);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_dereg
+**
+** Description Start a deregister event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* set dealloc */
+ p_scb->dealloc = TRUE;
+ /* remove sdp records */
+ bta_ag_del_records(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_open
+**
+** Description This starts an AG open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ BD_ADDR pending_bd_addr;
+ /* store parameters */
+ if (p_data) {
+ bdcpy(p_scb->peer_addr, p_data->api_open.bd_addr);
+ p_scb->open_services = p_data->api_open.services;
+ p_scb->cli_sec_mask = p_data->api_open.sec_mask;
+ }
+ /* Check if RFCOMM has any incoming connection to avoid collision. */
+ if (PORT_IsOpening (pending_bd_addr)) {
+ /* Let the incoming connection goes through. */
+ /* Issue collision for this scb for now. */
+ /* We will decide what to do when we find incoming connetion later. */
+ bta_ag_collision_cback (0, BTA_ID_AG, 0, p_scb->peer_addr);
+ return;
+ }
+ /* close servers */
+ bta_ag_close_servers(p_scb, p_scb->reg_services);
+ /* set role */
+ p_scb->role = BTA_AG_INT;
+ /* do service search */
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_int_res
+**
+** Description This function handles a discovery result when initiator.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 event = BTA_AG_DISC_FAIL_EVT;
+ APPL_TRACE_DEBUG ("bta_ag_disc_int_res: Status: %d", p_data->disc_result.status);
+
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ if (bta_ag_sdp_find_attr(p_scb, p_scb->open_services)) {
+ /* set connected service */
+ p_scb->conn_service = bta_ag_service_to_idx(p_scb->open_services);
+ /* send ourselves sdp ok event */
+ event = BTA_AG_DISC_OK_EVT;
+ }
+ }
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+ /* if service not found check if we should search for other service */
+ if ((event == BTA_AG_DISC_FAIL_EVT) &&
+ (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL ||
+ p_data->disc_result.status == SDP_NO_RECS_MATCH)) {
+ if ((p_scb->open_services & BTA_HFP_SERVICE_MASK) &&
+ (p_scb->open_services & BTA_HSP_SERVICE_MASK)) {
+ /* search for HSP */
+ p_scb->open_services &= ~BTA_HFP_SERVICE_MASK;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ } else if ((p_scb->open_services & BTA_HSP_SERVICE_MASK) &&
+ (p_scb->hsp_version == HSP_VERSION_1_2)) {
+ /* search for UUID_SERVCLASS_HEADSET for HSP 1.0 device */
+ p_scb->hsp_version = HSP_VERSION_1_0;
+ bta_ag_do_disc(p_scb, p_scb->open_services);
+ } else {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+ } else {
+ /* send ourselves sdp ok/fail event */
+ bta_ag_sm_execute(p_scb, event, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_acp_res
+**
+** Description This function handles a discovery result when acceptor.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* if found service */
+ if (p_data->disc_result.status == SDP_SUCCESS ||
+ p_data->disc_result.status == SDP_DB_FULL) {
+ /* get attributes */
+ bta_ag_sdp_find_attr(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+ }
+ /* free discovery db */
+ bta_ag_free_db(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_disc_fail
+**
+** Description This function handles a discovery failure.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+ /* reinitialize stuff */
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_SDP);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_open_fail
+**
+** Description open connection failed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, p_data, BTA_AG_FAIL_RESOURCES);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_fail
+**
+** Description RFCOMM connection failed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+ /* reinitialize stuff */
+ p_scb->conn_handle = 0;
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ p_scb->sco_codec = BTA_AG_CODEC_NONE;
+#endif
+ p_scb->role = 0;
+ p_scb->svc_conn = FALSE;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+ /*Clear the BD address*/
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+ /* reopen registered servers */
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+ /* call open cback w. failure */
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_FAIL_RFCOMM);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_close
+**
+** Description RFCOMM connection closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_CLOSE close;
+ tBTA_SERVICE_MASK services;
+ int i, num_active_conn = 0;
+ UNUSED(p_data);
+ /* reinitialize stuff */
+ p_scb->conn_service = 0;
+ p_scb->peer_features = 0;
+#if (BTM_WBS_INCLUDED == TRUE )
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ p_scb->sco_codec = BTA_AG_CODEC_NONE;
+ /* Clear these flags upon SLC teardown */
+ p_scb->codec_updated = FALSE;
+ p_scb->codec_fallback = FALSE;
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+ p_scb->role = 0;
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ p_scb->svc_conn = FALSE;
+ p_scb->hsp_version = HSP_VERSION_1_2;
+ bta_ag_at_reinit(&p_scb->at_cb);
+ /* stop timers */
+ bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+ close.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ close.hdr.app_id = p_scb->app_id;
+ bdcpy(close.bd_addr, p_scb->peer_addr);
+
+ bta_sys_conn_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* call close call-out */
+ // bta_ag_sco_co_close(close.hdr.handle);
+ bta_ag_sco_co_close();
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(BTA_AG_CLOSE_EVT, (tBTA_AG *) &close);
+
+ /* if not deregistering (deallocating) reopen registered servers */
+ if (p_scb->dealloc == FALSE) {
+ /* Clear peer bd_addr so instance can be reused */
+ bdcpy(p_scb->peer_addr, bd_addr_null);
+
+ /* start only unopened server */
+ services = p_scb->reg_services;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++) {
+ if (p_scb->serv_handle[i]) {
+ services &= ~((tBTA_SERVICE_MASK)1 << (BTA_HSP_SERVICE_ID + i));
+ }
+ }
+ bta_ag_start_servers(p_scb, services);
+ p_scb->conn_handle = 0;
+ /* Make sure SCO state is BTA_AG_SCO_SHUTDOWN_ST */
+ bta_ag_sco_shutdown(p_scb, NULL);
+ /* Check if all the SLCs are down */
+ for (i = 0; i < BTA_AG_NUM_SCB; i++) {
+ if (bta_ag_cb.scb[i].in_use && bta_ag_cb.scb[i].svc_conn) {
+ num_active_conn++;
+ }
+ }
+ if (!num_active_conn) {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ } else {
+ /* else close port and deallocate scb */
+ RFCOMM_RemoveServer(p_scb->conn_handle);
+ bta_ag_scb_dealloc(p_scb);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_open
+**
+** Description Handle RFCOMM channel open.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* initialize AT feature variables */
+ p_scb->clip_enabled = FALSE;
+ p_scb->ccwa_enabled = FALSE;
+ p_scb->cmer_enabled = FALSE;
+ p_scb->cmee_enabled = FALSE;
+ p_scb->inband_enabled = ((p_scb->features & BTA_AG_FEAT_INBAND) == BTA_AG_FEAT_INBAND);
+
+ /* set up AT command interpreter */
+ p_scb->at_cb.p_at_tbl = (tBTA_AG_AT_CMD *) bta_ag_at_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_cmd_cback = (tBTA_AG_AT_CMD_CBACK *) bta_ag_at_cback_tbl[p_scb->conn_service];
+ p_scb->at_cb.p_err_cback = (tBTA_AG_AT_ERR_CBACK *) bta_ag_at_err_cback;
+ p_scb->at_cb.p_user = p_scb;
+ p_scb->at_cb.cmd_max_len = BTA_AG_CMD_MAX;
+ bta_ag_at_init(&p_scb->at_cb);
+
+ /* call app open call-out */
+ bta_ag_sco_co_open(bta_ag_scb_to_idx(p_scb), p_scb->air_mode, BTA_HFP_SCO_OUT_PKT_SIZE, bta_ag_svc_id[p_scb->conn_service]);
+ bta_sys_conn_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ bta_ag_cback_open(p_scb, NULL, BTA_AG_SUCCESS);
+
+ if (p_scb->conn_service == BTA_AG_HFP) {
+ /* if hfp start timer for service level conn */
+ bta_sys_start_timer(&p_scb->act_timer, BTA_AG_SVC_TOUT_EVT, p_bta_ag_cfg->conn_tout);
+ } else {
+ /* else service level conn is open */
+ bta_ag_svc_conn_open(p_scb, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_acp_open
+**
+** Description Handle RFCOMM channel open when accepting connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 lcid;
+ int i;
+ tBTA_AG_SCB *ag_scb, *other_scb;
+ BD_ADDR dev_addr;
+ int status;
+ /* set role */
+ p_scb->role = BTA_AG_ACP;
+ APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: serv_handle0 = %d serv_handle1 = %d",
+ p_scb->serv_handle[0], p_scb->serv_handle[1]);
+ /* get bd addr of peer */
+ if (PORT_SUCCESS != (status=PORT_CheckConnection(p_data->rfc.port_handle, dev_addr, &lcid))) {
+ APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open error PORT_CheckConnection returned status %d", status);
+ }
+ /* Collision Handling */
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) {
+ if ((ag_scb->in_use) && (ag_scb->colli_tmr_on)) {
+ /* stop collision timer */
+ ag_scb->colli_tmr_on = FALSE;
+ bta_sys_stop_timer (&ag_scb->colli_timer);
+
+ if (bdcmp (dev_addr, ag_scb->peer_addr) == 0) {
+ /* If incoming and outgoing device are same, nothing more to do. */
+ /* Outgoing conn will be aborted because we have successful incoming conn. */
+ } else {
+ /* Resume outgoing connection. */
+ other_scb = bta_ag_get_other_idle_scb (p_scb);
+ if (other_scb) {
+ bdcpy(other_scb->peer_addr, ag_scb->peer_addr);
+ other_scb->open_services = ag_scb->open_services;
+ other_scb->cli_sec_mask = ag_scb->cli_sec_mask;
+ bta_ag_resume_open (other_scb);
+ }
+ }
+ break;
+ }
+ }
+ bdcpy (p_scb->peer_addr, dev_addr);
+ /* determine connected service from port handle */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: i = %d serv_handle = %d port_handle = %d",
+ i, p_scb->serv_handle[i], p_data->rfc.port_handle);
+ if (p_scb->serv_handle[i] == p_data->rfc.port_handle) {
+ p_scb->conn_service = i;
+ p_scb->conn_handle = p_data->rfc.port_handle;
+ break;
+ }
+ }
+ APPL_TRACE_DEBUG ("bta_ag_rfc_acp_open: conn_service = %d conn_handle = %d",
+ p_scb->conn_service, p_scb->conn_handle);
+ /* close any unopened server */
+ bta_ag_close_servers(p_scb, (p_scb->reg_services & ~bta_ag_svc_mask[p_scb->conn_service]));
+ /* do service discovery to get features */
+ bta_ag_do_disc(p_scb, bta_ag_svc_mask[p_scb->conn_service]);
+ /* continue with common open processing */
+ bta_ag_rfc_open(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_data
+**
+** Description Read and process data from RFCOMM.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 len;
+ char buf[BTA_AG_RFC_READ_MAX];
+ UNUSED(p_data);
+ memset(buf, 0, BTA_AG_RFC_READ_MAX);
+
+ APPL_TRACE_DEBUG("bta_ag_rfc_data");
+ /* do the following */
+ for (;;) {
+ /* read data from rfcomm; if bad status, we're done */
+ if (PORT_ReadData(p_scb->conn_handle, buf, BTA_AG_RFC_READ_MAX, &len) != PORT_SUCCESS) {
+ break;
+ }
+ /* if no data, we're done */
+ if (len == 0) {
+ break;
+ }
+ /* run AT command interpreter on data */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ bta_ag_at_parse(&p_scb->at_cb, buf, len);
+ bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ /* no more data to read, we're done */
+ if (len < BTA_AG_RFC_READ_MAX) {
+ break;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_close
+**
+** Description Start the process of closing SCO and RFCOMM connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ /* Take the link out of sniff and set L2C idle time to 0 */
+ bta_dm_pm_active(p_scb->peer_addr);
+ L2CA_SetIdleTimeoutByBdAddr(p_scb->peer_addr, 0, BT_TRANSPORT_BR_EDR);
+ /* if SCO is open close SCO and wait on RFCOMM close */
+ if (bta_ag_sco_is_open(p_scb)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_CLOSE_RFC;
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_rfc_do_close(p_scb, p_data);
+ }
+ /* Always do SCO shutdown to handle all SCO corner cases */
+ bta_ag_sco_shutdown(p_scb, p_data);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_post_sco_open
+**
+** Description Perform post-SCO open action, if any
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ switch (p_scb->post_sco) {
+ case BTA_AG_POST_SCO_RING:
+ bta_ag_send_ring(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_post_sco_close
+**
+** Description Perform post-SCO close action, if any
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ switch (p_scb->post_sco) {
+ case BTA_AG_POST_SCO_CLOSE_RFC:
+ bta_ag_rfc_do_close(p_scb, p_data);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_CONN:
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_CONN_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_ORIG:
+ bta_ag_send_call_inds(p_scb, BTA_AG_OUT_CALL_ORIG_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END:
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ break;
+
+ case BTA_AG_POST_SCO_CALL_END_INCALL:
+ {
+ bta_ag_send_call_inds(p_scb, BTA_AG_END_CALL_RES);
+ /* Sending callsetup IND and Ring were defered to after SCO close. */
+ bta_ag_send_call_inds(p_scb, BTA_AG_IN_CALL_RES);
+
+ if (bta_ag_inband_enabled(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, p_data);
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ bta_ag_send_ring(p_scb, p_data);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_svc_conn_open
+**
+** Description Service level connection opened
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_CONN evt;
+ UNUSED(p_data);
+
+ if (!p_scb->svc_conn) {
+ /* set state variable */
+ p_scb->svc_conn = TRUE;
+ /* Clear AT+BIA mask from previous SLC if any. */
+ p_scb->bia_masked_out = 0;
+ /* stop timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+ /* call callback */
+ evt.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ evt.hdr.app_id = p_scb->app_id;
+ evt.peer_feat = p_scb->peer_features;
+ bdcpy(evt.bd_addr, p_scb->peer_addr);
+#if (BTM_WBS_INCLUDED == TRUE )
+ evt.peer_codec = p_scb->peer_codecs;
+#endif
+ if ((p_scb->call_ind != BTA_AG_CALL_INACTIVE) ||
+ (p_scb->callsetup_ind != BTA_AG_CALLSETUP_NONE)) {
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ (*bta_ag_cb.p_cback)(BTA_AG_CONN_EVT, (tBTA_AG *) &evt);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_rx_data
+**
+** Description Send result code to RFCOMM
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 len;
+ tBTA_AG_CI_RX_WRITE *p_rx_write_msg = (tBTA_AG_CI_RX_WRITE *)p_data;
+ char *p_data_area = (char *)(p_rx_write_msg+1); /* Point to data area after header */
+
+ APPL_TRACE_DEBUG("bta_ag_ci_rx_data:");
+ /* send to RFCOMM */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ PORT_WriteData(p_scb->conn_handle, p_data_area, strlen(p_data_area), &len);
+ bta_sys_idle(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rcvd_slc_ready
+**
+** Description Handles SLC ready call-in in case of pass-through mode.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+ APPL_TRACE_DEBUG("bta_ag_rcvd_slc_ready: handle = %d", bta_ag_scb_to_idx(p_scb));
+
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+ /* In pass-through mode, BTA knows that SLC is ready only through call-in. */
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_setcodec
+**
+** Description Handle API SetCodec
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_PEER_CODEC codec_type = p_data->api_setcodec.codec;
+ tBTA_AG_VAL val;
+
+ /* Check if the requested codec type is valid */
+ if((codec_type != BTA_AG_CODEC_NONE) &&
+ (codec_type != BTA_AG_CODEC_CVSD) &&
+ (codec_type != BTA_AG_CODEC_MSBC)) {
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+ (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG *) &val);
+ return;
+ }
+
+ if((p_scb->peer_codecs & codec_type) || (codec_type == BTA_AG_CODEC_NONE) ||
+ (codec_type == BTA_AG_CODEC_CVSD)) {
+ p_scb->sco_codec = codec_type;
+ p_scb->codec_updated = TRUE;
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_SUCCESS;
+ APPL_TRACE_DEBUG("bta_ag_setcodec: Updated codec type %d", codec_type);
+ } else {
+ val.num = codec_type;
+ val.hdr.status = BTA_AG_FAIL_RESOURCES;
+ APPL_TRACE_ERROR("bta_ag_setcodec error: unsupported codec type %d", codec_type);
+ }
+ (*bta_ag_cb.p_cback)(BTA_AG_WBS_EVT, (tBTA_AG *) &val);
+#endif
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the implementation of the API for the audio gateway (AG)
+ * subsystem of BTA, Broadcom's Bluetooth application layer for mobile
+ * phones.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta/bta_api.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_ag_api.h"
+#include "bta_ag_int.h"
+#include "osi/allocator.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+static const tBTA_SYS_REG bta_ag_reg =
+{
+ bta_ag_hdl_event,
+ BTA_AgDisable
+};
+
+/*******************************************************************************
+**
+** Function BTA_AgEnable
+**
+** Description Enable the audio gateway service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AG_ENABLE_EVT. This function must
+** be called before other function in the AG API are
+** called.
+**
+** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback)
+{
+ tBTA_AG_API_ENABLE *p_buf;
+ UINT8 idx;
+
+ /* Error if AG is already enabled, or AG is in the middle of disabling. */
+ for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+ if (bta_ag_cb.scb[idx].in_use) {
+ APPL_TRACE_ERROR ("BTA_AgEnable: FAILED, AG already enabled.");
+ return BTA_FAILURE;
+ }
+ }
+ /* register with BTA system manager */
+ bta_sys_register(BTA_ID_AG, &bta_ag_reg);
+
+ if ((p_buf = (tBTA_AG_API_ENABLE *) osi_malloc(sizeof(tBTA_AG_API_ENABLE))) != NULL) {
+ p_buf->hdr.event = BTA_AG_API_ENABLE_EVT;
+ p_buf->parse_mode = parse_mode;
+ p_buf->p_cback = p_cback;
+ bta_sys_sendmsg(p_buf);
+ }
+ return BTA_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgDisable
+**
+** Description Disable the audio gateway service
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDisable(void)
+{
+ BT_HDR *p_buf;
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_API_DISABLE_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgRegister
+**
+** Description Register an Audio Gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,tBTA_AG_FEAT features,
+ char * p_service_names[], UINT8 app_id)
+{
+ tBTA_AG_API_REGISTER *p_buf;
+ int i;
+
+ if ((p_buf = (tBTA_AG_API_REGISTER *) osi_malloc(sizeof(tBTA_AG_API_REGISTER))) != NULL) {
+ p_buf->hdr.event = BTA_AG_API_REGISTER_EVT;
+ p_buf->features = features;
+ p_buf->sec_mask = sec_mask;
+ p_buf->services = services;
+ p_buf->app_id = app_id;
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ if(p_service_names[i]) {
+ BCM_STRNCPY_S(p_buf->p_name[i], BTA_SERVICE_NAME_LEN+1, p_service_names[i], BTA_SERVICE_NAME_LEN);
+ p_buf->p_name[i][BTA_SERVICE_NAME_LEN] = 0;
+ } else {
+ p_buf->p_name[i][0] = 0;
+ }
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgDeregister
+**
+** Description Deregister an audio gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDeregister(UINT16 handle)
+{
+ BT_HDR *p_buf;
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_API_DEREGISTER_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgOpen
+**
+** Description Opens a connection to a headset or hands-free device.
+** When connection is open callback function is called
+** with a BTA_AG_OPEN_EVT. Only the data connection is
+** opened. The audio connection is not opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services)
+{
+ tBTA_AG_API_OPEN *p_buf;
+
+ if ((p_buf = (tBTA_AG_API_OPEN *) osi_malloc(sizeof(tBTA_AG_API_OPEN))) != NULL) {
+ p_buf->hdr.event = BTA_AG_API_OPEN_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bdcpy(p_buf->bd_addr, bd_addr);
+ p_buf->services = services;
+ p_buf->sec_mask = sec_mask;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgClose
+**
+** Description Close the current connection to a headset or a handsfree
+** Any current audio connection will also be closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_API_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioOpen
+**
+** Description Opens an audio connection to the currently connected
+** headset or handsfree.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioOpen(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_API_AUDIO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioClose
+**
+** Description Close the currently active audio connection to a headset
+** or handsfree. The data connection remains open
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioClose(UINT16 handle)
+{
+ BT_HDR *p_buf;
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_API_AUDIO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function BTA_AgResult
+**
+** Description Send an AT result code to a headset or hands-free device.
+** This function is only used when the AG parse mode is set
+** to BTA_AG_PARSE.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data)
+{
+ tBTA_AG_API_RESULT *p_buf;
+
+ // printf("BTA_AgReslut: %d\n",result);
+
+ if ((p_buf = (tBTA_AG_API_RESULT *) osi_malloc(sizeof(tBTA_AG_API_RESULT))) != NULL) {
+ p_buf->hdr.event = BTA_AG_API_RESULT_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->result = result;
+ if(p_data) {
+ memcpy(&p_buf->data, p_data, sizeof(p_buf->data));
+ }
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function BTA_AgSetCodec
+**
+** Description Specify the codec type to be used for the subsequent
+** audio connection.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec)
+{
+ tBTA_AG_API_SETCODEC *p_buf;
+
+ if ((p_buf = (tBTA_AG_API_SETCODEC *) osi_malloc(sizeof(tBTA_AG_API_SETCODEC))) != NULL) {
+ p_buf->hdr.event = BTA_AG_API_SETCODEC_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->codec = codec;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/************************************************************************************************
+ * Function BTA_AgCiData
+ *
+ * Description Trigger the lower-layer to fetch and send audio data. This function is only
+ * only used in the case that Voice Over HCI is enabled. Precondition is that
+ * the HFP audio connection is connected. After this function is called, lower
+ * layer will invoke esp_hf_client_outgoing_data_cb_t to fetch data
+ *
+ ***********************************************************************************************/
+void BTA_AgCiData(void)
+{
+ BT_HDR *p_buf;
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_CI_SCO_DATA_EVT;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE)*/
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "osi/allocator.h"
+#include "bta_ag_at.h"
+#include "bta/utl.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/******************************************************************************
+**
+** Function bta_ag_at_init
+**
+** Description Initialize the AT command parser control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_init(tBTA_AG_AT_CB *p_cb)
+{
+ p_cb->p_cmd_buf = NULL;
+ p_cb->cmd_pos = 0;
+}
+
+/******************************************************************************
+**
+** Function bta_ag_at_reinit
+**
+** Description Re-initialize the AT command parser control block. This
+** function resets the AT command parser state and frees
+** any GKI buffer.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb)
+{
+ if (p_cb->p_cmd_buf != NULL) {
+ osi_free(p_cb->p_cmd_buf);
+ p_cb->p_cmd_buf = NULL;
+ }
+ p_cb->cmd_pos = 0;
+}
+/******************************************************************************
+**
+** Function bta_ag_process_at
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_process_at(tBTA_AG_AT_CB *p_cb)
+{
+ UINT16 idx;
+ UINT8 arg_type;
+ char *p_arg;
+ INT16 int_arg = 0;
+ /* loop through at command table looking for match */
+ for (idx = 0; p_cb->p_at_tbl[idx].p_cmd[0] != 0; idx++) {
+ if (!utl_strucmp(p_cb->p_at_tbl[idx].p_cmd, p_cb->p_cmd_buf)) {
+ break;
+ }
+ }
+
+ /* if there is a match; verify argument type */
+ if (p_cb->p_at_tbl[idx].p_cmd[0] != 0) {
+ /* start of argument is p + strlen matching command */
+ p_arg = p_cb->p_cmd_buf + strlen(p_cb->p_at_tbl[idx].p_cmd);
+ /* if no argument */
+ if (p_arg[0] == 0) {
+ arg_type = BTA_AG_AT_NONE;
+ }
+ /* else if arg is '?' and it is last character */
+ else if (p_arg[0] == '?' && p_arg[1] == 0) {
+ arg_type = BTA_AG_AT_READ; /* we have a read */
+ }
+ /* else if arg is '=' */
+ else if (p_arg[0] == '=' && p_arg[1] != 0) {
+ if (p_arg[1] == '?' && p_arg[2] == 0) {
+ arg_type = BTA_AG_AT_TEST; /* we have a test */
+ } else {
+ arg_type = BTA_AG_AT_SET; /* we have a set */
+ p_arg++; /* skip past '=' */
+ }
+ }
+ /* else it is freeform argument */
+ else {
+ arg_type = BTA_AG_AT_FREE;
+ }
+ /* if arguments match command capabilities */
+ if ((arg_type & p_cb->p_at_tbl[idx].arg_type) != 0) {
+ /* if it's a set integer check max, min range */
+ if (arg_type == BTA_AG_AT_SET && p_cb->p_at_tbl[idx].fmt == BTA_AG_AT_INT) {
+ int_arg = utl_str2int(p_arg);
+ if (int_arg < (INT16) p_cb->p_at_tbl[idx].min ||
+ int_arg > (INT16) p_cb->p_at_tbl[idx].max) {
+ /* arg out of range; error */
+ (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+ } else {
+ (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+ }
+ } else {
+ (*p_cb->p_cmd_cback)(p_cb->p_user, idx, arg_type, p_arg, int_arg);
+ }
+ } else {
+ /* else error */
+ (*p_cb->p_err_cback)(p_cb->p_user, FALSE, NULL);
+ }
+ } else {
+ /* else no match call error callback */
+ (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_ag_at_parse
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len)
+{
+ int i = 0;
+ char* p_save;
+
+ if (p_cb->p_cmd_buf == NULL) {
+ if ((p_cb->p_cmd_buf = (char *) osi_malloc(p_cb->cmd_max_len)) == NULL) {
+ APPL_TRACE_ERROR("%s: osi_malloc() failed allocation", __func__);
+ return;
+ }
+ p_cb->cmd_pos = 0;
+ }
+
+ for (i = 0; i < len;) {
+ while (p_cb->cmd_pos < p_cb->cmd_max_len-1 && i < len) {
+ /* Skip null characters between AT commands. */
+ if ((p_cb->cmd_pos == 0) && (p_buf[i] == 0)) {
+ i++;
+ continue;
+ }
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = p_buf[i++];
+ if ( p_cb->p_cmd_buf[p_cb->cmd_pos] == '\r' || p_cb->p_cmd_buf[p_cb->cmd_pos] == '\n') {
+ p_cb->p_cmd_buf[p_cb->cmd_pos] = 0;
+ if ((p_cb->cmd_pos > 2) &&
+ (p_cb->p_cmd_buf[0] == 'A' || p_cb->p_cmd_buf[0] == 'a') &&
+ (p_cb->p_cmd_buf[1] == 'T' || p_cb->p_cmd_buf[1] == 't')) {
+ p_save = p_cb->p_cmd_buf;
+ p_cb->p_cmd_buf += 2;
+ bta_ag_process_at(p_cb);
+ p_cb->p_cmd_buf = p_save;
+ }
+ p_cb->cmd_pos = 0;
+ } else if( p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1A || p_cb->p_cmd_buf[p_cb->cmd_pos] == 0x1B) {
+ p_cb->p_cmd_buf[++p_cb->cmd_pos] = 0;
+ (*p_cb->p_err_cback)(p_cb->p_user, TRUE, p_cb->p_cmd_buf);
+ p_cb->cmd_pos = 0;
+ } else {
+ ++p_cb->cmd_pos;
+ }
+ }
+
+ if (i < len) {
+ p_cb->cmd_pos = 0;
+ }
+ }
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains compile-time configurable constants for the audio
+ * gateway.
+ *
+ ******************************************************************************/
+
+#include "osi/allocator.h"
+#include "bta/bta_api.h"
+#include "bta/bta_ag_api.h"
+#include "common/bt_target.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+
+#ifndef BTA_AG_CIND_INFO
+#define BTA_AG_CIND_INFO "(\"call\",(0,1)),(\"callsetup\",(0-3)),(\"service\",(0-3)),(\"signal\",(0-6)),(\"roam\",(0,1)),(\"battchg\",(0-5)),(\"callheld\",(0-2))"
+#endif
+
+#ifndef BTA_AG_CONN_TIMEOUT
+#define BTA_AG_CONN_TIMEOUT 5000
+#endif
+
+#ifndef BTA_AG_SCO_PKT_TYPES
+/* S1 packet type setting from HFP 1.5 spec */
+#define BTA_AG_SCO_PKT_TYPES /* BTM_SCO_LINK_ALL_PKT_MASK */ (BTM_SCO_LINK_ONLY_MASK | \
+ BTM_SCO_PKT_TYPES_MASK_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+#endif /* BTA_AG_SCO_PKT_TYPES */
+
+const tBTA_AG_CFG bta_ag_cfg =
+{
+ BTA_AG_CIND_INFO,
+ BTA_AG_CONN_TIMEOUT,
+ BTA_AG_SCO_PKT_TYPES,
+ BTA_AG_CHLD_VAL_ECC,
+ BTA_AG_CHLD_VAL
+};
+tBTA_AG_CFG *p_bta_ag_cfg = (tBTA_AG_CFG *) &bta_ag_cfg;
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for processing AT commands and results.
+ *
+ ******************************************************************************/
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "common/bt_target.h"
+#include "common/bt_trace.h"
+#include "stack/bt_types.h"
+#include "bta/bta_ag_api.h"
+#include "bta_ag_at.h"
+#include "bta_ag_int.h"
+#include "bta/bta_api.h"
+#include "bta/bta_sys.h"
+#include "osi/allocator.h"
+#include "stack/port_api.h"
+#include "bta/utl.h"
+
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+
+/* ring timeout */
+#define BTA_AG_RING_TOUT 5000
+#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */
+
+/* Invalid Chld command */
+#define BTA_AG_INVALID_CHLD 255
+
+/* clip type constants */
+#define BTA_AG_CLIP_TYPE_MIN 128
+#define BTA_AG_CLIP_TYPE_MAX 175
+#define BTA_AG_CLIP_TYPE_DEFAULT 129
+#define BTA_AG_CLIP_TYPE_VOIP 255
+
+/*******************************************
+* HSP callback
+********************************************/
+/* callback event lookup table for HSP */
+const tBTA_AG_EVT bta_ag_hsp_cb_evt[] =
+{
+ BTA_AG_AT_CKPD_EVT, /* BTA_AG_HS_CMD_CKPD */
+ BTA_AG_SPK_EVT, /* BTA_AG_HS_CMD_VGS */
+ BTA_AG_MIC_EVT /* BTA_AG_HS_CMD_VGM */
+};
+/* HSP AT commands matches bta_ag_hsp_cmd[] */
+enum
+{
+ BTA_AG_HS_CMD_CKPD,
+ BTA_AG_HS_CMD_VGS,
+ BTA_AG_HS_CMD_VGM
+};
+/* HSP AT command interpreter table */
+const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] =
+{
+ {"+CKPD", BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
+};
+
+/*******************************************
+* HFP callback
+********************************************/
+/* callback event lookup table for HFP (Indexed by command) */
+const tBTA_AG_EVT bta_ag_hfp_cb_evt[] =
+{
+ BTA_AG_AT_A_EVT, /* BTA_AG_HF_CMD_A */
+ BTA_AG_AT_D_EVT, /* BTA_AG_HF_CMD_D */
+ BTA_AG_SPK_EVT, /* BTA_AG_HF_CMD_VGS */
+ BTA_AG_MIC_EVT, /* BTA_AG_HF_CMD_VGM */
+ 0, /* BTA_AG_HF_CMD_CCWA */
+ BTA_AG_AT_CHLD_EVT, /* BTA_AG_HF_CMD_CHLD */
+ BTA_AG_AT_CHUP_EVT, /* BTA_AG_HF_CMD_CHUP */
+ BTA_AG_AT_CIND_EVT, /* BTA_AG_HF_CMD_CIND */
+ 0, /* BTA_AG_HF_CMD_CLIP */
+ 0, /* BTA_AG_HF_CMD_CMER */
+ BTA_AG_AT_VTS_EVT, /* BTA_AG_HF_CMD_VTS */
+ BTA_AG_AT_BINP_EVT, /* BTA_AG_HF_CMD_BINP */
+ BTA_AG_AT_BLDN_EVT, /* BTA_AG_HF_CMD_BLDN */
+ BTA_AG_AT_BVRA_EVT, /* BTA_AG_HF_CMD_BVRA */
+ 0, /* BTA_AG_HF_CMD_BRSF */
+ BTA_AG_AT_NREC_EVT, /* BTA_AG_HF_CMD_NREC */
+ BTA_AG_AT_CNUM_EVT, /* BTA_AG_HF_CMD_CNUM */
+ BTA_AG_AT_BTRH_EVT, /* BTA_AG_HF_CMD_BTRH */
+ BTA_AG_AT_CLCC_EVT, /* BTA_AG_HF_CMD_CLCC */
+ BTA_AG_AT_COPS_EVT, /* BTA_AG_HF_CMD_COPS */
+ 0, /* BTA_AG_HF_CMD_CMEE */
+ 0, /* BTA_AG_HF_CMD_BIA */
+ BTA_AG_AT_CBC_EVT, /* BTA_AG_HF_CMD_CBC */
+ 0, /* BTA_AG_HF_CMD_BCC */
+ BTA_AG_AT_BCS_EVT, /* BTA_AG_HF_CMD_BCS */
+ BTA_AG_AT_BAC_EVT /* BTA_AG_HF_CMD_BAC */
+};
+
+/* HFP AT commands matches bta_ag_hfp_cmd[] */
+enum
+{
+ BTA_AG_HF_CMD_A,
+ BTA_AG_HF_CMD_D,
+ BTA_AG_HF_CMD_VGS,
+ BTA_AG_HF_CMD_VGM,
+ BTA_AG_HF_CMD_CCWA,
+ BTA_AG_HF_CMD_CHLD,
+ BTA_AG_HF_CMD_CHUP,
+ BTA_AG_HF_CMD_CIND,
+ BTA_AG_HF_CMD_CLIP,
+ BTA_AG_HF_CMD_CMER,
+ BTA_AG_HF_CMD_VTS,
+ BTA_AG_HF_CMD_BINP,
+ BTA_AG_HF_CMD_BLDN,
+ BTA_AG_HF_CMD_BVRA,
+ BTA_AG_HF_CMD_BRSF,
+ BTA_AG_HF_CMD_NREC,
+ BTA_AG_HF_CMD_CNUM,
+ BTA_AG_HF_CMD_BTRH,
+ BTA_AG_HF_CMD_CLCC,
+ BTA_AG_HF_CMD_COPS,
+ BTA_AG_HF_CMD_CMEE,
+ BTA_AG_HF_CMD_BIA,
+ BTA_AG_HF_CMD_CBC,
+ BTA_AG_HF_CMD_BCC,
+ BTA_AG_HF_CMD_BCS,
+ BTA_AG_HF_CMD_BAC
+};
+
+/* HFP AT command interpreter table */
+const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] =
+{
+ {"A", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"D", (BTA_AG_AT_NONE | BTA_AG_AT_FREE), BTA_AG_AT_STR, 0, 0},
+ {"+VGS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+VGM", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15},
+ {"+CCWA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ /* Consider CHLD as str to take care of indexes for ECC */
+ {"+CHLD", (BTA_AG_AT_SET | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 4},
+ {"+CHUP", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+CIND", (BTA_AG_AT_READ | BTA_AG_AT_TEST), BTA_AG_AT_STR, 0, 0},
+ {"+CLIP", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+CMER", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+VTS", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"+BINP", BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1},
+ {"+BLDN", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BVRA", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BRSF", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+NREC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0},
+ {"+CNUM", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BTRH", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_INT, 0, 2},
+ {"+CLCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+COPS", (BTA_AG_AT_READ | BTA_AG_AT_SET), BTA_AG_AT_STR, 0, 0},
+ {"+CMEE", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1},
+ {"+BIA", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20},
+ {"+CBC", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100},
+ {"+BCC", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0},
+ {"+BCS", BTA_AG_AT_SET, BTA_AG_AT_INT, 0, BTA_AG_CMD_MAX_VAL},
+ {"+BAC", BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0},
+ {"", BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}
+};
+
+/*******************************************
+* AT Result
+********************************************/
+const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX] =
+{
+ bta_ag_hsp_cmd,
+ bta_ag_hfp_cmd
+};
+
+/* AT result code argument types */
+enum
+{
+ BTA_AG_RES_FMT_NONE, /* no argument */
+ BTA_AG_RES_FMT_INT, /* integer argument */
+ BTA_AG_RES_FMT_STR /* string argument */
+};
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+#define BTA_AG_AT_MULTI_LEN 2
+#define AT_SET_RES_CB(res_cb, c, p, i) {res_cb.code = c; res_cb.p_arg = p; res_cb.int_arg = i;}
+
+/* type for AT result code block */
+typedef struct
+{
+ UINT8 code;
+ char *p_arg;
+ INT16 int_arg;
+} tBTA_AG_RESULT_CB;
+
+/* type for multiple AT result codes block */
+typedef struct
+{
+ UINT8 num_result;
+ tBTA_AG_RESULT_CB res_cb[BTA_AG_AT_MULTI_LEN];
+} tBTA_AG_MULTI_RESULT_CB;
+#endif
+
+/* AT result code table element */
+typedef struct
+{
+ const char *p_res; /* AT result string */
+ UINT8 fmt; /* whether argument is int or string */
+} tBTA_AG_RESULT;
+
+/* AT result code constant table (Indexed by result code) */
+const tBTA_AG_RESULT bta_ag_result_tbl[] =
+{
+ {"OK", BTA_AG_RES_FMT_NONE},
+ {"ERROR", BTA_AG_RES_FMT_NONE},
+ {"RING", BTA_AG_RES_FMT_NONE},
+ {"+VGS: ", BTA_AG_RES_FMT_INT},
+ {"+VGM: ", BTA_AG_RES_FMT_INT},
+ {"+CCWA: ", BTA_AG_RES_FMT_STR},
+ {"+CHLD: ", BTA_AG_RES_FMT_STR},
+ {"+CIND: ", BTA_AG_RES_FMT_STR},
+ {"+CLIP: ", BTA_AG_RES_FMT_STR},
+ {"+CIEV: ", BTA_AG_RES_FMT_STR},
+ {"+BINP: ", BTA_AG_RES_FMT_STR},
+ {"+BVRA: ", BTA_AG_RES_FMT_INT},
+ {"+BRSF: ", BTA_AG_RES_FMT_INT},
+ {"+BSIR: ", BTA_AG_RES_FMT_INT},
+ {"+CNUM: ", BTA_AG_RES_FMT_STR},
+ {"+BTRH: ", BTA_AG_RES_FMT_INT},
+ {"+CLCC: ", BTA_AG_RES_FMT_STR},
+ {"+COPS: ", BTA_AG_RES_FMT_STR},
+ {"+CME ERROR: ", BTA_AG_RES_FMT_INT},
+ {"+BCS: ", BTA_AG_RES_FMT_INT},
+ {"", BTA_AG_RES_FMT_STR}
+};
+
+/* AT result codes, matches bta_ag_result_tbl[] */
+enum
+{
+ BTA_AG_RES_OK,
+ BTA_AG_RES_ERROR,
+ BTA_AG_RES_RING,
+ BTA_AG_RES_VGS,
+ BTA_AG_RES_VGM,
+ BTA_AG_RES_CCWA,
+ BTA_AG_RES_CHLD,
+ BTA_AG_RES_CIND,
+ BTA_AG_RES_CLIP,
+ BTA_AG_RES_CIEV,
+ BTA_AG_RES_BINP,
+ BTA_AG_RES_BVRA,
+ BTA_AG_RES_BRSF,
+ BTA_AG_RES_BSIR,
+ BTA_AG_RES_CNUM,
+ BTA_AG_RES_BTRH,
+ BTA_AG_RES_CLCC,
+ BTA_AG_RES_COPS,
+ BTA_AG_RES_CMEE,
+ BTA_AG_RES_BCS,
+ BTA_AG_RES_UNAT
+};
+
+/* translation of API result code values to internal values */
+const UINT8 bta_ag_trans_result[] =
+{
+ BTA_AG_RES_VGS, /* BTA_AG_SPK_RES */
+ BTA_AG_RES_VGM, /* BTA_AG_MIC_RES */
+ BTA_AG_RES_BSIR, /* BTA_AG_INBAND_RING_RES */
+ BTA_AG_RES_CIND, /* BTA_AG_CIND_RES */
+ BTA_AG_RES_BINP, /* BTA_AG_BINP_RES */
+ BTA_AG_RES_CIEV, /* BTA_AG_IND_RES */
+ BTA_AG_RES_BVRA, /* BTA_AG_BVRA_RES */
+ BTA_AG_RES_CNUM, /* BTA_AG_CNUM_RES */
+ BTA_AG_RES_BTRH, /* BTA_AG_BTRH_RES */
+ BTA_AG_RES_CLCC, /* BTA_AG_CLCC_RES */
+ BTA_AG_RES_COPS, /* BTA_AG_COPS_RES */
+ 0, /* BTA_AG_IN_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_RES_CCWA, /* BTA_AG_CALL_WAIT_RES */
+ 0, /* BTA_AG_OUT_CALL_ORIG_RES */
+ 0, /* BTA_AG_OUT_CALL_ALERT_RES */
+ 0, /* BTA_AG_OUT_CALL_CONN_RES */
+ 0, /* BTA_AG_CALL_CANCEL_RES */
+ 0, /* BTA_AG_END_CALL_RES */
+ 0, /* BTA_AG_IN_CALL_HELD_RES */
+ BTA_AG_RES_UNAT /* BTA_AG_UNAT_RES */
+};
+
+/* callsetup indicator value lookup table */
+const UINT8 bta_ag_callsetup_ind_tbl[] =
+{
+ 0, /* BTA_AG_SPK_RES */
+ 0, /* BTA_AG_MIC_RES */
+ 0, /* BTA_AG_INBAND_RING_RES */
+ 0, /* BTA_AG_CIND_RES */
+ 0, /* BTA_AG_BINP_RES */
+ 0, /* BTA_AG_IND_RES */
+ 0, /* BTA_AG_BVRA_RES */
+ 0, /* BTA_AG_CNUM_RES */
+ 0, /* BTA_AG_BTRH_RES */
+ 0, /* BTA_AG_CLCC_RES */
+ 0, /* BTA_AG_COPS_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_IN_CALL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_IN_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_INCOMING, /* BTA_AG_CALL_WAIT_RES */
+ BTA_AG_CALLSETUP_OUTGOING, /* BTA_AG_OUT_CALL_ORIG_RES */
+ BTA_AG_CALLSETUP_ALERTING, /* BTA_AG_OUT_CALL_ALERT_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_OUT_CALL_CONN_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_CALL_CANCEL_RES */
+ BTA_AG_CALLSETUP_NONE, /* BTA_AG_END_CALL_RES */
+ BTA_AG_CALLSETUP_NONE /* BTA_AG_IN_CALL_HELD_RES */
+};
+
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+#define COLON_IDX_4_VGSVGM 4
+#endif
+
+/*******************************************
+* Funcitons Result
+********************************************/
+/*******************************************************************************
+**
+** Function bta_ag_send_result
+**
+** Description Send an AT result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_result(tBTA_AG_SCB *p_scb, UINT8 code, char *p_arg, INT16 int_arg)
+{
+ char buf[BTA_AG_AT_MAX_LEN + 16];
+ char *p = buf;
+ UINT16 len;
+#if (BTIF_TRACE_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[code].p_res);
+#if defined(BTA_HSP_RESULT_REPLACE_COLON) && (BTA_HSP_RESULT_REPLACE_COLON == TRUE)
+ if(p_scb->conn_service == BTA_AG_HSP) {
+ /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */
+ switch(code) {
+ case BTA_AG_RES_VGS:
+ case BTA_AG_RES_VGM:
+ {
+ if(*(p+COLON_IDX_4_VGSVGM) == ':')
+ {
+ #if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("[HSP] ':'symbol is changed as '=' for HSP compatibility");
+ #endif
+ *(p+COLON_IDX_4_VGSVGM) = '=';
+ }
+ break;
+ }
+ }
+ }
+#endif
+ p += strlen(bta_ag_result_tbl[code].p_res);
+
+ /* copy argument if any */
+ if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_INT) {
+ p += utl_itoa((UINT16) int_arg, p);
+ } else if (bta_ag_result_tbl[code].fmt == BTA_AG_RES_FMT_STR) {
+ BCM_STRCPY_S(p, sizeof(buf), p_arg);
+ p += strlen(p_arg);
+ }
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+ APPL_TRACE_DEBUG("bta_ag_send_result: %s", buf);
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_ag_send_multi_result
+**
+** Description Send multiple AT result codes.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_multi_result(tBTA_AG_SCB *p_scb, tBTA_AG_MULTI_RESULT_CB *m_res_cb)
+{
+ char buf[BTA_AG_AT_MAX_LEN * BTA_AG_AT_MULTI_LEN + 16];
+ char *p = buf;
+ UINT16 len;
+ UINT8 res_idx = 0;
+
+ if((!m_res_cb) || (m_res_cb->num_result == 0) || (m_res_cb->num_result > BTA_AG_AT_MULTI_LEN)) {
+ APPL_TRACE_DEBUG("m_res_cb is NULL or num_result is out of range.");
+ return;
+ }
+
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ memset(buf, NULL, sizeof(buf));
+#endif
+
+ while(res_idx < m_res_cb->num_result) {
+ /* init with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+
+ /* copy result code string */
+ BCM_STRCPY_S(p, sizeof(buf), bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+ p += strlen(bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].p_res);
+
+ /* copy argument if any */
+ if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_INT) {
+ p += utl_itoa((UINT16) m_res_cb->res_cb[res_idx].int_arg, p);
+ } else if (bta_ag_result_tbl[m_res_cb->res_cb[res_idx].code].fmt == BTA_AG_RES_FMT_STR) {
+ BCM_STRCPY_S(p, sizeof(buf), m_res_cb->res_cb[res_idx].p_arg);
+ p += strlen(m_res_cb->res_cb[res_idx].p_arg);
+ }
+ /* finish with \r\n */
+ *p++ = '\r';
+ *p++ = '\n';
+ res_idx++;
+ }
+#if defined(BTA_AG_RESULT_DEBUG) && (BTA_AG_RESULT_DEBUG == TRUE)
+ APPL_TRACE_DEBUG("send_result: %s", buf);
+#endif
+ /* send to RFCOMM */
+ PORT_WriteData(p_scb->conn_handle, buf, (UINT16) (p - buf), &len);
+}
+#endif /* #if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE) */
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ok
+**
+** Description Send an OK result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_ok(tBTA_AG_SCB *p_scb)
+{
+ bta_ag_send_result(p_scb, BTA_AG_RES_OK, NULL, 0);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_error
+**
+** Description Send an ERROR result code.
+** errcode - used to send verbose errocode
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_error(tBTA_AG_SCB *p_scb, INT16 errcode)
+{
+ /* If HFP and extended audio gateway error codes are enabled */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled) {
+ bta_ag_send_result(p_scb, BTA_AG_RES_CMEE, NULL, errcode);
+ } else {
+ bta_ag_send_result(p_scb, BTA_AG_RES_ERROR, NULL, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ind
+**
+** Description Send an indicator CIEV result code.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_send_ind(tBTA_AG_SCB *p_scb, UINT16 id, UINT16 value, BOOLEAN on_demand)
+{
+ char str[12];
+ char *p = str;
+ /* If the indicator is masked out, just return */
+ /* Mandatory indicators can not be masked out. */
+ if ((p_scb->bia_masked_out & ((UINT32)1 << id)) &&
+ ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && (id != BTA_AG_IND_CALLHELD)))
+ return;
+
+ /* Ensure we do not send duplicate indicators if not requested by app */
+ /* If it was requested by app, transmit CIEV even if it is duplicate. */
+ if (id == BTA_AG_IND_CALL) {
+ if ((value == p_scb->call_ind) && (on_demand == FALSE)) {
+ return;
+ }
+ p_scb->call_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == FALSE)) {
+ if (value == p_scb->callsetup_ind) {
+ return;
+ }
+ p_scb->callsetup_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_SERVICE) && (on_demand == FALSE)) {
+ if (value == p_scb->service_ind) {
+ return;
+ }
+ p_scb->service_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_SIGNAL) && (on_demand == FALSE)) {
+ if (value == p_scb->signal_ind) {
+ return;
+ }
+ p_scb->signal_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_ROAM) && (on_demand == FALSE)) {
+ if (value == p_scb->roam_ind) {
+ return;
+ }
+ p_scb->roam_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_BATTCHG) && (on_demand == FALSE)) {
+ if (value == p_scb->battchg_ind) {
+ return;
+ }
+ p_scb->battchg_ind = (UINT8)value;
+ }
+ if ((id == BTA_AG_IND_CALLHELD) && (on_demand == FALSE)) {
+ /* call swap could result in sending callheld=1 multiple times */
+ if ((value != 1) && (value == p_scb->callheld_ind)) {
+ return;
+ }
+ p_scb->callheld_ind = (UINT8)value;
+ }
+ if (p_scb->cmer_enabled) {
+ p += utl_itoa(id, p);
+ *p++ = ',';
+ utl_itoa(value, p);
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIEV, str, 0);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_cmer
+**
+** Description Parse AT+CMER parameter string.
+**
+**
+** Returns TRUE if parsed ok, FALSE otherwise.
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_parse_cmer(char *p_s, BOOLEAN *p_enabled)
+{
+ INT16 n[4] = {-1, -1, -1, -1};
+ int i;
+ char *p;
+
+ for (i = 0; i < 4; i++) {
+ /* skip to comma delimiter */
+ for (p = p_s; *p != ',' && *p != 0; p++);
+ /* get integer value */
+ *p = 0;
+ n[i] = utl_str2int(p_s);
+ p_s = p + 1;
+ if (p_s == 0) {
+ break;
+ }
+ }
+ /* process values */
+ if (n[0] < 0 || n[3] < 0) {
+ return FALSE;
+ }
+ if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0))) {
+ *p_enabled = (BOOLEAN) n[3];
+ }
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_parse_chld
+**
+** Description Parse AT+CHLD parameter string.
+**
+**
+** Returns Returns idx (1-7), 0 if ECC not enabled or BTA_AG_INVALID_CHLD
+ if idx doesn't exist/1st character of argument is not a digit
+**
+*******************************************************************************/
+static UINT8 bta_ag_parse_chld(tBTA_AG_SCB *p_scb, char *p_s)
+{
+ UINT8 retval = 0;
+ INT16 idx = -1;
+ UNUSED(p_scb);
+
+ if (!isdigit(p_s[0])) {
+ return BTA_AG_INVALID_CHLD;
+ }
+
+ if (p_s[1] != 0) {
+ /* p_idxstr++; point to beginning of call number */
+ idx = utl_str2int(&p_s[1]);
+ if (idx != -1 && idx < 255) {
+ retval = (UINT8)idx;
+ } else {
+ retval = BTA_AG_INVALID_CHLD;
+ }
+ }
+ return(retval);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_parse_bac
+**
+** Description Parse AT+BAC parameter string.
+**
+** Returns Returns bitmap of supported codecs.
+**
+*******************************************************************************/
+static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB *p_scb, char *p_s)
+{
+ tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE;
+ UINT16 uuid_codec;
+ BOOLEAN cont = FALSE; /* Continue processing */
+ char *p;
+
+ while (p_s) {
+ /* skip to comma delimiter */
+ for (p = p_s; *p != ',' && *p != 0; p++);
+
+ /* get integre value */
+ if (*p != 0) {
+ *p = 0;
+ cont = TRUE;
+ } else {
+ cont = FALSE;
+ }
+ uuid_codec = utl_str2int(p_s);
+ switch(uuid_codec) {
+ case UUID_CODEC_CVSD:
+ retval |= BTA_AG_CODEC_CVSD;
+ break;
+
+ case UUID_CODEC_MSBC:
+ retval |= BTA_AG_CODEC_MSBC;
+ break;
+
+ default:
+ APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec);
+ return BTA_AG_CODEC_NONE;
+ }
+ if (cont) {
+ p_s = p + 1;
+ }
+ else {
+ break;
+ }
+ }
+ return (retval);
+}
+#endif /* #if (BTM_WBS_INCLUDED == TRUE ) */
+
+/*******************************************************************************
+**
+** Function bta_ag_process_unat_res
+**
+** Description Process the unat response data and remove extra carriage return
+** and line feed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_process_unat_res(char *unat_result)
+{
+ UINT8 str_leng;
+ UINT8 i = 0;
+ UINT8 j = 0;
+ UINT8 pairs_of_nl_cr;
+ char trim_data[BTA_AG_AT_MAX_LEN];
+
+ str_leng = strlen(unat_result);
+ /* If no extra CR and LF, just return */
+ if(str_leng < 4) {
+ return;
+ }
+
+ /* Remove the carriage return and left feed */
+ while(unat_result[0] =='\r' && unat_result[1] =='\n'
+ && unat_result[str_leng-2] =='\r' && unat_result[str_leng-1] =='\n') {
+ pairs_of_nl_cr = 1;
+ for (i=0;i<(str_leng-4*pairs_of_nl_cr);i++) {
+ trim_data[j++] = unat_result[i+pairs_of_nl_cr*2];
+ }
+ /* Add EOF */
+ trim_data[j] = '\0';
+ str_leng = str_leng - 4;
+ BCM_STRNCPY_S(unat_result, BTA_AG_AT_MAX_LEN+1, trim_data,str_leng+1);
+ i=0;
+ j=0;
+ if(str_leng <4) {
+ return;
+ }
+ }
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_inband_enabled
+**
+** Description Determine whether in-band ring can be used.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb)
+{
+ /* if feature is enabled and no other scbs connected */
+ if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_call_inds
+**
+** Description Send call and callsetup indicators.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result)
+{
+ UINT8 call = p_scb->call_ind;
+ UINT8 callsetup;
+ /* set new call and callsetup values based on BTA_AgResult */
+ callsetup = bta_ag_callsetup_ind_tbl[result];
+
+ if (result == BTA_AG_END_CALL_RES) {
+ call = BTA_AG_CALL_INACTIVE;
+ } else if (result == BTA_AG_IN_CALL_CONN_RES || result == BTA_AG_OUT_CALL_CONN_RES
+ || result == BTA_AG_IN_CALL_HELD_RES) {
+ call = BTA_AG_CALL_ACTIVE;
+ } else {
+ call = p_scb->call_ind;
+ }
+ /* Send indicator function tracks if the values have actually changed */
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, FALSE);
+ bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, FALSE);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_hsp_cback
+**
+** Description AT command processing callback for HSP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg)
+{
+ tBTA_AG_VAL val;
+ APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type, int_arg, p_arg);
+
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = (UINT16) int_arg;
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+ /* call callback with event */
+ (*bta_ag_cb.p_cback)(bta_ag_hsp_cb_evt[cmd], (tBTA_AG *) &val);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_hfp_cback
+**
+** Description AT command processing callback for HFP.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg)
+{
+ tBTA_AG_VAL val;
+ tBTA_AG_EVT event;
+ tBTA_AG_SCB *ag_scb;
+ UINT32 i, ind_id;
+ UINT32 bia_masked_out;
+#if (BTM_WBS_INCLUDED == TRUE)
+ tBTA_AG_PEER_CODEC codec_type, codec_sent;
+#endif
+ if (p_arg == NULL) {
+ APPL_TRACE_ERROR("%s: p_arg is null, send error and return", __func__);
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ return;
+ }
+ APPL_TRACE_DEBUG("HFP AT cmd:%d arg_type:%d arg:%d arg:%s", cmd, arg_type, int_arg, p_arg);
+
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = int_arg;
+ bdcpy(val.bd_addr, p_scb->peer_addr);
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+ event = bta_ag_hfp_cb_evt[cmd];
+
+ switch (cmd)
+ {
+ case BTA_AG_HF_CMD_A:
+ case BTA_AG_HF_CMD_VGS:
+ case BTA_AG_HF_CMD_VGM:
+ case BTA_AG_HF_CMD_CHUP:
+ case BTA_AG_HF_CMD_CBC:
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_BLDN:
+ /* Do not send OK, App will send error or OK depending on last-dial-umber enabled or not */
+ break;
+
+ case BTA_AG_HF_CMD_D:
+ {
+ /* Do not send OK for Dial cmds Let application decide whether to send OK or ERROR*/
+ /* if mem dial cmd, make sure string contains only digits */
+ if(p_arg[0] == '>') {
+ if(!utl_isintstr(p_arg+1)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ } else if (p_arg[0] == 'V') {
+ /* ATDV : Dial VoIP Call */
+ /* We do not check string. Code will be added later if needed. */
+ if(!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && (p_scb->features & BTA_AG_FEAT_VOIP))) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ } else {
+ /* If dial cmd, make sure string contains only dial digits
+ ** Dial digits are 0-9, A-C, *, #, + */
+ if(!utl_isdialstr(p_arg)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR);
+ }
+ }
+ break;
+ }
+
+ case BTA_AG_HF_CMD_CCWA:
+ p_scb->ccwa_enabled = (BOOLEAN) int_arg; /* store setting */
+ bta_ag_send_ok(p_scb); /* send OK */
+ break;
+
+ case BTA_AG_HF_CMD_CHLD:
+ {
+ if (arg_type == BTA_AG_AT_TEST) {
+ /* don't call callback */
+ event = 0;
+ /* send CHLD string */
+ /* Form string based on supported 1.5 feature */
+ if ((p_scb->peer_version >= HFP_VERSION_1_5) &&
+ (p_scb->features & BTA_AG_FEAT_ECC) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)) {
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val_ecc, 0);
+ } else {
+ bta_ag_send_result(p_scb, BTA_AG_RES_CHLD, p_bta_ag_cfg->chld_val, 0);
+ }
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ /* if service level conn. not already open, now it's open */
+ bta_ag_svc_conn_open(p_scb, NULL);
+ } else {
+ val.idx = bta_ag_parse_chld(p_scb, val.str);
+ if (val.idx == BTA_AG_INVALID_CHLD) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+ }
+ if(val.idx && !((p_scb->features & BTA_AG_FEAT_ECC) && (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))) {
+ /* we do not support ECC, but HF is sending us a CHLD with call index*/
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+
+ } else {
+ /* If it is swap between calls, set call held indicator to 3(out of valid 0-2)
+ ** Application will set it back to 1
+ ** callheld indicator will be sent across to the peer. */
+ if(val.str[0] == '2') {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) {
+ if (ag_scb->in_use) {
+ if((ag_scb->call_ind == BTA_AG_CALL_ACTIVE)
+ && (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) {
+ ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1;
+ }
+ }
+ }
+ }
+ }
+ /* Do not send OK. Let app decide after parsing the val str */
+ /* bta_ag_send_ok(p_scb); */
+ }
+ break;
+ }
+
+ case BTA_AG_HF_CMD_CIND:
+ if (arg_type == BTA_AG_AT_TEST) {
+ /* don't call callback */
+ event = 0;
+ /* send CIND string, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_RES_CIND, p_bta_ag_cfg->cind_info, 0);
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CLIP:
+ /* store setting, send OK */
+ p_scb->clip_enabled = (BOOLEAN) int_arg;
+ bta_ag_send_ok(p_scb);
+ break;
+
+ case BTA_AG_HF_CMD_CMER:
+ /* if parsed ok store setting, send OK */
+ if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled)) {
+ bta_ag_send_ok(p_scb);
+ /* if service level conn. not already open and our features and
+ ** peer features do not have 3-way, service level conn. now open
+ */
+ if (!p_scb->svc_conn && !((p_scb->features & BTA_AG_FEAT_3WAY) && (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) {
+ bta_ag_svc_conn_open(p_scb, NULL);
+ }
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_VTS:
+ /* check argument */
+ if (strlen(p_arg) == 1) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BINP:
+ /* if feature not set don't call callback, send ERROR */
+ if (!(p_scb->features & BTA_AG_FEAT_VTAG)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BVRA:
+ /* if feature not supported don't call callback, send ERROR. App will send OK */
+ if (!(p_scb->features & BTA_AG_FEAT_VREC)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BRSF:
+ {
+ /* store peer features */
+ p_scb->peer_features = (UINT16) int_arg;
+ /* send BRSF, send OK */
+ bta_ag_send_result(p_scb, BTA_AG_RES_BRSF, NULL, (INT16) (p_scb->features & BTA_AG_BSRF_FEAT_SPEC));
+ bta_ag_send_ok(p_scb);
+ break;
+ }
+
+ case BTA_AG_HF_CMD_NREC:
+ /* if feature send OK, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_ECNR) {
+ bta_ag_send_ok(p_scb);
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_BTRH:
+ /* if feature send BTRH, send OK:, else don't call callback, send ERROR */
+ if (p_scb->features & BTA_AG_FEAT_BTRH) {
+ /* If set command; send response and notify app */
+ if (arg_type == BTA_AG_AT_SET) {
+ for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, ag_scb++) {
+ if (ag_scb->in_use) {
+ bta_ag_send_result(ag_scb, BTA_AG_RES_BTRH, NULL, int_arg);
+ }
+ }
+ bta_ag_send_ok(p_scb);
+ } else {
+ /* Read Command */
+ val.num = BTA_AG_BTRH_READ;
+ }
+ } else {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_COPS:
+ if (arg_type == BTA_AG_AT_SET) {
+ /* don't call callback */
+ event = 0;
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CMEE:
+ if (p_scb->features & BTA_AG_FEAT_EXTERR) {
+ /* store setting */
+ p_scb->cmee_enabled = (BOOLEAN) int_arg;
+ /* send OK */
+ bta_ag_send_ok(p_scb);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ /* don't call callback */
+ event = 0;
+ break;
+
+ case BTA_AG_HF_CMD_BIA:
+ {
+ /* don't call callback */
+ event = 0;
+ bia_masked_out = p_scb->bia_masked_out;
+ /* Parse the indicator mask */
+ for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); i++, ind_id++) {
+ if (val.str[i] == ',')
+ continue;
+ if (val.str[i] == '0')
+ bia_masked_out |= ((UINT32)1 << ind_id);
+ else if (val.str[i] == '1')
+ bia_masked_out &= ~((UINT32)1 << ind_id);
+ else
+ break;
+ i++;
+ if ( (val.str[i] != 0) && (val.str[i] != ',') )
+ break;
+ }
+ if (val.str[i] == 0) {
+ p_scb->bia_masked_out = bia_masked_out;
+ bta_ag_send_ok (p_scb);
+ } else {
+ bta_ag_send_error (p_scb, BTA_AG_ERR_INVALID_INDEX);
+ }
+ break;
+ }
+
+ case BTA_AG_HF_CMD_CNUM:
+ if(!(p_scb->features & BTA_AG_FEAT_ECS)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+ case BTA_AG_HF_CMD_CLCC:
+ if(!(p_scb->features & BTA_AG_FEAT_ECS)) {
+ event = 0;
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_HF_CMD_BAC:
+ {
+ bta_ag_send_ok(p_scb);
+ /* store available codecs from the peer */
+ if((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && (p_scb->features & BTA_AG_FEAT_CODEC)) {
+ p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg);
+ p_scb->codec_updated = TRUE;
+
+ if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC) {
+ p_scb->sco_codec = UUID_CODEC_MSBC;
+ APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC");
+ } else {
+ p_scb->sco_codec = UUID_CODEC_CVSD;
+ APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD");
+ }
+ /* The above logic sets the stack preferred codec based on local and peer codec
+ capabilities. This can be overridden by the application depending on its preference
+ using the bta_ag_setcodec API. We send the peer_codecs to the application. */
+ val.num = p_scb->peer_codecs;
+ /* Received BAC while in codec negotiation. */
+ if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb)) {
+ bta_ag_codec_negotiate (p_scb);
+ }
+ } else {
+ p_scb->peer_codecs = BTA_AG_CODEC_NONE;
+ APPL_TRACE_ERROR("Unexpected CMD:AT+BAC, Codec Negotiation is not supported");
+ }
+ break;
+ }
+
+ case BTA_AG_HF_CMD_BCS:
+ {
+ bta_ag_send_ok(p_scb);
+ /* stop cn timer */
+ bta_sys_stop_timer(&p_scb->cn_timer);
+
+ switch(int_arg) {
+ case UUID_CODEC_CVSD:
+ codec_type = BTA_AG_CODEC_CVSD;
+ break;
+
+ case UUID_CODEC_MSBC:
+ codec_type = BTA_AG_CODEC_MSBC;
+ break;
+
+ default:
+ APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg);
+ codec_type = 0xFFFF;
+ break;
+ }
+
+ if (p_scb->codec_fallback) {
+ codec_sent = BTA_AG_CODEC_CVSD;
+ } else {
+ codec_sent = p_scb->sco_codec;
+ }
+
+ if(codec_type == codec_sent) {
+ bta_ag_sco_codec_nego(p_scb, TRUE);
+ } else {
+ bta_ag_sco_codec_nego(p_scb, FALSE);
+ }
+ /* send final codec info to callback */
+ val.num = codec_sent;
+ break;
+ }
+
+ case BTA_AG_HF_CMD_BCC:
+ {
+ bta_ag_send_ok(p_scb);
+ bta_ag_sco_open(p_scb, NULL);
+ break;
+ }
+#endif
+ default:
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ break;
+ }
+ /* call callback */
+ if (event != 0) {
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &val);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_at_err_cback
+**
+** Description AT command parser error callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg)
+{
+ tBTA_AG_VAL val;
+
+ if(unknown && (!strlen(p_arg))) {
+ APPL_TRACE_DEBUG("Empty AT cmd string received");
+ bta_ag_send_ok(p_scb);
+ return;
+ }
+
+ /* if unknown AT command and configured to pass these to app */
+ if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) {
+ val.hdr.handle = bta_ag_scb_to_idx(p_scb);
+ val.hdr.app_id = p_scb->app_id;
+ val.num = 0;
+ BCM_STRNCPY_S(val.str, sizeof(val.str), p_arg, BTA_AG_AT_MAX_LEN);
+ val.str[BTA_AG_AT_MAX_LEN] = 0;
+ (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG *) &val);
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hsp_result
+**
+** Description Handle API result for HSP connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_hsp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+ UINT8 code = bta_ag_trans_result[p_result->result];
+
+ APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result);
+
+ switch(p_result->result) {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ {
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+ } else {
+ /* else open sco, send ring after sco opened */
+ /* HSPv1.2: AG shall not send RING if using in-band ring tone. */
+ if (p_scb->hsp_version >= HSP_VERSION_1_2) {
+ p_scb->post_sco = BTA_AG_POST_SCO_NONE;
+ } else {
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ }
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ break;
+ }
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ {
+ /* if incoming call connected stop ring timer */
+ if (p_result->result == BTA_AG_IN_CALL_CONN_RES) {
+ bta_sys_stop_timer(&p_scb->act_timer);
+ }
+
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ /* if audio connected to this scb open sco */
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+ /* else if no audio at call close sco */
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+ }
+
+ case BTA_AG_END_CALL_RES:
+ {
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+ /* close sco */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ } else {
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+ }
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+ break;
+
+ case BTA_AG_UNAT_RES:
+ {
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) {
+ bta_ag_send_ok(p_scb);
+ }
+ } else {
+ bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR);
+ }
+ break;
+ }
+ default:
+ break; /* ignore all others */
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hfp_result
+**
+** Description Handle API result for HFP connections.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_hfp_result(tBTA_AG_SCB *p_scb, tBTA_AG_API_RESULT *p_result)
+{
+ UINT8 code = bta_ag_trans_result[p_result->result];
+
+ APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result);
+
+ switch(p_result->result)
+ {
+ case BTA_AG_SPK_RES:
+ case BTA_AG_MIC_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ break;
+
+ case BTA_AG_IN_CALL_RES:
+ {
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ /* store caller id string.
+ * append type info at the end.
+ * make sure a valid type info is passed.
+ * otherwise add 129 as default type */
+ if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) {
+ if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP) {
+ p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT;
+ }
+ }
+ APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num);
+ p_scb->clip[0] = 0;
+ if (p_result->data.str[0] != 0) {
+ snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", p_result->data.str, p_result->data.num);
+ }
+ /* send callsetup indicator */
+ if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) {
+ /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO close. */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL;
+ } else {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ /* if sco already opened or no inband ring send ring now */
+ if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) ||
+ (p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_send_ring(p_scb, (tBTA_AG_DATA *) p_result);
+ } else {
+ /* else open sco, send ring after sco opened */
+ p_scb->post_sco = BTA_AG_POST_SCO_RING;
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+ }
+
+ case BTA_AG_IN_CALL_CONN_RES:
+ {
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+ /* if sco not opened and we need to open it, send indicators first
+ ** then open sco. */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ } else if ((p_result->data.audio_handle == BTA_AG_HANDLE_NONE) && bta_ag_sco_is_open(p_scb)) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+ }
+
+ case BTA_AG_IN_CALL_HELD_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_OUT_CALL_ORIG_RES:
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ break;
+
+ case BTA_AG_OUT_CALL_ALERT_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ break;
+
+ case BTA_AG_MULTI_CALL_RES:
+ /* open SCO at SLC for this three way call */
+ APPL_TRACE_DEBUG("Headset Connected in three way call");
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_OUT_CALL_CONN_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ /* open or close sco */
+ if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) {
+ bta_ag_sco_open(p_scb, (tBTA_AG_DATA *) p_result);
+ } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) {
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ }
+ }
+ break;
+
+ case BTA_AG_CALL_CANCEL_RES:
+ /* send indicators */
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_END_CALL_RES:
+ /* stop ring timer */
+ bta_sys_stop_timer(&p_scb->act_timer);
+ /* if sco open, close sco then send indicator values */
+ if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && !(p_scb->features & BTA_AG_FEAT_NOSCO)) {
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ bta_ag_sco_close(p_scb, (tBTA_AG_DATA *) p_result);
+ } else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) {
+ /* sco closing for outgoing call because of incoming call */
+ /* Send only callsetup end indicator after sco close */
+ p_scb->post_sco = BTA_AG_POST_SCO_CALL_END;
+ } else {
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ /* if av got suspended by this call, let it resume. */
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+ break;
+
+ case BTA_AG_INBAND_RING_RES:
+ p_scb->inband_enabled = p_result->data.state;
+ APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled);
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_CIND_RES:
+ {
+ /* store local values */
+ p_scb->call_ind = p_result->data.str[0] - '0';
+ p_scb->callsetup_ind = p_result->data.str[2] - '0';
+ p_scb->service_ind = p_result->data.str[4] - '0';
+ p_scb->signal_ind = p_result->data.str[6] - '0';
+ p_scb->roam_ind = p_result->data.str[8] - '0';
+ p_scb->battchg_ind = p_result->data.str[10] - '0';
+ p_scb->callheld_ind = p_result->data.str[12] - '0';
+
+ APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind, p_scb->callsetup_ind);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ bta_ag_send_ok(p_scb);
+ break;
+ }
+
+ case BTA_AG_BINP_RES: // Not supported yet
+ case BTA_AG_CNUM_RES:
+ case BTA_AG_CLCC_RES:
+ case BTA_AG_COPS_RES:
+ {
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ bta_ag_send_ok(p_scb);
+ }
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) {
+ bta_ag_send_ok(p_scb);
+ }
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+ }
+
+ case BTA_AG_UNAT_RES:
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ if (p_result->data.str[0] != 0) {
+ bta_ag_process_unat_res(p_result->data.str);
+ APPL_TRACE_DEBUG("BTA_AG_RES :%s",p_result->data.str);
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) {
+ bta_ag_send_ok(p_scb);
+ }
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ case BTA_AG_CALL_WAIT_RES:
+ if (p_scb->ccwa_enabled) {
+ bta_ag_send_result(p_scb, code, p_result->data.str, 0);
+ }
+ bta_ag_send_call_inds(p_scb, p_result->result);
+ break;
+
+ case BTA_AG_IND_RES:
+ bta_ag_send_ind(p_scb, p_result->data.ind.type, p_result->data.ind.value, FALSE);
+ break;
+
+ case BTA_AG_BVRA_RES:
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.state);
+ break;
+
+ case BTA_AG_BTRH_RES: // Not supported yet
+ if (p_result->data.ok_flag != BTA_AG_OK_ERROR) {
+ /* Don't respond to read if not in response & hold state */
+ if (p_result->data.num != BTA_AG_BTRH_NO_RESP) {
+ bta_ag_send_result(p_scb, code, NULL, p_result->data.num);
+ }
+ /* In case of a response to a read request we need to send OK */
+ if (p_result->data.ok_flag == BTA_AG_OK_DONE) {
+ bta_ag_send_ok(p_scb);
+ }
+ } else {
+ bta_ag_send_error(p_scb, p_result->data.errcode);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_result
+**
+** Description Handle API result.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ if (p_scb->conn_service == BTA_AG_HSP) {
+ bta_ag_hsp_result(p_scb, &p_data->api_result);
+ } else {
+ bta_ag_hfp_result(p_scb, &p_data->api_result);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_send_bcs
+**
+** Description Send +BCS AT command to peer.
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_WBS_INCLUDED == TRUE )
+void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 codec_uuid;
+
+ if (p_scb->codec_fallback) {
+ codec_uuid = UUID_CODEC_CVSD;
+ } else {
+ switch(p_scb->sco_codec) {
+ case BTA_AG_CODEC_NONE:
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+
+ case BTA_AG_CODEC_CVSD:
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+
+ case BTA_AG_CODEC_MSBC:
+ codec_uuid = UUID_CODEC_MSBC;
+ break;
+
+ default:
+ APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD", p_scb->sco_codec);
+ codec_uuid = UUID_CODEC_CVSD;
+ break;
+ }
+ }
+ /* send +BCS */
+ APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid);
+ bta_ag_send_result(p_scb, BTA_AG_RES_BCS, NULL, codec_uuid);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_send_ring
+**
+** Description Send RING result code to peer.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+
+#if defined(BTA_AG_MULTI_RESULT_INCLUDED) && (BTA_AG_MULTI_RESULT_INCLUDED == TRUE)
+ tBTA_AG_MULTI_RESULT_CB m_res_cb;
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0) {
+ memset(&m_res_cb, NULL, sizeof(tBTA_AG_MULTI_RESULT_CB));
+ m_res_cb.num_result = 2;
+ AT_SET_RES_CB(m_res_cb.res_cb[0], BTA_AG_RES_RING, NULL, 0)
+ AT_SET_RES_CB(m_res_cb.res_cb[1], BTA_AG_RES_CLIP, p_scb->clip, 0)
+ bta_ag_send_multi_result(p_scb, &m_res_cb);
+ } else {
+ /* send RING ONLY */
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+ }
+#else
+ /* send RING */
+ bta_ag_send_result(p_scb, BTA_AG_RES_RING, NULL, 0);
+ /* if HFP and clip enabled and clip data send CLIP */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && p_scb->clip[0] != 0) {
+ bta_ag_send_result(p_scb, BTA_AG_RES_CLIP, p_scb->clip, 0);
+ }
+#endif
+ /* restart ring timer */
+ bta_sys_start_timer(&p_scb->act_timer, BTA_AG_RING_TOUT_EVT, BTA_AG_RING_TOUT);
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the main implementation file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include "bta/bta_api.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_ag_co.h"
+#include "bta/utl.h"
+#include "common/bt_defs.h"
+#include "common/bt_trace.h"
+#include "osi/allocator.h"
+#include "bta_ag_int.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants and types
+*****************************************************************************/
+#ifndef BTA_AG_DEBUG
+#define BTA_AG_DEBUG TRUE
+#endif
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result);
+static char *bta_ag_state_str(UINT8 state);
+#endif
+
+/* state machine states */
+enum
+{
+ BTA_AG_INIT_ST,
+ BTA_AG_OPENING_ST,
+ BTA_AG_OPEN_ST,
+ BTA_AG_CLOSING_ST
+};
+
+/* state machine action enumeration list */
+enum
+{
+ BTA_AG_REGISTER,
+ BTA_AG_DEREGISTER,
+ BTA_AG_START_OPEN,
+ BTA_AG_RFC_DO_OPEN,
+ BTA_AG_RFC_DO_CLOSE,
+ BTA_AG_START_DEREG,
+ BTA_AG_START_CLOSE,
+ BTA_AG_RFC_OPEN,
+ BTA_AG_OPEN_FAIL,
+ BTA_AG_RFC_ACP_OPEN,
+ BTA_AG_RFC_CLOSE,
+ BTA_AG_RFC_FAIL,
+ BTA_AG_RFC_DATA,
+ BTA_AG_DISC_INT_RES,
+ BTA_AG_DISC_FAIL,
+ BTA_AG_DISC_ACP_RES,
+ BTA_AG_FREE_DB,
+ BTA_AG_SCO_CONN_OPEN,
+ BTA_AG_SCO_CONN_CLOSE,
+ BTA_AG_SCO_LISTEN,
+ BTA_AG_SCO_OPEN,
+ BTA_AG_SCO_CLOSE,
+ BTA_AG_SCO_SHUTDOWN,
+ BTA_AG_POST_SCO_OPEN,
+ BTA_AG_POST_SCO_CLOSE,
+ BTA_AG_SVC_CONN_OPEN,
+ BTA_AG_RESULT,
+ BTA_AG_SETCODEC,
+ BTA_AG_SEND_RING,
+ BTA_AG_CI_SCO_DATA,
+ BTA_AG_CI_RX_DATA,
+ BTA_AG_RCVD_SLC_READY,
+ BTA_AG_NUM_ACTIONS
+};
+
+#define BTA_AG_IGNORE BTA_AG_NUM_ACTIONS
+
+/* type for action functions */
+typedef void (*tBTA_AG_ACTION) (tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* action functions */
+const tBTA_AG_ACTION bta_ag_action[] =
+{
+ bta_ag_register,
+ bta_ag_deregister,
+ bta_ag_start_open,
+ bta_ag_rfc_do_open,
+ bta_ag_rfc_do_close,
+ bta_ag_start_dereg,
+ bta_ag_start_close,
+ bta_ag_rfc_open,
+ bta_ag_open_fail,
+ bta_ag_rfc_acp_open,
+ bta_ag_rfc_close,
+ bta_ag_rfc_fail,
+ bta_ag_rfc_data,
+ bta_ag_disc_int_res,
+ bta_ag_disc_fail,
+ bta_ag_disc_acp_res,
+ bta_ag_free_db,
+ bta_ag_sco_conn_open,
+ bta_ag_sco_conn_close,
+ bta_ag_sco_listen,
+ bta_ag_sco_open,
+ bta_ag_sco_close,
+ bta_ag_sco_shutdown,
+ bta_ag_post_sco_open,
+ bta_ag_post_sco_close,
+ bta_ag_svc_conn_open,
+ bta_ag_result,
+ bta_ag_setcodec,
+ bta_ag_send_ring,
+ bta_ag_ci_sco_data,
+ bta_ag_ci_rx_data,
+ bta_ag_rcvd_slc_ready
+};
+
+/* state table information */
+#define BTA_AG_ACTIONS 2 /* number of actions */
+#define BTA_AG_NEXT_STATE 2 /* position of next state */
+#define BTA_AG_NUM_COLS 3 /* number of columns in state tables */
+
+/* state table for init state */
+const UINT8 bta_ag_st_init[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_REGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_DEREGISTER, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_OPEN_EVT */ {BTA_AG_START_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_RFC_ACP_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_INIT_ST}
+};
+
+/* state table for opening state */
+const UINT8 bta_ag_st_opening[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_RFC_DO_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_RFC_OPEN, BTA_AG_SCO_LISTEN, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_DISC_INT_RES, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_OK_EVT */ {BTA_AG_RFC_DO_OPEN, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_DISC_FAIL, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPENING_ST}
+};
+
+/* state table for open state */
+const UINT8 bta_ag_st_open[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_START_CLOSE, BTA_AG_START_DEREG, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_CLOSE_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_SCO_OPEN, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_SCO_CLOSE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_RESULT_EVT */ {BTA_AG_RESULT, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_SETCODEC, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RFC_DATA_EVT */ {BTA_AG_RFC_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_POST_SCO_OPEN, BTA_AG_OPEN_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_OPEN_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_DISC_ACP_RES, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_CI_RX_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* RING_TOUT_EVT */ {BTA_AG_SEND_RING, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_START_CLOSE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_CI_SCO_DATA, BTA_AG_IGNORE, BTA_AG_OPEN_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_RCVD_SLC_READY, BTA_AG_IGNORE, BTA_AG_OPEN_ST}
+};
+
+/* state table for closing state */
+const UINT8 bta_ag_st_closing[][BTA_AG_NUM_COLS] =
+{
+/* Event Action 1 Action 2 Next state */
+/* API_REGISTER_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_DEREGISTER_EVT */ {BTA_AG_START_DEREG, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_OPEN_EVT */ {BTA_AG_OPEN_FAIL, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_AUDIO_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_RESULT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* API_SETCODEC_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_OPEN_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_CLOSE_EVT */ {BTA_AG_RFC_CLOSE, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* RFC_SRV_CLOSE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RFC_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SCO_OPEN_EVT */ {BTA_AG_SCO_CONN_OPEN, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SCO_CLOSE_EVT */ {BTA_AG_SCO_CONN_CLOSE, BTA_AG_POST_SCO_CLOSE, BTA_AG_CLOSING_ST},
+/* DISC_ACP_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* DISC_INT_RES_EVT */ {BTA_AG_FREE_DB, BTA_AG_IGNORE, BTA_AG_INIT_ST},
+/* DISC_OK_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* DISC_FAIL_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_RX_WRITE_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* RING_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* SVC_TOUT_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_SCO_DATA_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST},
+/* CI_SLC_READY_EVT */ {BTA_AG_IGNORE, BTA_AG_IGNORE, BTA_AG_CLOSING_ST}
+};
+
+/* type for state table */
+typedef const UINT8 (*tBTA_AG_ST_TBL)[BTA_AG_NUM_COLS];
+
+/* state table */
+const tBTA_AG_ST_TBL bta_ag_st_tbl[] =
+{
+ bta_ag_st_init,
+ bta_ag_st_opening,
+ bta_ag_st_open,
+ bta_ag_st_closing
+};
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+const char *bta_ag_version = "1.5"; //"1.6"
+/* AG control block */
+#if BTA_DYNAMIC_MEMORY == FALSE
+tBTA_AG_CB bta_ag_cb;
+#else
+tBTA_AG_CB *bta_ag_cb_ptr;
+#endif
+
+#if BTA_AG_DEBUG == TRUE
+static char *bta_ag_evt_str(UINT16 event, tBTA_AG_RES result)
+{
+ switch (event)
+ {
+ case BTA_AG_API_REGISTER_EVT:
+ return "Register Request";
+ case BTA_AG_API_DEREGISTER_EVT:
+ return "Deregister Request";
+ case BTA_AG_API_OPEN_EVT:
+ return "Open SLC Request";
+ case BTA_AG_API_CLOSE_EVT:
+ return "Close SLC Request";
+ case BTA_AG_API_AUDIO_OPEN_EVT:
+ return "Open Audio Request";
+ case BTA_AG_API_AUDIO_CLOSE_EVT:
+ return "Close Audio Request";
+ case BTA_AG_API_RESULT_EVT:
+ switch (result) {
+ case BTA_AG_SPK_RES: return ("AT Result BTA_AG_SPK_RES");
+ case BTA_AG_MIC_RES: return ("AT Result BTA_AG_MIC_RES");
+ case BTA_AG_INBAND_RING_RES: return ("AT Result BTA_AG_INBAND_RING_RES");
+ case BTA_AG_CIND_RES: return ("AT Result BTA_AG_CIND_RES");
+ case BTA_AG_BINP_RES: return ("AT Result BTA_AG_BINP_RES");
+ case BTA_AG_IND_RES: return ("AT Result BTA_AG_IND_RES");
+ case BTA_AG_BVRA_RES: return ("AT Result BTA_AG_BVRA_RES");
+ case BTA_AG_CNUM_RES: return ("AT Result BTA_AG_CNUM_RES");
+ case BTA_AG_BTRH_RES: return ("AT Result BTA_AG_BTRH_RES");
+ case BTA_AG_CLCC_RES: return ("AT Result BTA_AG_CLCC_RES");
+ case BTA_AG_COPS_RES: return ("AT Result BTA_AG_COPS_RES");
+ case BTA_AG_IN_CALL_RES: return ("AT Result BTA_AG_IN_CALL_RES");
+ case BTA_AG_IN_CALL_CONN_RES: return ("AT Result BTA_AG_IN_CALL_CONN_RES");
+ case BTA_AG_CALL_WAIT_RES: return ("AT Result BTA_AG_CALL_WAIT_RES");
+ case BTA_AG_OUT_CALL_ORIG_RES: return ("AT Result BTA_AG_OUT_CALL_ORIG_RES");
+ case BTA_AG_OUT_CALL_ALERT_RES: return ("AT Result BTA_AG_OUT_CALL_ALERT_RES");
+ case BTA_AG_OUT_CALL_CONN_RES: return ("AT Result BTA_AG_OUT_CALL_CONN_RES");
+ case BTA_AG_CALL_CANCEL_RES: return ("AT Result BTA_AG_CALL_CANCEL_RES");
+ case BTA_AG_END_CALL_RES: return ("AT Result BTA_AG_END_CALL_RES");
+ case BTA_AG_UNAT_RES: return ("AT Result BTA_AG_UNAT_RES");
+ default: return ("Unknown AG Result");
+ }
+ case BTA_AG_API_SETCODEC_EVT:
+ return "Set Codec Request";
+ case BTA_AG_RFC_OPEN_EVT:
+ return "RFC Opened";
+ case BTA_AG_RFC_CLOSE_EVT:
+ return "RFC Closed";
+ case BTA_AG_RFC_SRV_CLOSE_EVT:
+ return "RFC SRV Closed";
+ case BTA_AG_RFC_DATA_EVT:
+ return "RFC Data";
+ case BTA_AG_SCO_OPEN_EVT:
+ return "Audio Opened";
+ case BTA_AG_SCO_CLOSE_EVT:
+ return "Audio Closed";
+ case BTA_AG_DISC_ACP_RES_EVT:
+ return "Discovery ACP Result";
+ case BTA_AG_DISC_INT_RES_EVT:
+ return "Discovery INT Result";
+ case BTA_AG_DISC_OK_EVT:
+ return "Discovery OK";
+ case BTA_AG_DISC_FAIL_EVT:
+ return "Discovery Failed";
+ case BTA_AG_CI_RX_WRITE_EVT:
+ return "CI RX Write";
+ case BTA_AG_RING_TOUT_EVT:
+ return "Ring Timeout";
+ case BTA_AG_SVC_TOUT_EVT:
+ return "Service Timeout";
+ case BTA_AG_API_ENABLE_EVT:
+ return "Enable AG";
+ case BTA_AG_API_DISABLE_EVT:
+ return "Disable AG";
+ case BTA_AG_CI_SCO_DATA_EVT:
+ return "SCO data Callin";
+ case BTA_AG_CI_SLC_READY_EVT:
+ return "SLC Ready Callin";
+ default:
+ return "Unknown AG Event";
+ }
+}
+
+static char *bta_ag_state_str(UINT8 state)
+{
+ switch (state) {
+ case BTA_AG_INIT_ST:
+ return "Initial";
+ case BTA_AG_OPENING_ST:
+ return "Opening";
+ case BTA_AG_OPEN_ST:
+ return "Open";
+ case BTA_AG_CLOSING_ST:
+ return "Closing";
+ default:
+ return "Unknown AG State";
+ }
+}
+
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_timer_cback
+**
+** Description AG timer callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_timer_cback(void *p)
+{
+ BT_HDR *p_buf;
+ TIMER_LIST_ENT *p_tle = (TIMER_LIST_ENT *) p;
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = p_tle->event;
+ p_buf->layer_specific = bta_ag_scb_to_idx((tBTA_AG_SCB *) p_tle->param);
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_alloc
+**
+** Description Allocate an AG service control block.
+**
+**
+** Returns pointer to the scb, or NULL if none could be allocated.
+**
+*******************************************************************************/
+static tBTA_AG_SCB *bta_ag_scb_alloc(void)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ int i;
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (!p_scb->in_use) {
+ /* initialize variables */
+ p_scb->in_use = TRUE;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+#if (BTM_WBS_INCLUDED == TRUE )
+ p_scb->codec_updated = FALSE;
+#endif
+ /* set up timers */
+ p_scb->act_timer.param = (UINT32) p_scb;
+ p_scb->act_timer.p_cback = bta_ag_timer_cback;
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* set eSCO mSBC setting to T2 as the preferred */
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+ APPL_TRACE_DEBUG("bta_ag_scb_alloc %d", bta_ag_scb_to_idx(p_scb));
+ break;
+ }
+ }
+
+ if (i == BTA_AG_NUM_SCB) {
+ p_scb = NULL; /* out of scbs */
+ APPL_TRACE_WARNING("Out of ag scbs");
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_dealloc
+**
+** Description Deallocate a service control block.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb)
+{
+ UINT8 idx;
+ BOOLEAN allocated = FALSE;
+
+ APPL_TRACE_DEBUG("bta_ag_scb_dealloc %d", bta_ag_scb_to_idx(p_scb));
+ /* stop timers */
+ bta_sys_stop_timer(&p_scb->act_timer);
+#if (BTM_WBS_INCLUDED == TRUE)
+ bta_sys_stop_timer(&p_scb->cn_timer);
+#endif
+ bta_sys_stop_timer(&p_scb->colli_timer);
+
+ /* initialize control block */
+ memset(p_scb, 0, sizeof(tBTA_AG_SCB));
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ /* If all scbs are deallocated, callback with disable event */
+ if (!bta_sys_is_register (BTA_ID_AG)) {
+ for (idx = 0; idx < BTA_AG_NUM_SCB; idx++) {
+ if (bta_ag_cb.scb[idx].in_use) {
+ allocated = TRUE;
+ break;
+ }
+ }
+ if (!allocated) {
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_to_idx
+**
+** Description Given a pointer to an scb, return its index.
+**
+**
+** Returns Index of scb.
+**
+*******************************************************************************/
+UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb)
+{
+ /* use array arithmetic to determine index */
+ return ((UINT16) (p_scb - bta_ag_cb.scb)) + 1;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_by_idx
+**
+** Description Given an scb index return pointer to scb.
+**
+**
+** Returns Pointer to scb or NULL if not allocated.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx)
+{
+ tBTA_AG_SCB *p_scb;
+ /* verify index */
+ if (idx > 0 && idx <= BTA_AG_NUM_SCB) {
+ p_scb = &bta_ag_cb.scb[idx - 1];
+ if (!p_scb->in_use) {
+ p_scb = NULL;
+ APPL_TRACE_WARNING("ag scb idx %d not allocated", idx);
+ }
+ } else {
+ p_scb = NULL;
+ APPL_TRACE_DEBUG("ag scb idx %d out of range", idx);
+ }
+ return p_scb;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_service_to_idx
+**
+** Description Given a BTA service mask convert to profile index.
+**
+**
+** Returns Profile ndex of scb.
+**
+*******************************************************************************/
+UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services)
+{
+ if (services & BTA_HFP_SERVICE_MASK) {
+ return BTA_AG_HFP;
+ } else {
+ return BTA_AG_HSP;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_idx_by_bdaddr
+**
+** Description Find SCB associated with peer BD address.
+**
+**
+** Returns Index of SCB or zero if none found.
+**
+*******************************************************************************/
+UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ UINT16 i;
+
+ if (peer_addr != NULL) {
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && !bdcmp(peer_addr, p_scb->peer_addr)) {
+ return (i + 1);
+ }
+ }
+ }
+ /* no scb found */
+ APPL_TRACE_WARNING("No ag scb for peer addr");
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_other_scb_open
+**
+** Description Check whether any other scb is in open state.
+**
+**
+** Returns TRUE if another scb is in open state, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+
+ for (int i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && p_scb != p_curr_scb && p_scb->state == BTA_AG_OPEN_ST) {
+ return TRUE;
+ }
+ }
+ /* no other scb found */
+ APPL_TRACE_DEBUG("No other ag scb open");
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_scb_open
+**
+** Description Check whether given scb is in open state.
+**
+**
+** Returns TRUE if scb is in open state, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_scb_open(tBTA_AG_SCB *p_curr_scb)
+{
+ if (p_curr_scb && p_curr_scb->in_use && p_curr_scb->state == BTA_AG_OPEN_ST) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_get_other_idle_scb
+**
+** Description Return other scb if it is in INIT st.
+**
+**
+** Returns Pointer to other scb if INIT st, NULL otherwise.
+**
+*******************************************************************************/
+tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb)
+{
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ UINT8 xx;
+
+ for (xx = 0; xx < BTA_AG_NUM_SCB; xx++, p_scb++) {
+ if (p_scb->in_use && (p_scb != p_curr_scb) && (p_scb->state == BTA_AG_INIT_ST)) {
+ return p_scb;
+ }
+ }
+ /* no other scb found */
+ APPL_TRACE_DEBUG("bta_ag_get_other_idle_scb: No idle AG scb");
+ return NULL;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_colli_timer_cback
+**
+** Description AG connection collision timer callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_colli_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_AG_SCB *p_scb;
+
+ APPL_TRACE_DEBUG ("bta_ag_colli_timer_cback");
+ if (p_tle) {
+ p_scb = (tBTA_AG_SCB *)p_tle->param;
+ if (p_scb) {
+ p_scb->colli_tmr_on = FALSE;
+ /* If the peer haven't opened AG connection */
+ /* we will restart opening process. */
+ bta_ag_resume_open (p_scb);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_collision_cback
+**
+** Description Get notified about collision.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_collision_cback (tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr)
+{
+ UINT16 handle;
+ tBTA_AG_SCB *p_scb;
+ UNUSED(status);
+ UNUSED(app_id);
+
+ /* Check if we have opening scb for the peer device. */
+ handle = bta_ag_idx_by_bdaddr (peer_addr);
+ p_scb = bta_ag_scb_by_idx (handle);
+
+ if (p_scb && (p_scb->state == BTA_AG_OPENING_ST)) {
+ if (id == BTA_ID_SYS) {
+ /* ACL collision */
+ APPL_TRACE_WARNING ("AG found collision (ACL) ...");
+ } else if (id == BTA_ID_AG) {
+ /* RFCOMM collision */
+ APPL_TRACE_WARNING ("AG found collision (RFCOMM) ...");
+ } else {
+ APPL_TRACE_WARNING ("AG found collision (\?\?\?) ...");
+ }
+ p_scb->state = BTA_AG_INIT_ST;
+ /* Cancel SDP if it had been started. */
+ if(p_scb->p_disc_db) {
+ (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+ bta_ag_free_db(p_scb, NULL);
+ }
+ /* reopen registered servers */
+ /* Collision may be detected before or after we close servers. */
+ if (bta_ag_is_server_closed (p_scb)) {
+ bta_ag_start_servers(p_scb, p_scb->reg_services);
+ }
+ /* Start timer to han */
+ p_scb->colli_timer.p_cback = (TIMER_CBACK*)&bta_ag_colli_timer_cback;
+ p_scb->colli_timer.param = (INT32)p_scb;
+ bta_sys_start_timer(&p_scb->colli_timer, 0, BTA_AG_COLLISION_TIMER);
+ p_scb->colli_tmr_on = TRUE;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_resume_open
+**
+** Description Resume opening process.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_resume_open (tBTA_AG_SCB *p_scb)
+{
+ if (p_scb) {
+ APPL_TRACE_DEBUG ("bta_ag_resume_open, Handle(%d)", bta_ag_scb_to_idx(p_scb));
+ /* resume opening process. */
+ if (p_scb->state == BTA_AG_INIT_ST) {
+ p_scb->state = BTA_AG_OPENING_ST;
+ bta_ag_start_open (p_scb, NULL);
+ }
+ } else {
+ APPL_TRACE_ERROR ("bta_ag_resume_open, Null p_scb");
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_enable
+**
+** Description Handle an API enable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_enable(tBTA_AG_DATA *p_data)
+{
+ /* initialize control block */
+ memset(&bta_ag_cb, 0, sizeof(tBTA_AG_CB));
+ /* store callback function */
+ bta_ag_cb.p_cback = p_data->api_enable.p_cback;
+ bta_ag_cb.parse_mode = p_data->api_enable.parse_mode;
+ /* check if mSBC support enabled */
+ if (strcmp(bta_ag_version, "1.6") == 0) {
+ bta_ag_cb.msbc_enabled = TRUE;
+ bta_ag_cb.scb->negotiated_codec = BTM_SCO_CODEC_MSBC;
+ } else{
+ bta_ag_cb.msbc_enabled = FALSE;
+ bta_ag_cb.scb->negotiated_codec = BTM_SCO_CODEC_CVSD;
+ }
+
+ /* set deault setting for eSCO/SCO */
+ BTM_WriteVoiceSettings(AG_VOICE_SETTINGS);
+ bta_sys_collision_register (BTA_ID_AG, bta_ag_collision_cback);
+ /* call callback with enable event */
+ (*bta_ag_cb.p_cback)(BTA_AG_ENABLE_EVT, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_disable
+**
+** Description Handle an API disable event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_disable(tBTA_AG_DATA *p_data)
+{
+ /* deregister all scbs in use */
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ BOOLEAN do_dereg = FALSE;
+ int i;
+
+ if (!bta_sys_is_register (BTA_ID_AG)) {
+ APPL_TRACE_ERROR("BTA AG is already disabled, ignoring ...");
+ return;
+ }
+ /* De-register with BTA system manager */
+ bta_sys_deregister(BTA_ID_AG);
+
+ for (i = 0; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use) {
+ bta_ag_sm_execute(p_scb, BTA_AG_API_DEREGISTER_EVT, p_data);
+ do_dereg = TRUE;
+ }
+ }
+
+ if (!do_dereg) {
+ /* Done, send callback evt to app */
+ (*bta_ag_cb.p_cback)(BTA_AG_DISABLE_EVT, NULL);
+ }
+ bta_sys_collision_register (BTA_ID_AG, NULL);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_register
+**
+** Description Handle an API event registers a new service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_register(tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ tBTA_AG_REGISTER reg;
+
+ /* allocate an scb */
+ if ((p_scb = bta_ag_scb_alloc()) != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_api_register: p_scb 0x%08x ", (unsigned int)p_scb);
+ bta_ag_sm_execute(p_scb, p_data->hdr.event, p_data);
+ } else {
+ reg.status = BTA_AG_FAIL_RESOURCES;
+ (*bta_ag_cb.p_cback)(BTA_AG_REGISTER_EVT, (tBTA_AG *) ®);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_api_result
+**
+** Description Handle an API result event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_api_result(tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ int i;
+
+ if (p_data->hdr.layer_specific != BTA_AG_HANDLE_ALL) {
+ if ((p_scb = bta_ag_scb_by_idx(p_data->hdr.layer_specific)) != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_api_result: p_scb 0x%08x ", (unsigned int)p_scb);
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ } else {
+ for (i = 0, p_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; i++, p_scb++) {
+ if (p_scb->in_use && p_scb->svc_conn) {
+ APPL_TRACE_DEBUG("bta_ag_api_result p_scb 0x%08x ", (unsigned int)p_scb);
+ bta_ag_sm_execute(p_scb, BTA_AG_API_RESULT_EVT, p_data);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sm_execute
+**
+** Description State machine event handling function for AG
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_ST_TBL state_table;
+ UINT8 action;
+
+#if BTA_AG_DEBUG == TRUE
+ UINT16 in_event = event;
+ UINT8 in_state = p_scb->state;
+ /* Ignore displaying of AT results when not connected (Ignored in state machine) */
+ if (in_event != BTA_AG_API_RESULT_EVT || p_scb->state == BTA_AG_OPEN_ST) {
+ APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d (%s), Event 0x%04x (%s)",
+ bta_ag_scb_to_idx(p_scb),
+ p_scb->state, bta_ag_state_str(p_scb->state),
+ event, bta_ag_evt_str(event, p_data->api_result.result));
+ }
+#else
+ APPL_TRACE_EVENT("AG evt (hdl 0x%04x): State %d, Event 0x%04x",
+ bta_ag_scb_to_idx(p_scb), p_scb->state, event);
+#endif
+ event &= 0x00FF;
+ if (event >= (BTA_AG_MAX_EVT & 0x00FF)) {
+ APPL_TRACE_ERROR("AG evt out of range, ignoring...");
+ return;
+ }
+ /* look up the state table for the current state */
+ state_table = bta_ag_st_tbl[p_scb->state];
+ /* set next state */
+ p_scb->state = state_table[event][BTA_AG_NEXT_STATE];
+ /* execute action functions */
+ for (int i = 0; i < BTA_AG_ACTIONS; i++) {
+ if ((action = state_table[event][i]) != BTA_AG_IGNORE) {
+ (*bta_ag_action[action])(p_scb, p_data);
+ } else {
+ break;
+ }
+ }
+#if BTA_AG_DEBUG == TRUE
+ if (p_scb->state != in_state) {
+ APPL_TRACE_EVENT("BTA AG State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_state_str(in_state),
+ bta_ag_state_str(p_scb->state),
+ bta_ag_evt_str(in_event, p_data->api_result.result));
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_hdl_event
+**
+** Description Data gateway main event handling function.
+**
+**
+** Returns BOOLEAN
+**
+*******************************************************************************/
+BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg)
+{
+ tBTA_AG_SCB *p_scb;
+ APPL_TRACE_DEBUG("bta_ag_hdl_event: Event 0x%04x ", p_msg->event);
+
+ switch (p_msg->event) {
+ /* handle enable event */
+ case BTA_AG_API_ENABLE_EVT:
+ bta_ag_api_enable((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle disable event */
+ case BTA_AG_API_DISABLE_EVT:
+ bta_ag_api_disable((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle register event */
+ case BTA_AG_API_REGISTER_EVT:
+ bta_ag_api_register((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* handle result event */
+ case BTA_AG_API_RESULT_EVT:
+ bta_ag_api_result((tBTA_AG_DATA *) p_msg);
+ break;
+
+ /* all others reference scb by handle */
+ default:
+ if ((p_scb = bta_ag_scb_by_idx(p_msg->layer_specific)) != NULL) {
+ APPL_TRACE_DEBUG("bta_ag_hdl_event: p_scb 0x%08x ", (unsigned int)p_scb);
+ bta_ag_sm_execute(p_scb, p_msg->event, (tBTA_AG_DATA *) p_msg);
+ }
+ break;
+ }
+ return TRUE;
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions controlling the RFCOMM
+ * connections.
+ *
+ ******************************************************************************/
+
+
+#include <string.h>
+#include "bta_ag_int.h"
+#include "bta/bta_api.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_ag_co.h"
+#include "bta/utl.h"
+#include "stack/btm_api.h"
+#include "stack/port_api.h"
+#include "stack/rfcdefs.h"
+#include "common/bt_trace.h"
+#include "osi/allocator.h"
+
+
+#if (BTA_AG_INCLUDED == TRUE)
+/* Event mask for RfCOMM port callback */
+#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR
+
+/* each scb has its own rfcomm callbacks */
+void bta_ag_port_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_port_cback_3(UINT32 code, UINT16 port_handle);
+
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 port_handle);
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 port_handle);
+
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len);
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len);
+
+/* rfcomm callback function tables */
+typedef tPORT_CALLBACK *tBTA_AG_PORT_CBACK;
+const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] =
+{
+ bta_ag_port_cback_1,
+ bta_ag_port_cback_2,
+ bta_ag_port_cback_3
+};
+
+const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] =
+{
+ bta_ag_mgmt_cback_1,
+ bta_ag_mgmt_cback_2,
+ bta_ag_mgmt_cback_3
+};
+
+typedef tPORT_DATA_CALLBACK *tBTA_AG_DATA_CBACK;
+const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] =
+{
+ bta_ag_data_cback_1,
+ bta_ag_data_cback_2,
+ bta_ag_data_cback_3
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_port_cback
+**
+** Description RFCOMM Port callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_port_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+ BT_HDR *p_buf;
+ tBTA_AG_SCB *p_scb;
+ UNUSED(code);
+
+ if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) {
+ /* ignore port events for port handles other than connected handle */
+ if (port_handle != p_scb->conn_handle) {
+ APPL_TRACE_DEBUG("ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d",
+ port_handle, p_scb->conn_handle, handle);
+ return;
+ }
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
+ p_buf->event = BTA_AG_RFC_DATA_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_mgmt_cback
+**
+** Description RFCOMM management callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_mgmt_cback(UINT32 code, UINT16 port_handle, UINT16 handle)
+{
+ tBTA_AG_RFC *p_buf;
+ tBTA_AG_SCB *p_scb;
+ UINT16 event;
+ UINT8 i;
+ BOOLEAN found_handle = FALSE;
+
+ APPL_TRACE_DEBUG("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d",
+ code, port_handle, handle);
+
+ if ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) {
+ /* ignore close event for port handles other than connected handle */
+ if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) {
+ APPL_TRACE_DEBUG("ag_mgmt_cback ignoring handle:%d", port_handle);
+ return;
+ }
+
+ if (code == PORT_SUCCESS) {
+ if (p_scb->conn_handle) {
+ /* Outgoing connection */
+ if (port_handle == p_scb->conn_handle)
+ found_handle = TRUE;
+ } else {
+ /* Incoming connection */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ if (port_handle == p_scb->serv_handle[i])
+ found_handle = TRUE;
+ }
+ }
+
+ if (!found_handle) {
+ APPL_TRACE_ERROR ("bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
+ return;
+ }
+ event = BTA_AG_RFC_OPEN_EVT;
+ } else if (port_handle == p_scb->conn_handle) {
+ /* distinguish server close events */
+ event = BTA_AG_RFC_CLOSE_EVT;
+ } else {
+ event = BTA_AG_RFC_SRV_CLOSE_EVT;
+ }
+
+ if ((p_buf = (tBTA_AG_RFC *) osi_malloc(sizeof(tBTA_AG_RFC))) != NULL) {
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = handle;
+ p_buf->port_handle = port_handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_data_cback
+**
+** Description RFCOMM data callback
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static int bta_ag_data_cback(UINT16 port_handle, void *p_data, UINT16 len, UINT16 handle)
+{
+ UNUSED(port_handle);
+
+ /* call data call-out directly */
+ bta_ag_co_tx_write(handle, (UINT8 *) p_data, len);
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_port_cback_1 to 3
+** bta_ag_mgmt_cback_1 to 3
+**
+** Description RFCOMM callback functions. This is an easy way to
+** distinguish scb from the callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_mgmt_cback_1(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 1);}
+void bta_ag_mgmt_cback_2(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 2);}
+void bta_ag_mgmt_cback_3(UINT32 code, UINT16 handle) {bta_ag_mgmt_cback(code, handle, 3);}
+void bta_ag_port_cback_1(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 1);}
+void bta_ag_port_cback_2(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 2);}
+void bta_ag_port_cback_3(UINT32 code, UINT16 handle) {bta_ag_port_cback(code, handle, 3);}
+
+/*******************************************************************************
+**
+** Function bta_ag_data_cback_1 to 3
+**
+** Description RFCOMM data callback functions. This is an easy way to
+** distinguish scb from the callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+int bta_ag_data_cback_1(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 1);
+}
+int bta_ag_data_cback_2(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 2);
+}
+int bta_ag_data_cback_3(UINT16 port_handle, void *p_data, UINT16 len)
+{
+ return bta_ag_data_cback(port_handle, p_data, len, 3);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_setup_port
+**
+** Description Setup RFCOMM port for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_setup_port(tBTA_AG_SCB *p_scb, UINT16 handle)
+{
+ UINT16 i = bta_ag_scb_to_idx(p_scb) - 1;
+
+ /* set up data callback if using pass through mode */
+ if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) {
+ PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]);
+ }
+ PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK);
+ PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_start_servers
+**
+** Description Setup RFCOMM servers for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+ int bta_ag_port_status;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ BTM_SetSecurityLevel(FALSE, "", bta_ag_sec_id[i], p_scb->serv_sec_mask,
+ BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_ag_cb.profile[i].scn);
+
+ bta_ag_port_status = RFCOMM_CreateConnection(bta_ag_uuid[i], bta_ag_cb.profile[i].scn,
+ TRUE, BTA_AG_MTU, (UINT8 *) bd_addr_any, &(p_scb->serv_handle[i]),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+
+ if( bta_ag_port_status == PORT_SUCCESS ) {
+ bta_ag_setup_port(p_scb, p_scb->serv_handle[i]);
+ } else {
+ /* TODO: CR#137125 to handle to error properly */
+ APPL_TRACE_DEBUG("bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", bta_ag_port_status);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_close_servers
+**
+** Description Close RFCOMM servers port for use by AG.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services)
+{
+ int i;
+
+ services >>= BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ RFCOMM_RemoveServer(p_scb->serv_handle[i]);
+ p_scb->serv_handle[i] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_is_server_closed
+**
+** Description Returns TRUE if all servers are closed.
+**
+**
+** Returns TRUE if all servers are closed, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb)
+{
+ UINT8 i;
+ BOOLEAN is_closed = TRUE;
+
+ for (i = 0; i < BTA_AG_NUM_IDX; i++) {
+ if (p_scb->serv_handle[i] != 0)
+ is_closed = FALSE;
+ }
+ return is_closed;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_do_open
+**
+** Description Open an RFCOMM connection to the peer device.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ BTM_SetSecurityLevel(TRUE, "", bta_ag_sec_id[p_scb->conn_service],
+ p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, p_scb->peer_scn);
+
+ if (RFCOMM_CreateConnection(bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn,
+ FALSE, BTA_AG_MTU, p_scb->peer_addr, &(p_scb->conn_handle),
+ bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == PORT_SUCCESS) {
+ bta_ag_setup_port(p_scb, p_scb->conn_handle);
+ APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d", p_scb->conn_handle);
+ } else {
+ /* RFCOMM create connection failed; send ourselves RFCOMM close event */
+ bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_rfc_do_close
+**
+** Description Close RFCOMM connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_RFC *p_buf;
+ UNUSED(p_data);
+
+ if (p_scb->conn_handle) {
+ RFCOMM_RemoveConnection(p_scb->conn_handle);
+ } else {
+ /* Close API was called while AG is in Opening state. */
+ /* Need to trigger the state machine to send callback to the app */
+ /* and move back to INIT state. */
+ if ((p_buf = (tBTA_AG_RFC *) osi_malloc(sizeof(tBTA_AG_RFC))) != NULL) {
+ p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT;
+ p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb);
+ bta_sys_sendmsg(p_buf);
+ }
+ /* Cancel SDP if it had been started. */
+ /*
+ if(p_scb->p_disc_db)
+ {
+ (void)SDP_CancelServiceSearch (p_scb->p_disc_db);
+ }
+ */
+ }
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains functions for managing the SCO connection used in AG.
+ *
+ ******************************************************************************/
+#include <stddef.h>
+#include "bta_ag_int.h"
+#include "bta/bta_api.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_ag_co.h"
+#include "bta/bta_hfp_defs.h"
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+#include "bta/bta_dm_co.h"
+#include "hci/hci_audio.h"
+#endif
+
+#include "bta/utl.h"
+#include "stack/btm_api.h"
+#include "common/bt_trace.h"
+#include "osi/allocator.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+
+#ifndef BTA_AG_CODEC_NEGO_TIMEOUT
+#define BTA_AG_CODEC_NEGO_TIMEOUT 3000
+#endif
+
+static char *bta_ag_sco_evt_str(UINT8 event);
+static char *bta_ag_sco_state_str(UINT8 state);
+
+#define BTA_AG_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
+
+/* sco events */
+enum
+{
+ BTA_AG_SCO_LISTEN_E, /* listen request */
+ BTA_AG_SCO_OPEN_E, /* open request */
+ BTA_AG_SCO_XFER_E, /* transfer request */
+#if (BTM_WBS_INCLUDED == TRUE )
+ BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */
+ BTA_AG_SCO_REOPEN_E, /* Retry with other codec when failed */
+#endif
+ BTA_AG_SCO_CLOSE_E, /* close request */
+ BTA_AG_SCO_SHUTDOWN_E, /* shutdown request */
+ BTA_AG_SCO_CONN_OPEN_E, /* sco open */
+ BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ BTA_AG_SCO_CI_DATA_E /* SCO data ready */
+#endif
+};
+
+#if (BTM_WBS_INCLUDED == TRUE )
+#define BTA_AG_NUM_CODECS 3
+#define BTA_AG_ESCO_SETTING_IDX_CVSD 0 /* eSCO setting for CVSD */
+#define BTA_AG_ESCO_SETTING_IDX_T1 1 /* eSCO setting for mSBC T1 */
+#define BTA_AG_ESCO_SETTING_IDX_T2 2 /* eSCO setting for mSBC T2 */
+
+static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
+{
+ /* CVSD */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+ },
+ /* mSBC T1 */
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */
+ 8, /* 8 ms */
+ BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + NO_2_EV3 */
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 ),
+ BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ },
+ /* mSBC T2*/
+ {
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */
+ 13, /* 13 ms */
+ BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + 2-EV3 */
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
+ }
+};
+#else
+/* WBS not included, CVSD by default */
+static const tBTM_ESCO_PARAMS bta_ag_esco_params =
+{
+ BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
+ BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
+ 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
+ 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
+ (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
+ BTM_SCO_PKT_TYPES_MASK_HV2 +
+ BTM_SCO_PKT_TYPES_MASK_HV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV3 +
+ BTM_SCO_PKT_TYPES_MASK_EV4 +
+ BTM_SCO_PKT_TYPES_MASK_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
+ BTM_ESCO_RETRANS_POWER /* Retransmission effort */
+};
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_cback
+**
+** Description BTM SCO connection callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_conn_cback(UINT16 sco_idx)
+{
+ UINT16 handle;
+ BT_HDR *p_buf;
+ tBTA_AG_SCB *p_scb = &bta_ag_cb.scb[0];
+ tBTM_ESCO_DATA sco_data;
+
+ APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
+
+ /* match callback to scb; first check current sco scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+ {
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+ /* then check for scb connected to this peer */
+ else
+ {
+ /* Check if SLC is up */
+ handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
+ p_scb = bta_ag_scb_by_idx(handle);
+ if(p_scb && !p_scb->svc_conn)
+ handle = 0;
+ }
+
+ if (handle != 0)
+ {
+ BTM_ReadEScoLinkParms(sco_idx, &sco_data);
+
+ p_scb->link_type = sco_data.link_type;
+ p_scb->tx_interval = sco_data.tx_interval;
+ p_scb->retrans_window = sco_data.retrans_window;
+ p_scb->air_mode = sco_data.air_mode;
+
+ if (sco_data.air_mode == BTM_SCO_AIR_MODE_CVSD)
+ {
+ p_scb->out_pkt_len = sco_data.tx_pkt_len * 2;
+ p_scb->in_pkt_len = sco_data.rx_pkt_len * 2;
+ }
+ else {
+ p_scb->out_pkt_len = sco_data.tx_pkt_len;
+ p_scb->in_pkt_len = sco_data.rx_pkt_len;
+ }
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_SCO_OPEN_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ /* no match found; disconnect sco, init sco variables */
+ else
+ {
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ BTM_RemoveSco(sco_idx);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_disc_cback
+**
+** Description BTM SCO disconnection callback.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_disc_cback(UINT16 sco_idx)
+{
+ BT_HDR *p_buf;
+ UINT16 handle = 0;
+
+ APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", (unsigned int)sco_idx, (unsigned int)bta_ag_cb.sco.p_curr_scb, (unsigned int)bta_ag_cb.sco.state);
+
+ APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
+ (unsigned int) &bta_ag_cb.scb[0], (unsigned int)bta_ag_cb.scb[0].in_use, (unsigned int)bta_ag_cb.scb[0].sco_idx, (unsigned int)bta_ag_cb.scb[0].state);
+ APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
+ (unsigned int) &bta_ag_cb.scb[1], (unsigned int) bta_ag_cb.scb[1].in_use, (unsigned int) bta_ag_cb.scb[1].sco_idx, (unsigned int) bta_ag_cb.scb[1].state);
+
+ /* match callback to scb */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
+ {
+ /* We only care about callbacks for the active SCO */
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx)
+ {
+ if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF)
+ return;
+ }
+ handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
+ }
+
+ if (handle != 0)
+ {
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
+ APPL_TRACE_DEBUG("bta_ag_sco_disc_cback sco close config status = %d", status);
+ /* SCO clean up here */
+ bta_ag_sco_co_close();
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* Restore settings */
+ if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
+ {
+ /* set_sco_codec(BTM_SCO_CODEC_NONE); we should get a close */
+ BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
+
+ /* If SCO open was initiated by AG and failed for mSBC, then attempt
+ mSBC with T1 settings i.e. 'Safe Settings'. If this fails, then switch to CVSD */
+ if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
+ {
+ if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2)
+ {
+ APPL_TRACE_DEBUG("Fallback to mSBC T1 settings");
+ bta_ag_cb.sco.p_curr_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T1;
+ }
+ else
+ {
+ APPL_TRACE_DEBUG("Fallback to CVSD settings");
+ bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
+ }
+ }
+ }
+
+ bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+
+ if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL)
+ {
+ p_buf->event = BTA_AG_SCO_CLOSE_EVT;
+ p_buf->layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+ /* no match found */
+ else
+ {
+ APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
+
+ /* sco could be closed after scb dealloc'ed */
+ if (bta_ag_cb.sco.p_curr_scb != NULL)
+ {
+ bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ }
+}
+
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_sco_read_cback
+**
+** Description Callback function is the callback function for incoming
+** SCO data over HCI.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_read_cback(UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
+{
+ if (status != BTM_SCO_DATA_CORRECT)
+ {
+ APPL_TRACE_DEBUG("bta_ag_sco_read_cback: status(%d)", status);
+ }
+
+ /* Callout function must free the data. */
+ bta_ag_sco_co_in_data(p_data, status);
+}
+#endif
+/*******************************************************************************
+**
+** Function bta_ag_remove_sco
+**
+** Description Removes the specified SCO from the system.
+** If only_active is TRUE, then SCO is only removed if connected
+**
+** Returns BOOLEAN - TRUE if Sco removal was started
+**
+*******************************************************************************/
+static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active)
+{
+ BOOLEAN removed_started = FALSE;
+ tBTM_STATUS status;
+
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+ {
+ if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx)
+ {
+ status = BTM_RemoveSco(p_scb->sco_idx);
+
+ APPL_TRACE_DEBUG("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
+
+ if (status == BTM_CMD_STARTED)
+ {
+ /* Sco is connected; set current control block */
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ removed_started = TRUE;
+ }
+ /* If no connection reset the sco handle */
+ else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
+ {
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ }
+ }
+ }
+ return removed_started;
+}
+
+
+/*******************************************************************************
+**
+** Function bta_ag_esco_connreq_cback
+**
+** Description BTM eSCO connection requests and eSCO change requests
+** Only the connection requests are processed by BTA.
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
+{
+ tBTA_AG_SCB *p_scb;
+ UINT16 handle;
+ UINT16 sco_inx = p_data->conn_evt.sco_inx;
+
+ /* Only process connection requests */
+ if (event == BTM_ESCO_CONN_REQ_EVT)
+ {
+ if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
+ ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn)
+ {
+ p_scb->sco_idx = sco_inx;
+
+ /* If no other SCO active, allow this one */
+ if (!bta_ag_cb.sco.p_curr_scb)
+ {
+ APPL_TRACE_EVENT("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ else /* Begin a transfer: Close current SCO before responding */
+ {
+ APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER");
+ bta_ag_cb.sco.p_xfer_scb = p_scb;
+ bta_ag_cb.sco.conn_data = p_data->conn_evt;
+ bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
+
+ if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE))
+ {
+ APPL_TRACE_ERROR("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx);
+ bta_ag_cb.sco.p_xfer_scb = NULL;
+ bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
+
+ bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
+ }
+ }
+ }
+ /* If error occurred send reject response immediately */
+ else
+ {
+ APPL_TRACE_WARNING("no scb for bta_ag_esco_connreq_cback or no resources");
+ BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
+ }
+ }
+ /* Received a change in the esco link */
+ else if (event == BTM_ESCO_CHG_EVT)
+ {
+ APPL_TRACE_EVENT("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
+ p_data->chg_evt.sco_inx,
+ p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len,
+ p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_cback_sco
+**
+** Description Call application callback function with SCO event.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+ tBTA_AG_HDR sco;
+
+ sco.handle = bta_ag_scb_to_idx(p_scb);
+ sco.app_id = p_scb->app_id;
+
+ /* call close cback */
+ (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_create_sco
+**
+** Description Create a sco connection and is is_orig is TRUE means AG originate
+** this connection, if FALSE it's peer device originate the connection.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
+{
+ tBTM_STATUS status;
+ UINT8 *p_bd_addr = NULL;
+ tBTM_ESCO_PARAMS params;
+#if (BTM_WBS_INCLUDED == TRUE)
+ tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD;
+ int codec_index = 0;
+#endif
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ tBTM_SCO_ROUTE_TYPE sco_route;
+ tBTA_HFP_CODEC_INFO codec_info = {BTA_HFP_SCO_CODEC_PCM};
+ UINT32 pcm_sample_rate;
+#endif
+
+ /* Make sure this sco handle is not already in use */
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+ {
+ APPL_TRACE_WARNING("bta_ag_create_sco: Index 0x%04x Already In Use!",
+ p_scb->sco_idx);
+ return;
+ }
+
+#if (BTM_WBS_INCLUDED == TRUE)
+
+ if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) && !p_scb->codec_fallback && !p_scb->retry_with_sco_only)
+ {
+ esco_codec = BTM_SCO_CODEC_MSBC;
+ }
+ if (p_scb->codec_fallback)
+ {
+ p_scb->codec_fallback = FALSE;
+ /* Force AG to send +BCS for the next audio connection. */
+ p_scb->codec_updated = TRUE;
+ }
+ /* If WBS included, use CVSD by default, index is 0 for CVSD by initialization */
+ /* If eSCO codec is mSBC, index is T2 or T1 */
+ if (esco_codec == BTM_SCO_CODEC_MSBC)
+ {
+ if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2)
+ {
+ codec_index = BTA_AG_ESCO_SETTING_IDX_T2;
+ }
+ else
+ {
+ codec_index = BTA_AG_ESCO_SETTING_IDX_T1;
+ }
+ }
+ params = bta_ag_esco_params[codec_index];
+#else
+ /* When WBS is not included, use CVSD by default */
+ params = bta_ag_esco_params;
+#endif
+
+ if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
+ params = bta_ag_cb.sco.params;
+
+ if(!bta_ag_cb.sco.param_updated)
+ {
+#if (BTM_WBS_INCLUDED == TRUE)
+ if (esco_codec == BTM_SCO_CODEC_CVSD) /* For CVSD */
+#endif
+ {
+ /* Use the application packet types (5 slot EV packets not allowed) */
+ params.packet_types = p_bta_ag_cfg->sco_pkt_types |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
+ }
+ }
+
+ /* if initiating, set current scb and peer bd addr */
+ if (is_orig)
+ {
+ /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
+ /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
+ if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only)
+ {
+ BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms);
+ /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
+ if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
+ ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO))
+ {
+#if (BTM_WBS_INCLUDED == TRUE)
+ if (esco_codec != BTA_AG_CODEC_MSBC)
+ {
+ p_scb->retry_with_sco_only = TRUE;
+ APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
+ }
+ else /* Do not use SCO when using mSBC */
+ {
+ p_scb->retry_with_sco_only = FALSE;
+ APPL_TRACE_API("Setting retry_with_sco_only to FALSE");
+ }
+#else
+ p_scb->retry_with_sco_only = TRUE;
+ APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
+#endif
+ }
+ }
+ else
+ {
+ if(p_scb->retry_with_sco_only){
+ APPL_TRACE_API("retrying with SCO only");
+ }
+ p_scb->retry_with_sco_only = FALSE;
+ BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms);
+ }
+
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP, esco_codec);
+
+ /* This setting may not be necessary */
+ /* To be verified with stable 2049 boards */
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ BTM_WriteVoiceSettings(BTM_VOICE_SETTING_TRANS);
+ else
+ BTM_WriteVoiceSettings(BTM_VOICE_SETTING_CVSD);
+ /* save the current codec because sco_codec can be updated while SCO is open. */
+ p_scb->inuse_codec = esco_codec;
+#else
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#if (BTM_WBS_INCLUDED == TRUE)
+ if (esco_codec == BTA_AG_CODEC_MSBC)
+ pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_16K;
+#endif
+ pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
+ sco_route = bta_ag_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id);
+#endif
+
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+ BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ else{
+ p_scb->retry_with_sco_only = FALSE;
+ }
+
+ p_bd_addr = p_scb->peer_addr;
+
+ status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types, &p_scb->sco_idx, bta_ag_sco_conn_cback, bta_ag_sco_disc_cback);
+
+ if (status == BTM_CMD_STARTED)
+ {
+ if (!is_orig)
+ {
+ BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
+ }
+ else /* Initiating the connection, set the current sco handle */
+ {
+ bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
+ }
+ }
+
+ APPL_TRACE_API("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
+ is_orig, p_scb->sco_idx, status, params.packet_types);
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function bta_ag_attempt_msbc_safe_settings
+**
+** Description Checks if ESCO connection needs to be attempted using mSBC T1(safe) settings
+**
+**
+** Returns TRUE if T1 settings has to be used, FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN bta_ag_attempt_msbc_safe_settings(tBTA_AG_SCB *p_scb)
+{
+ if (p_scb->svc_conn && p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
+ p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_cn_timer_cback
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle)
+{
+ tBTA_AG_SCB *p_scb;
+
+ if (p_tle)
+ {
+ p_scb = (tBTA_AG_SCB *)p_tle->param;
+
+ if (p_scb)
+ {
+ /* Announce that codec negotiation failed. */
+ bta_ag_sco_codec_nego(p_scb, FALSE);
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_codec_negotiate
+**
+** Description Initiate codec negotiation by sending AT command.
+** If not necessary, skip negotiation.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
+{
+ bta_ag_cb.sco.p_curr_scb = p_scb;
+
+ if ((p_scb->codec_updated || p_scb->codec_fallback ||
+ bta_ag_attempt_msbc_safe_settings(p_scb)) &&
+ (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC))
+ {
+ /* Change the power mode to Active until sco open is completed. */
+ bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* Send +BCS to the peer */
+ bta_ag_send_bcs(p_scb, NULL);
+
+ /* Start timer to handle timeout */
+ p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
+ p_scb->cn_timer.param = (INT32)p_scb;
+ bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
+ }
+ else
+ {
+ /* use same codec type as previous SCO connection, skip codec negotiation */
+ APPL_TRACE_DEBUG("use same codec type as previous SCO connection,skip codec negotiation");
+ bta_ag_sco_codec_nego(p_scb, TRUE);
+ }
+}
+#endif /* (BTM_WBS_INCLUDED == TRUE ) */
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_event
+**
+** Description AG Sco State Machine
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
+{
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
+ BT_HDR *p_buf;
+#endif
+#if (BTM_WBS_INCLUDED == TRUE)
+ tBTA_AG_SCB *p_cn_scb = NULL; /* For codec negotiation */
+#endif
+ UINT8 in_state = p_sco->state;
+ APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
+ p_scb->sco_idx, p_sco->state,
+ bta_ag_sco_state_str(p_sco->state), event, bta_ag_sco_evt_str(event));
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ if (event == BTA_AG_SCO_CI_DATA_E)
+ {
+ UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
+ UINT16 len_to_send = 0;
+ while (TRUE)
+ {
+ p_buf = osi_calloc(sizeof(BT_HDR) + pkt_offset + p_scb->out_pkt_len);
+ if (!p_buf) {
+ APPL_TRACE_WARNING("%s, no mem", __FUNCTION__);
+ break;
+ }
+ p_buf->offset = pkt_offset;
+ len_to_send = bta_ag_sco_co_out_data(p_buf->data + pkt_offset);
+ p_buf->len = len_to_send;
+
+ if (len_to_send == p_scb->out_pkt_len)
+ {
+ if (p_sco->state == BTA_AG_SCO_OPEN_ST) {
+ tBTM_STATUS write_stat = BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
+ if (write_stat != BTM_SUCCESS) {
+ break;
+ }
+ else {
+ osi_free(p_buf);
+ }
+ }
+ else {
+ osi_free(p_buf);
+ break;
+ }
+ }
+ return;
+ }
+ }
+#endif
+
+ /* State Machine Start */
+ switch (p_sco->state)
+ {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, FALSE);
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+#else
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+ if (p_scb == p_sco->p_curr_scb)
+ p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* remove listening connection */
+ /* Ignore the event. We need to keep listening SCO for the active SLC */
+ APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CODEC_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ bta_ag_create_sco(p_scb, FALSE);
+ break;
+
+ case BTA_AG_SCO_CN_DONE_E:
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+
+ if (p_scb == p_sco->p_curr_scb)
+ p_sco->p_curr_scb = NULL;
+
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* sco open is not started yet. just go back to listening */
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+#endif
+
+ case BTA_AG_SCO_OPENING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ case BTA_AG_SCO_REOPEN_E:
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+ break;
+#endif
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPEN_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_CL_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not opening scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+
+ break;
+
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, TRUE);
+
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* sco failed; create sco listen connection */
+
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection */
+ bta_ag_remove_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* closed sco; place in listen mode and
+ accept the transferred connection */
+ bta_ag_create_sco(p_scb, FALSE); /* Back into listen mode */
+ /* Accept sco connection with xfer scb */
+ bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+ p_sco->p_curr_scb = p_sco->p_xfer_scb;
+ p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
+ p_sco->p_xfer_scb = NULL;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* second headset has now joined */
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* close current sco connection */
+ bta_ag_remove_sco(p_sco->p_curr_scb, TRUE);
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* close sco connection if active */
+ if (bta_ag_remove_sco(p_scb, TRUE))
+ {
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* remove all listening connections */
+ bta_ag_remove_sco(p_scb, FALSE);
+ /* If SCO was active on this scb, close it */
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ }
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_OPEN_E:
+ p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
+ break;
+
+ case BTA_AG_SCO_XFER_E:
+ /* save xfer scb */
+ p_sco->p_xfer_scb = p_scb;
+ p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* If not closing scb, just close it */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ /* remove listening connection */
+ bta_ag_remove_sco(p_scb, FALSE);
+ }
+ else
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* peer closed sco; create sco listen connection */
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CLOSE_E:
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_scb;
+#else
+ /* open sco connection */
+ bta_ag_create_sco(p_scb, TRUE);
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection so headset can be transferred
+ Probably entered this state from "opening state" */
+ bta_ag_remove_sco(p_scb, TRUE);
+ break;
+
+ case BTA_AG_SCO_CLOSE_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+ p_sco->state = BTA_AG_SCO_CLOSING_ST;
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ /* clear xfer scb */
+ p_sco->p_xfer_scb = NULL;
+ p_sco->state = BTA_AG_SCO_SHUTTING_ST;
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* closed sco; place old sco in listen mode,
+ take current sco out of listen, and
+ create originating sco for current */
+ bta_ag_create_sco(p_scb, FALSE);
+ bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* start codec negotiation */
+ p_sco->state = BTA_AG_SCO_CODEC_ST;
+ p_cn_scb = p_sco->p_xfer_scb;
+ p_sco->p_xfer_scb = NULL;
+#else
+ /* create sco connection to peer */
+ bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
+ p_sco->p_xfer_scb = NULL;
+ p_sco->state = BTA_AG_SCO_OPENING_ST;
+#endif
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTTING_ST:
+ switch (event)
+ {
+ case BTA_AG_SCO_CONN_OPEN_E:
+ /* close sco connection; wait for conn close event */
+ bta_ag_remove_sco(p_scb, TRUE);
+ break;
+
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ /* If last SCO instance then finish shutting down */
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ /* If SCO closed for other HS which is not being disconnected,
+ then create listen sco connection for it as scb still open */
+ if (bta_ag_scb_open(p_scb))
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ case BTA_AG_SCO_LISTEN_E:
+ /* create sco listen connection (Additional channel) */
+ if (p_scb != p_sco->p_curr_scb)
+ {
+ bta_ag_create_sco(p_scb, FALSE);
+ }
+ break;
+
+ case BTA_AG_SCO_SHUTDOWN_E:
+ if (!bta_ag_other_scb_open(p_scb))
+ {
+ p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
+ }
+ else /* Other instance is still listening */
+ {
+ p_sco->state = BTA_AG_SCO_LISTEN_ST;
+ }
+
+ if (p_scb == p_sco->p_curr_scb)
+ {
+ p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+ p_sco->p_curr_scb = NULL;
+ }
+ break;
+
+ default:
+ APPL_TRACE_WARNING("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (p_sco->state != in_state)
+ {
+ APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
+ bta_ag_sco_state_str(in_state),
+ bta_ag_sco_state_str(p_sco->state),
+ bta_ag_sco_evt_str(event));
+ }
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ if (p_cn_scb)
+ {
+ bta_ag_codec_negotiate(p_cn_scb);
+ }
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_is_open
+**
+** Description Check if sco is open for this scb.
+**
+**
+** Returns TRUE if sco open for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb)
+{
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_is_opening
+**
+** Description Check if sco is in Opening state.
+**
+**
+** Returns TRUE if sco is in Opening state for this scb, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb)
+{
+#if (BTM_WBS_INCLUDED == TRUE )
+ return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) ||
+ (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+#else
+ return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
+ (bta_ag_cb.sco.p_curr_scb == p_scb));
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_listen
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_open
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT8 event;
+ UNUSED(p_data);
+
+ /* if another scb using sco, this is a transfer */
+ if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
+ {
+ event = BTA_AG_SCO_XFER_E;
+ }
+ /* else it is an open */
+ else
+ {
+ event = BTA_AG_SCO_OPEN_E;
+ }
+
+ bta_ag_sco_event(p_scb, event);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_close
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ /* if scb is in use */
+#if (BTM_WBS_INCLUDED == TRUE )
+ /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */
+ if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
+#else
+ if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
+#endif
+ {
+ APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+ }
+}
+
+#if (BTM_WBS_INCLUDED == TRUE )
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_codec_nego
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result)
+{
+ if(result == TRUE)
+ {
+ /* Subsequent sco connection will skip codec negotiation */
+ p_scb->codec_updated = FALSE;
+
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
+ }
+ else /* codec negotiation failed */
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_shutdown
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_open
+**
+** Description
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
+
+ bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_ON, p_scb->inuse_codec);
+#else
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_ON);
+#endif
+ /* open SCO codec if SCO is routed through transport */
+ bta_ag_sco_co_open(bta_ag_scb_to_idx(p_scb), p_scb->air_mode, BTA_HFP_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT);
+#endif
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
+
+ p_scb->retry_with_sco_only = FALSE;
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* reset to mSBC T2 settings as the preferred */
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_close
+**
+** Description This function is called when a SCO connection is closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UINT16 handle = bta_ag_scb_to_idx(p_scb);
+ UNUSED(p_data);
+
+ /* clear current scb */
+ bta_ag_cb.sco.p_curr_scb = NULL;
+ p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* codec_fallback is set when AG is initiator and connection failed for mSBC. */
+ /* OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
+ if ((p_scb->codec_fallback && p_scb->svc_conn) ||
+ bta_ag_attempt_msbc_safe_settings(p_scb))
+ {
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
+ }
+ else if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+ {
+ /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */
+ bta_ag_create_sco(p_scb, TRUE);
+ }
+#else
+ /* retry_with_sco_only, will be set only when AG is initiator
+ ** and AG is first trying to establish an eSCO connection */
+ if (p_scb->retry_with_sco_only && p_scb->svc_conn)
+ {
+ bta_ag_create_sco(p_scb, TRUE);
+ }
+#endif
+ else
+ {
+ sco_state_t sco_state = bta_ag_cb.sco.p_xfer_scb ? SCO_STATE_OFF_TRANSFER : SCO_STATE_OFF;
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* Indicate if the closing of audio is because of transfer */
+ bta_ag_sco_audio_state(handle, p_scb->app_id, sco_state, p_scb->inuse_codec);
+#else
+ /* Indicate if the closing of audio is because of transfer */
+ bta_ag_sco_audio_state(handle, p_scb->app_id, sco_state);
+#endif
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
+
+ bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+ /* if av got suspended by this call, let it resume. */
+ /* In case call stays alive regardless of sco, av should not be affected. */
+ if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
+ || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END))
+ {
+ bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+ }
+
+ /* call app callback */
+ bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
+#if (BTM_WBS_INCLUDED == TRUE)
+ p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
+#endif
+ }
+ p_scb->retry_with_sco_only = FALSE;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_conn_rsp
+**
+** Description Process the SCO connection request
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
+{
+ tBTM_ESCO_PARAMS resp;
+ UINT8 hci_status = HCI_SUCCESS;
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ tBTA_HFP_CODEC_INFO codec_info = {BTA_HFP_SCO_CODEC_PCM};
+ UINT32 pcm_sample_rate;
+#endif
+
+ if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
+ bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
+ {
+ /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
+ if (bta_ag_cb.sco.param_updated)
+ {
+ resp = bta_ag_cb.sco.params;
+ }
+ else
+ {
+ resp.rx_bw = BTM_64KBITS_RATE;
+ resp.tx_bw = BTM_64KBITS_RATE;
+ resp.max_latency = 10;
+ resp.voice_contfmt = 0x60;
+ resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
+
+ if (p_data->link_type == BTM_LINK_TYPE_SCO)
+ {
+ resp.packet_types = (BTM_SCO_LINK_ONLY_MASK |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ else /* Allow controller to use all types available except 5-slot EDR */
+ {
+ resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
+ BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
+ BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
+ }
+ }
+
+ /* tell sys to stop av if any */
+ bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
+
+#if (BTM_WBS_INCLUDED == FALSE)
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP);
+#else
+ /* When HS initiated SCO, it cannot be WBS. */
+ /* Allow any platform specific pre-SCO set up to take place */
+ bta_ag_sco_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, SCO_STATE_SETUP,
+ BTA_AG_CODEC_CVSD);
+#endif
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+ pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
+ /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
+ BTM_ConfigScoPath(bta_ag_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
+ bta_ag_sco_read_cback, NULL, TRUE);
+#endif
+ }
+ else
+ hci_status = HCI_ERR_HOST_REJECT_DEVICE;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* If SCO open was initiated from HS, it must be CVSD */
+ p_scb->inuse_codec = BTA_AG_CODEC_NONE;
+#endif
+ BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_sco_data
+**
+** Description Process the SCO data ready callin event
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_scb);
+ UNUSED(p_data);
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+ bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
+#endif
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_set_esco_param
+**
+** Description Update esco parameters from script wrapper.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param)
+{
+ if(set_reset == FALSE) /* reset the parameters to default */
+ {
+ bta_ag_cb.sco.param_updated = FALSE;
+ APPL_TRACE_DEBUG("bta_ag_set_esco_param : Resetting ESCO parameters to default");
+ }
+ else
+ {
+ bta_ag_cb.sco.param_updated = TRUE;
+ bta_ag_cb.sco.params = *param;
+ APPL_TRACE_DEBUG("bta_ag_set_esco_param : Setting ESCO parameters");
+ }
+}
+
+/*******************************************************************************
+** Debugging functions
+*******************************************************************************/
+static char *bta_ag_sco_evt_str(UINT8 event)
+{
+ switch (event)
+ {
+ case BTA_AG_SCO_LISTEN_E:
+ return "Listen Request";
+ case BTA_AG_SCO_OPEN_E:
+ return "Open Request";
+ case BTA_AG_SCO_XFER_E:
+ return "Transfer Request";
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CN_DONE_E:
+ return "Codec Negotiation Done";
+ case BTA_AG_SCO_REOPEN_E:
+ return "Reopen Request";
+#endif
+ case BTA_AG_SCO_CLOSE_E:
+ return "Close Request";
+ case BTA_AG_SCO_SHUTDOWN_E:
+ return "Shutdown Request";
+ case BTA_AG_SCO_CONN_OPEN_E:
+ return "Opened";
+ case BTA_AG_SCO_CONN_CLOSE_E:
+ return "Closed";
+ case BTA_AG_SCO_CI_DATA_E :
+ return "Sco Data";
+ default:
+ return "Unknown SCO Event";
+ }
+}
+
+static char *bta_ag_sco_state_str(UINT8 state)
+{
+ switch (state)
+ {
+ case BTA_AG_SCO_SHUTDOWN_ST:
+ return "Shutdown";
+ case BTA_AG_SCO_LISTEN_ST:
+ return "Listening";
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_SCO_CODEC_ST:
+ return "Codec Negotiation";
+#endif
+ case BTA_AG_SCO_OPENING_ST:
+ return "Opening";
+ case BTA_AG_SCO_OPEN_CL_ST:
+ return "Open while closing";
+ case BTA_AG_SCO_OPEN_XFER_ST:
+ return "Opening while Transferring";
+ case BTA_AG_SCO_OPEN_ST:
+ return "Open";
+ case BTA_AG_SCO_CLOSING_ST:
+ return "Closing";
+ case BTA_AG_SCO_CLOSE_OP_ST:
+ return "Close while Opening";
+ case BTA_AG_SCO_CLOSE_XFER_ST:
+ return "Close while Transferring";
+ case BTA_AG_SCO_SHUTTING_ST:
+ return "Shutting Down";
+ default:
+ return "Unknown SCO State";
+ }
+}
+
+#endif //#if (BTA_AG_INCLUDED == TRUE)
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the audio gateway functions performing SDP
+ * operations.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include "bta_ag_int.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_ag_api.h"
+#include "bta/utl.h"
+#include "stack/sdp_api.h"
+#include "stack/btm_api.h"
+#include "common/bt_trace.h"
+#include "osi/allocator.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+
+/* Number of protocol elements in protocol element list. */
+#define BTA_AG_NUM_PROTO_ELEMS 2
+
+/* Number of elements in service class id list. */
+#define BTA_AG_NUM_SVC_ELEMS 2
+
+/* size of database for service discovery */
+#ifndef BTA_AG_DISC_BUF_SIZE
+#define BTA_AG_DISC_BUF_SIZE (4096+16)
+#endif
+
+/* declare sdp callback functions */
+void bta_ag_sdp_cback_1(UINT16 status);
+void bta_ag_sdp_cback_2(UINT16 status);
+void bta_ag_sdp_cback_3(UINT16 status);
+
+/* SDP callback function table */
+typedef tSDP_DISC_CMPL_CB *tBTA_AG_SDP_CBACK;
+const tBTA_AG_SDP_CBACK bta_ag_sdp_cback_tbl[] =
+{
+ bta_ag_sdp_cback_1,
+ bta_ag_sdp_cback_2,
+ bta_ag_sdp_cback_3
+};
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_cback
+**
+** Description SDP callback function.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_sdp_cback(UINT16 status, UINT8 idx)
+{
+ tBTA_AG_DISC_RESULT *p_buf;
+ UINT16 event;
+ tBTA_AG_SCB *p_scb;
+
+ APPL_TRACE_DEBUG("bta_ag_sdp_cback status:0x%x", status);
+
+ if ((p_scb = bta_ag_scb_by_idx(idx)) != NULL) {
+ /* set event according to int/acp */
+ if (p_scb->role == BTA_AG_ACP) {
+ event = BTA_AG_DISC_ACP_RES_EVT;
+ } else {
+ event = BTA_AG_DISC_INT_RES_EVT;
+ }
+
+ if ((p_buf = (tBTA_AG_DISC_RESULT *) osi_malloc(sizeof(tBTA_AG_DISC_RESULT))) != NULL) {
+ p_buf->hdr.event = event;
+ p_buf->hdr.layer_specific = idx;
+ p_buf->status = status;
+ bta_sys_sendmsg(p_buf);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_cback_1 to 3
+**
+** Description SDP callback functions. Since there is no way to
+** distinguish scb from the callback we need separate
+** callbacks for each scb.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sdp_cback_1(UINT16 status) {bta_ag_sdp_cback(status, 1);}
+void bta_ag_sdp_cback_2(UINT16 status) {bta_ag_sdp_cback(status, 2);}
+void bta_ag_sdp_cback_3(UINT16 status) {bta_ag_sdp_cback(status, 3);}
+
+/******************************************************************************
+**
+** Function bta_ag_add_record
+**
+** Description This function is called by a server application to add
+** HSP or HFP information to an SDP record. Prior to
+** calling this function the application must call
+** SDP_CreateRecord() to create an SDP record.
+**
+** Returns TRUE if function execution succeeded,
+** FALSE if function execution failed.
+**
+******************************************************************************/
+BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn,
+ tBTA_AG_FEAT features, UINT32 sdp_handle)
+{
+ tSDP_PROTOCOL_ELEM proto_elem_list[BTA_AG_NUM_PROTO_ELEMS];
+ UINT16 svc_class_id_list[BTA_AG_NUM_SVC_ELEMS];
+ UINT16 browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
+ UINT16 version;
+ UINT16 profile_uuid;
+ UINT8 network;
+ BOOLEAN result = TRUE;
+ BOOLEAN codec_supported = FALSE;
+ UINT8 buf[2];
+
+ APPL_TRACE_DEBUG("bta_ag_add_record uuid: %x", service_uuid);
+
+ memset( proto_elem_list, 0 , BTA_AG_NUM_PROTO_ELEMS*sizeof(tSDP_PROTOCOL_ELEM));
+ /* add the protocol element sequence */
+ proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
+ proto_elem_list[0].num_params = 0;
+ proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
+ proto_elem_list[1].num_params = 1;
+ proto_elem_list[1].params[0] = scn;
+ result &= SDP_AddProtocolList(sdp_handle, BTA_AG_NUM_PROTO_ELEMS, proto_elem_list);
+
+ /* add service class id list */
+ svc_class_id_list[0] = service_uuid;
+ svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
+ result &= SDP_AddServiceClassIdList(sdp_handle, BTA_AG_NUM_SVC_ELEMS, svc_class_id_list);
+
+ /* add profile descriptor list */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+ profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ version = HFP_VERSION_1_6;
+ } else {
+ profile_uuid = UUID_SERVCLASS_HEADSET;
+ version = HSP_VERSION_1_2;
+ }
+ result &= SDP_AddProfileDescriptorList(sdp_handle, profile_uuid, version);
+
+ /* add service name */
+ if (p_service_name != NULL && p_service_name[0] != 0) {
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
+ (UINT32)(strlen(p_service_name)+1), (UINT8 *) p_service_name);
+ }
+
+ /* add features and network */
+ if (service_uuid == UUID_SERVCLASS_AG_HANDSFREE) {
+ network = (features & BTA_AG_FEAT_REJECT) ? 1 : 0;
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_DATA_STORES_OR_NETWORK,
+ UINT_DESC_TYPE, 1, &network);
+
+ if (features & BTA_AG_FEAT_CODEC) {
+ codec_supported = TRUE;
+ }
+ features &= BTA_AG_SDP_FEAT_SPEC;
+ /* Codec bit position is different in SDP and in BRSF */
+ if (codec_supported) {
+ features |= 0x0020;
+ }
+ UINT16_TO_BE_FIELD(buf, features);
+ result &= SDP_AddAttribute(sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
+ }
+ /* add browse group list */
+ result &= SDP_AddUuidSequence(sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_create_records
+**
+** Description Create SDP records for registered services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_SERVICE_MASK services;
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+
+ for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) {
+ /* if service is set in mask */
+ if (services & 1) {
+ /* add sdp record if not already registered */
+ if (bta_ag_cb.profile[i].sdp_handle == 0) {
+ bta_ag_cb.profile[i].sdp_handle = SDP_CreateRecord();
+ bta_ag_cb.profile[i].scn = BTM_AllocateSCN();
+ bta_ag_add_record(bta_ag_uuid[i], p_data->api_register.p_name[i],
+ bta_ag_cb.profile[i].scn, p_data->api_register.features,
+ bta_ag_cb.profile[i].sdp_handle);
+ bta_sys_add_uuid(bta_ag_uuid[i]);
+ }
+ }
+ }
+ p_scb->hsp_version = HSP_VERSION_1_2;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_del_records
+**
+** Description Delete SDP records for any registered services.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ tBTA_AG_SCB *p = &bta_ag_cb.scb[0];
+ tBTA_SERVICE_MASK services;
+ tBTA_SERVICE_MASK others = 0;
+ int i;
+ UNUSED(p_data);
+
+ /* get services of all other registered servers */
+ for (i = 0; i < BTA_AG_NUM_IDX; i++, p++) {
+ if (p_scb == p) {
+ continue;
+ }
+ if (p->in_use && p->dealloc == FALSE) {
+ others |= p->reg_services;
+ }
+ }
+ others >>= BTA_HSP_SERVICE_ID;
+ services = p_scb->reg_services >> BTA_HSP_SERVICE_ID;
+ for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1, others >>= 1)
+ {
+ /* if service registered for this scb and not registered for any other scb */
+ if (((services & 1) == 1) && ((others & 1) == 0)) {
+ APPL_TRACE_DEBUG("bta_ag_del_records %d", i);
+ if (bta_ag_cb.profile[i].sdp_handle != 0) {
+ SDP_DeleteRecord(bta_ag_cb.profile[i].sdp_handle);
+ bta_ag_cb.profile[i].sdp_handle = 0;
+ }
+ BTM_FreeSCN(bta_ag_cb.profile[i].scn);
+ BTM_SecClrService(bta_ag_sec_id[i]);
+ bta_sys_remove_uuid(bta_ag_uuid[i]);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sdp_find_attr
+**
+** Description Process SDP discovery results to find requested attributes
+** for requested service.
+**
+**
+** Returns TRUE if results found, FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+ tSDP_DISC_REC *p_rec = NULL;
+ tSDP_DISC_ATTR *p_attr;
+ tSDP_PROTOCOL_ELEM pe;
+ UINT16 uuid;
+ BOOLEAN result = FALSE;
+
+ if (service & BTA_HFP_SERVICE_MASK) {
+ uuid = UUID_SERVCLASS_HF_HANDSFREE;
+ p_scb->peer_version = HFP_VERSION_1_1; /* Default version */
+ } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ uuid = UUID_SERVCLASS_HEADSET_HS;
+ p_scb->peer_version = 0x0100; /* Default version */
+ } else {
+ return result;
+ }
+
+ /* loop through all records we found */
+ while (TRUE)
+ {
+ /* get next record; if none found, we're done */
+ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) {
+ if (uuid == UUID_SERVCLASS_HEADSET_HS) {
+ /* Search again in case the peer device is HSP v1.0 */
+ uuid = UUID_SERVCLASS_HEADSET;
+ if ((p_rec = SDP_FindServiceInDb(p_scb->p_disc_db, uuid, p_rec)) == NULL) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* get scn from proto desc list if initiator */
+ if (p_scb->role == BTA_AG_INT) {
+ if (SDP_FindProtocolListElemInRec(p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
+ p_scb->peer_scn = (UINT8) pe.params[0];
+ } else {
+ continue;
+ }
+ }
+ /* get profile version (if failure, version parameter is not updated) */
+ SDP_FindProfileVersionInRec(p_rec, uuid, &p_scb->peer_version);
+ /* get features if HFP */
+ if (service & BTA_HFP_SERVICE_MASK) {
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_SUPPORTED_FEATURES)) != NULL) {
+ /* Found attribute. Get value. */
+ /* There might be race condition between SDP and BRSF. */
+ /* Do not update if we already received BRSF. */
+ if (p_scb->peer_features == 0)
+ p_scb->peer_features = p_attr->attr_value.v.u16;
+ }
+ } else {
+ /* HSP */
+ if ((p_attr = SDP_FindAttributeInRec(p_rec, ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL)) != NULL) {
+ /* Remote volume control of HSP */
+ if (p_attr->attr_value.v.u8) {
+ p_scb->peer_features |= BTA_AG_PEER_FEAT_VOL;
+ } else {
+ p_scb->peer_features &= ~BTA_AG_PEER_FEAT_VOL;
+ }
+ }
+ }
+ /* found what we needed */
+ result = TRUE;
+ break;
+ }
+ return result;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_do_disc
+**
+** Description Do service discovery.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service)
+{
+ tSDP_UUID uuid_list[2];
+ UINT16 num_uuid = 1;
+ UINT16 attr_list[4];
+ UINT8 num_attr;
+ BOOLEAN db_inited = FALSE;
+
+ /* HFP initiator; get proto list and features */
+ if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 4;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ } else if (service & BTA_HFP_SERVICE_MASK && p_scb->role == BTA_AG_ACP) {
+ /* HFP acceptor; get features */
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
+ num_attr = 3;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HF_HANDSFREE;
+ } else if (service & BTA_HSP_SERVICE_MASK && p_scb->role == BTA_AG_INT) {
+ /* HSP initiator; get proto list */
+ attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
+ attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
+ attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
+ attr_list[3] = ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL;
+ num_attr = 4;
+ uuid_list[0].uu.uuid16 = UUID_SERVCLASS_HEADSET; /* Legacy from HSP v1.0 */
+ if (p_scb->hsp_version >= HSP_VERSION_1_2) {
+ uuid_list[1].uu.uuid16 = UUID_SERVCLASS_HEADSET_HS;
+ num_uuid = 2;
+ }
+ } else {
+ /* HSP acceptor; no discovery */
+ return;
+ }
+
+ /* allocate buffer for sdp database */
+ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BTA_AG_DISC_BUF_SIZE);
+ if(p_scb->p_disc_db) {
+ /* set up service discovery database; attr happens to be attr_list len */
+ uuid_list[0].len = LEN_UUID_16;
+ uuid_list[1].len = LEN_UUID_16;
+ db_inited = SDP_InitDiscoveryDb(p_scb->p_disc_db, BTA_AG_DISC_BUF_SIZE, num_uuid,
+ uuid_list, num_attr, attr_list);
+ }
+
+ if(db_inited) {
+ /*Service discovery not initiated */
+ db_inited = SDP_ServiceSearchAttributeRequest(p_scb->peer_addr, p_scb->p_disc_db,
+ bta_ag_sdp_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]);
+ }
+ if(!db_inited) {
+ /*free discover db */
+ bta_ag_free_db(p_scb, NULL);
+ /* sent failed event */
+ bta_ag_sm_execute(p_scb, BTA_AG_DISC_FAIL_EVT, NULL);
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_free_db
+**
+** Description Free discovery database.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
+{
+ UNUSED(p_data);
+ if (p_scb->p_disc_db != NULL) {
+ osi_free(p_scb->p_disc_db);
+ p_scb->p_disc_db = NULL;
+ }
+}
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2004-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Interface file for BTA AG AT command interpreter.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_AT_H
+#define BTA_AG_AT_H
+
+#include "stack/bt_types.h"
+#include "common/bt_target.h"
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#if (BTA_AG_INCLUDED == TRUE)
+
+/* AT command argument capabilities */
+#define BTA_AG_AT_NONE 0x01 /* no argument */
+#define BTA_AG_AT_SET 0x02 /* set value */
+#define BTA_AG_AT_READ 0x04 /* read value */
+#define BTA_AG_AT_TEST 0x08 /* test value range */
+#define BTA_AG_AT_FREE 0x10 /* freeform argument */
+
+/* AT command argument format */
+#define BTA_AG_AT_STR 0 /* string */
+#define BTA_AG_AT_INT 1 /* integer */
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* AT command table element */
+typedef struct
+{
+ const char *p_cmd; /* AT command string */
+ UINT8 arg_type; /* allowable argument type syntax */
+ UINT8 fmt; /* whether arg is int or string */
+ UINT8 min; /* minimum value for int arg */
+ INT16 max; /* maximum value for int arg */
+} tBTA_AG_AT_CMD;
+
+/* callback function executed when command is parsed */
+typedef void (tBTA_AG_AT_CMD_CBACK)(void *p_user, UINT16 cmd, UINT8 arg_type,
+ char *p_arg, INT16 int_arg);
+
+/* callback function executed to send "ERROR" result code */
+typedef void (tBTA_AG_AT_ERR_CBACK)(void *p_user, BOOLEAN unknown, char *p_arg);
+
+/* AT command parsing control block */
+typedef struct
+{
+ tBTA_AG_AT_CMD *p_at_tbl; /* AT command table */
+ tBTA_AG_AT_CMD_CBACK *p_cmd_cback; /* command callback */
+ tBTA_AG_AT_ERR_CBACK *p_err_cback; /* error callback */
+ void *p_user; /* user-defined data */
+ char *p_cmd_buf; /* temp parsing buffer */
+ UINT16 cmd_pos; /* position in temp buffer */
+ UINT16 cmd_max_len; /* length of temp buffer to allocate */
+ UINT8 state; /* parsing state */
+} tBTA_AG_AT_CB;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+**
+** Function bta_ag_at_init
+**
+** Description Initialize the AT command parser control block.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_init(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function bta_ag_at_reinit
+**
+** Description Re-initialize the AT command parser control block. This
+** function resets the AT command parser state and frees
+** any GKI buffer.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_reinit(tBTA_AG_AT_CB *p_cb);
+
+/*****************************************************************************
+**
+** Function bta_ag_at_parse
+**
+** Description Parse AT commands. This function will take the input
+** character string and parse it for AT commands according to
+** the AT command table passed in the control block.
+**
+**
+** Returns void
+**
+*****************************************************************************/
+extern void bta_ag_at_parse(tBTA_AG_AT_CB *p_cb, char *p_buf, UINT16 len);
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
+
+#endif /* BTA_AG_AT_H */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the private interface file for the BTA audio gateway.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_INT_H
+#define BTA_AG_INT_H
+
+#include "bta_ag_at.h"
+#include "bta/bta_sys.h"
+#include "bta/bta_api.h"
+#include "bta/bta_ag_api.h"
+#include "stack/sdp_api.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+
+/* Send RING & CLIP in one AT cmd */
+#ifndef BTA_AG_MULTI_RESULT_INCLUDED
+#define BTA_AG_MULTI_RESULT_INCLUDED FALSE
+#endif
+
+/* Replace : in VGS and VGM for HSP */
+#ifndef BTA_HSP_RESULT_REPLACE_COLON
+#define BTA_HSP_RESULT_REPLACE_COLON TRUE
+#endif
+
+/*****************************************************************************
+** Constants
+*****************************************************************************/
+#define HFP_VERSION_1_1 0x0101
+#define HFP_VERSION_1_5 0x0105
+#define HFP_VERSION_1_6 0x0106
+
+#define HSP_VERSION_1_0 0x0100
+#define HSP_VERSION_1_2 0x0102
+
+/* Number of SCBs (AG service instances that can be registered) */
+#ifndef BTA_AG_NUM_SCB
+#define BTA_AG_NUM_SCB 1
+#endif
+
+/* Timer to wait for retry in case of collision */
+#ifndef BTA_AG_COLLISION_TIMER
+#define BTA_AG_COLLISION_TIMER 2000
+#endif
+
+/* RFCOMM MTU SIZE */
+#define BTA_AG_MTU 256
+
+/* Internal profile indexes */
+#define BTA_AG_HSP 0 /* index for HSP */
+#define BTA_AG_HFP 1 /* index for HFP */
+#define BTA_AG_NUM_IDX 2 /* number of profile indexes */
+
+/* profile role for connection */
+#define BTA_AG_ACP 0 /* accepted connection */
+#define BTA_AG_INT 1 /* initiating connection */
+
+/* feature mask that matches spec */
+#define BTA_AG_BSRF_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_VTAG | BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | BTA_AG_FEAT_ECC | \
+ BTA_AG_FEAT_EXTERR | BTA_AG_FEAT_CODEC | \
+ BTA_AG_FEAT_VOIP)
+
+#define BTA_AG_SDP_FEAT_SPEC (BTA_AG_FEAT_3WAY | BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_VREC | BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_VTAG)
+
+enum
+{
+ /* these events are handled by the state machine */
+ BTA_AG_API_REGISTER_EVT = BTA_SYS_EVT_START(BTA_ID_AG),
+ BTA_AG_API_DEREGISTER_EVT,
+ BTA_AG_API_OPEN_EVT,
+ BTA_AG_API_CLOSE_EVT,
+ BTA_AG_API_AUDIO_OPEN_EVT,
+ BTA_AG_API_AUDIO_CLOSE_EVT,
+ BTA_AG_API_RESULT_EVT,
+ BTA_AG_API_SETCODEC_EVT,
+ BTA_AG_RFC_OPEN_EVT,
+ BTA_AG_RFC_CLOSE_EVT,
+ BTA_AG_RFC_SRV_CLOSE_EVT,
+ BTA_AG_RFC_DATA_EVT,
+ BTA_AG_SCO_OPEN_EVT,
+ BTA_AG_SCO_CLOSE_EVT,
+ BTA_AG_DISC_ACP_RES_EVT,
+ BTA_AG_DISC_INT_RES_EVT,
+ BTA_AG_DISC_OK_EVT,
+ BTA_AG_DISC_FAIL_EVT,
+ BTA_AG_CI_RX_WRITE_EVT,
+ BTA_AG_RING_TOUT_EVT,
+ BTA_AG_SVC_TOUT_EVT,
+ #if (BTM_SCO_HCI_INCLUDED == TRUE )
+ BTA_AG_CI_SCO_DATA_EVT,
+ #endif /* (BTM_SCO_HCI_INCLUDED == TRUE ) */
+ BTA_AG_CI_SLC_READY_EVT,
+ BTA_AG_MAX_EVT,
+
+ /* these events are handled outside of the state machine */
+ BTA_AG_API_ENABLE_EVT,
+ BTA_AG_API_DISABLE_EVT
+};
+
+/* Actions to perform after a SCO event */
+enum
+{
+ BTA_AG_POST_SCO_NONE, /* no action */
+ BTA_AG_POST_SCO_CLOSE_RFC, /* close RFCOMM channel after SCO closes */
+ BTA_AG_POST_SCO_RING, /* send RING result code after SCO opens */
+ BTA_AG_POST_SCO_CALL_CONN, /* send call indicators after SCO opens/closes */
+ BTA_AG_POST_SCO_CALL_ORIG, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END, /* send call indicators after SCO closes */
+ BTA_AG_POST_SCO_CALL_END_INCALL /* send call indicators for end call & incoming call after SCO closes */
+};
+
+/* sco states */
+enum
+{
+ BTA_AG_SCO_SHUTDOWN_ST, /* no sco listening, all sco connections closed */
+ BTA_AG_SCO_LISTEN_ST, /* sco listening */
+#if (BTM_WBS_INCLUDED == TRUE )
+ BTA_AG_SCO_CODEC_ST, /* sco codec negotiation */
+#endif
+ BTA_AG_SCO_OPENING_ST, /* sco connection opening */
+ BTA_AG_SCO_OPEN_CL_ST, /* opening sco connection being closed */
+ BTA_AG_SCO_OPEN_XFER_ST, /* opening sco connection being transferred */
+ BTA_AG_SCO_OPEN_ST, /* sco open */
+ BTA_AG_SCO_CLOSING_ST, /* sco closing */
+ BTA_AG_SCO_CLOSE_OP_ST, /* closing sco being opened */
+ BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */
+ BTA_AG_SCO_SHUTTING_ST /* sco shutting down */
+};
+
+/*****************************************************************************
+** Data types
+*****************************************************************************/
+
+/* data type for BTA_AG_API_ENABLE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_PARSE_MODE parse_mode;
+ tBTA_AG_CBACK *p_cback;
+} tBTA_AG_API_ENABLE;
+
+/* data type for BTA_AG_API_REGISTER_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char p_name[2][BTA_SERVICE_NAME_LEN+1];
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+ tBTA_AG_FEAT features;
+ UINT8 app_id;
+} tBTA_AG_API_REGISTER;
+
+/* data type for BTA_AG_API_OPEN_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_MASK services;
+ tBTA_SEC sec_mask;
+} tBTA_AG_API_OPEN;
+
+/* data type for BTA_AG_API_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_RES result;
+ tBTA_AG_RES_DATA data;
+} tBTA_AG_API_RESULT;
+
+/* data type for BTA_AG_API_SETCODEC_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ tBTA_AG_PEER_CODEC codec;
+} tBTA_AG_API_SETCODEC;
+
+/* data type for BTA_AG_DISC_RESULT_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 status;
+} tBTA_AG_DISC_RESULT;
+
+/* data type for RFCOMM events */
+typedef struct
+{
+ BT_HDR hdr;
+ UINT16 port_handle;
+} tBTA_AG_RFC;
+
+/* data type for BTA_AG_CI_RX_WRITE_EVT */
+typedef struct
+{
+ BT_HDR hdr;
+ char p_data[BTA_AG_MTU+1];
+} tBTA_AG_CI_RX_WRITE;
+
+/* union of all event datatypes */
+typedef union
+{
+ BT_HDR hdr;
+ tBTA_AG_API_ENABLE api_enable;
+ tBTA_AG_API_REGISTER api_register;
+ tBTA_AG_API_OPEN api_open;
+ tBTA_AG_API_RESULT api_result;
+#if (BTM_WBS_INCLUDED == TRUE )
+ tBTA_AG_API_SETCODEC api_setcodec;
+#endif
+ tBTA_AG_DISC_RESULT disc_result;
+ tBTA_AG_RFC rfc;
+ tBTA_AG_CI_RX_WRITE ci_rx_write;
+} tBTA_AG_DATA;
+
+/* type for each profile */
+typedef struct
+{
+ UINT32 sdp_handle;
+ UINT8 scn;
+} tBTA_AG_PROFILE;
+
+#if (BTM_WBS_INCLUDED == TRUE)
+typedef enum
+{
+ BTA_AG_SCO_MSBC_SETTINGS_T2 = 0, /* preferred/default when codec is mSBC */
+ BTA_AG_SCO_MSBC_SETTINGS_T1,
+} tBTA_AG_SCO_MSBC_SETTINGS;
+#endif
+
+/* type for each service control block */
+typedef struct
+{
+ char clip[BTA_AG_AT_MAX_LEN+10]; /* number string used for CLIP */
+ UINT16 serv_handle[BTA_AG_NUM_IDX]; /* RFCOMM server handles */
+ tBTA_AG_AT_CB at_cb; /* AT command interpreter */
+ TIMER_LIST_ENT act_timer; /* ring timer */
+ BD_ADDR peer_addr; /* peer bd address */
+ tSDP_DISCOVERY_DB *p_disc_db; /* pointer to discovery database */
+ tBTA_SERVICE_MASK reg_services; /* services specified in register API */
+ tBTA_SERVICE_MASK open_services; /* services specified in open API */
+ UINT16 conn_handle; /* RFCOMM handle of connected service */
+ tBTA_SEC serv_sec_mask; /* server security mask */
+ tBTA_SEC cli_sec_mask; /* client security mask */
+ tBTA_AG_FEAT features; /* features registered by application */
+ tBTA_AG_PEER_FEAT peer_features; /* peer device features */
+ UINT16 peer_version; /* profile version of peer device */
+ UINT16 hsp_version; /* HSP profile version */
+#if (BTM_WBS_INCLUDED == TRUE)
+ tBTA_AG_PEER_CODEC peer_codecs; /* codecs for eSCO supported by the peer */
+ tBTA_AG_PEER_CODEC sco_codec; /* codec to be used for eSCO connection */
+ tBTA_AG_PEER_CODEC inuse_codec; /* codec being used for the current SCO connection */
+ BOOLEAN codec_updated; /* set to TRUE whenever the app updates codec type */
+ BOOLEAN codec_fallback; /* If sco nego fails for mSBC, fallback to CVSD */
+ tBTA_AG_SCO_MSBC_SETTINGS codec_msbc_settings; /* settings to be used for the impending eSCO */
+ TIMER_LIST_ENT cn_timer; /* codec negotiation timer */
+#endif
+ UINT16 sco_idx; /* SCO handle */
+ BOOLEAN in_use; /* scb in use */
+ BOOLEAN dealloc; /* TRUE if service shutting down */
+ BOOLEAN clip_enabled; /* set to TRUE if HF enables CLIP reporting */
+ BOOLEAN ccwa_enabled; /* set to TRUE if HF enables CCWA reporting */
+ BOOLEAN cmer_enabled; /* set to TRUE if HF enables CMER reporting */
+ BOOLEAN cmee_enabled; /* set to TRUE if HF enables CME ERROR reporting */
+ BOOLEAN inband_enabled; /* set to TRUE if inband ring enabled */
+ BOOLEAN svc_conn; /* set to TRUE when service level connection up */
+ TIMER_LIST_ENT colli_timer; /* Collision timer */
+ BOOLEAN colli_tmr_on; /* TRUE if collision timer is active */
+ UINT8 state; /* state machine state */
+ UINT8 conn_service; /* connected service */
+ UINT8 peer_scn; /* peer scn */
+ UINT8 app_id; /* application id */
+ UINT8 role; /* initiator/acceptor role */
+ tBTM_SCO_CODEC_TYPE negotiated_codec; /* negotiated codec */
+ UINT8 post_sco; /* action to perform after sco event */
+ UINT8 call_ind; /* CIEV call indicator value */
+ UINT8 callsetup_ind; /* CIEV callsetup indicator value */
+ UINT8 service_ind; /* CIEV service indicator value */
+ UINT8 signal_ind; /* CIEV signal indicator value */
+ UINT8 roam_ind; /* CIEV roam indicator value */
+ UINT8 battchg_ind; /* CIEV battery charge indicator value */
+ UINT8 callheld_ind; /* CIEV call held indicator value */
+ BOOLEAN retry_with_sco_only; /* indicator to try with SCO only when eSCO fails */
+ UINT32 bia_masked_out; /* indicators HF does not want us to send */
+ /* add */
+ UINT16 in_pkt_len;
+ UINT16 out_pkt_len;
+ UINT8 link_type; /* BTM_LINK_TYPE_SCO or BTM_LINK_TYPE_ESCO */
+ UINT8 tx_interval;
+ UINT8 retrans_window;
+ UINT8 air_mode;
+} tBTA_AG_SCB;
+
+/* type for sco data */
+typedef struct
+{
+ tBTM_ESCO_CONN_REQ_EVT_DATA conn_data; /* CO data for pending conn requestS */
+ tBTA_AG_SCB *p_curr_scb; /* SCB associated with SCO connection */
+ tBTA_AG_SCB *p_xfer_scb; /* SCB associated with SCO transfer */
+ UINT16 cur_idx; /* SCO handle */
+ UINT8 state; /* SCO state variable */
+ BOOLEAN param_updated; /* if params were updated to non-default */
+ tBTM_ESCO_PARAMS params; /* ESCO parameters */
+ tBTA_AG_DATA *p_data;
+} tBTA_AG_SCO_CB;
+
+/* type for AG control block */
+typedef struct
+{
+ tBTA_AG_SCB scb[BTA_AG_NUM_SCB]; /* service control blocks */
+ tBTA_AG_PROFILE profile[BTA_AG_NUM_IDX]; /* profile-specific data */
+ tBTA_AG_SCO_CB sco; /* SCO data */
+ tBTA_AG_CBACK *p_cback; /* application callback */
+ tBTA_AG_PARSE_MODE parse_mode; /* parse/pass-through mode */
+ BOOLEAN msbc_enabled;
+} tBTA_AG_CB;
+
+/*****************************************************************************
+** Global data
+*****************************************************************************/
+
+/* constant lookup tables */
+extern const UINT16 bta_ag_uuid[BTA_AG_NUM_IDX];
+extern const UINT8 bta_ag_sec_id[BTA_AG_NUM_IDX];
+extern const tBTA_AG_AT_CMD *bta_ag_at_tbl[BTA_AG_NUM_IDX];
+
+/* control block declaration */
+#if BTA_DYNAMIC_MEMORY == FALSE
+extern tBTA_AG_CB bta_ag_cb;
+#else
+extern tBTA_AG_CB *bta_ag_cb_ptr;
+#define bta_ag_cb (*bta_ag_cb_ptr)
+#endif
+
+/* config struct */
+extern tBTA_AG_CFG *p_bta_ag_cfg;
+
+/*****************************************************************************
+** Function prototypes
+*****************************************************************************/
+
+/* main functions */
+extern void bta_ag_scb_dealloc(tBTA_AG_SCB *p_scb);
+extern UINT16 bta_ag_scb_to_idx(tBTA_AG_SCB *p_scb);
+extern tBTA_AG_SCB *bta_ag_scb_by_idx(UINT16 idx);
+extern UINT8 bta_ag_service_to_idx(tBTA_SERVICE_MASK services);
+extern UINT16 bta_ag_idx_by_bdaddr(BD_ADDR peer_addr);
+extern BOOLEAN bta_ag_other_scb_open(tBTA_AG_SCB *p_curr_scb);
+extern BOOLEAN bta_ag_scb_open(tBTA_AG_SCB *p_curr_scb);
+extern tBTA_AG_SCB *bta_ag_get_other_idle_scb (tBTA_AG_SCB *p_curr_scb);
+extern void bta_ag_sm_execute(tBTA_AG_SCB *p_scb, UINT16 event, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_hdl_event(BT_HDR *p_msg);
+extern void bta_ag_collision_cback(tBTA_SYS_CONN_STATUS status, UINT8 id, UINT8 app_id, BD_ADDR peer_addr);
+extern void bta_ag_resume_open(tBTA_AG_SCB *p_scb);
+
+/* SDP functions */
+extern BOOLEAN bta_ag_add_record(UINT16 service_uuid, char *p_service_name, UINT8 scn, tBTA_AG_FEAT features, UINT32 sdp_handle);
+extern void bta_ag_create_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_del_records(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern BOOLEAN bta_ag_sdp_find_attr(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service);
+extern void bta_ag_free_db(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* RFCOMM functions */
+extern void bta_ag_start_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern void bta_ag_close_servers(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK services);
+extern BOOLEAN bta_ag_is_server_closed (tBTA_AG_SCB *p_scb);
+extern void bta_ag_rfc_do_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_do_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+/* SCO functions */
+extern BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb);
+extern BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb);
+extern void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data);
+
+/* AT command functions */
+extern void bta_ag_at_hsp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, char *p_arg, INT16 int_arg);
+extern void bta_ag_at_hfp_cback(tBTA_AG_SCB *p_scb, UINT16 cmd, UINT8 arg_type, char *p_arg, INT16 int_arg);
+extern void bta_ag_at_err_cback(tBTA_AG_SCB *p_scb, BOOLEAN unknown, char *p_arg);
+extern BOOLEAN bta_ag_inband_enabled(tBTA_AG_SCB *p_scb);
+extern void bta_ag_send_call_inds(tBTA_AG_SCB *p_scb, tBTA_AG_RES result);
+
+/* Action functions */
+extern void bta_ag_register(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_deregister(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_dereg(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_start_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_int_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_acp_res(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_disc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_open_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_fail(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_acp_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rfc_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE)
+extern void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result);
+extern void bta_ag_codec_negotiate (tBTA_AG_SCB *p_scb);
+#endif
+extern void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_post_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_svc_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_result(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_setcodec(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#if (BTM_WBS_INCLUDED == TRUE)
+extern void bta_ag_send_bcs(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+#endif
+extern void bta_ag_send_ring(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param);
+extern void bta_ag_ci_rx_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+extern void bta_ag_rcvd_slc_ready(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data);
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
+
+#endif /* BTA_AG_INT_H */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the public interface file for the audio gateway (AG) subsystem
+ * of BTA, Broadcom's Bluetooth application layer for mobile phones.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_API_H
+#define BTA_AG_API_H
+
+#include "bta_api.h"
+#include "bta_hfp_defs.h"
+#include "esp_hf_defs.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*****************************************************************************
+** Constants and data types
+*****************************************************************************/
+
+/* AG feature masks */
+#define BTA_AG_FEAT_3WAY 0x00000001 /* Three-way calling */
+#define BTA_AG_FEAT_ECNR 0x00000002 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_FEAT_VREC 0x00000004 /* Voice recognition */
+#define BTA_AG_FEAT_INBAND 0x00000008 /* In-band ring tone */
+#define BTA_AG_FEAT_VTAG 0x00000010 /* Attach a phone number to a voice tag */
+#define BTA_AG_FEAT_REJECT 0x00000020 /* Ability to reject incoming call */
+#define BTA_AG_FEAT_ECS 0x00000040 /* Enhanced Call Status */
+#define BTA_AG_FEAT_ECC 0x00000080 /* Enhanced Call Control */
+#define BTA_AG_FEAT_EXTERR 0x00000100 /* Extended error codes */
+#define BTA_AG_FEAT_CODEC 0x00000200 /* Codec Negotiation */
+#define BTA_AG_FEAT_VOIP 0x00000400 /* VoIP call */
+/* Proprietary features: using 31 ~ 16 bits */
+#define BTA_AG_FEAT_BTRH 0x00010000 /* CCAP incoming call hold */
+#define BTA_AG_FEAT_UNAT 0x00020000 /* Pass unknown AT commands to application */
+#define BTA_AG_FEAT_NOSCO 0x00040000 /* No SCO control performed by BTA AG */
+#define BTA_AG_FEAT_NO_ESCO 0x00080000 /* Do not allow or use eSCO */
+typedef UINT32 tBTA_AG_FEAT;
+
+/* HFP peer features */
+#define BTA_AG_PEER_FEAT_ECNR 0x0001 /* Echo cancellation and/or noise reduction */
+#define BTA_AG_PEER_FEAT_3WAY 0x0002 /* Call waiting and three-way calling */
+#define BTA_AG_PEER_FEAT_CLI 0x0004 /* Caller ID presentation capability */
+#define BTA_AG_PEER_FEAT_VREC 0x0008 /* Voice recognition activation */
+#define BTA_AG_PEER_FEAT_VOL 0x0010 /* Remote volume control */
+#define BTA_AG_PEER_FEAT_ECS 0x0020 /* Enhanced Call Status */
+#define BTA_AG_PEER_FEAT_ECC 0x0040 /* Enhanced Call Control */
+#define BTA_AG_PEER_FEAT_CODEC 0x0080 /* Codec Negotiation */
+#define BTA_AG_PEER_FEAT_VOIP 0x0100 /* VoIP call */
+typedef UINT16 tBTA_AG_PEER_FEAT;
+
+/* AG extended call handling - masks not related to any spec */
+#define BTA_AG_CLIENT_CHLD_REL 0x00000001 /* 0 Release waiting call or held calls */
+#define BTA_AG_CLIENT_CHLD_REL_ACC 0x00000002 /* 1 Release active calls and accept other (waiting or held) cal */
+#define BTA_AG_CLIENT_CHLD_REL_X 0x00000004 /* 1x Release x call*/
+#define BTA_AG_CLIENT_CHLD_HOLD_ACC 0x00000008 /* 2 Active calls on hold and accept other call */
+#define BTA_AG_CLIENT_CHLD_PRIV_X 0x00000010 /* 2x Active multiparty call on hold except call x */
+#define BTA_AG_CLIENT_CHLD_MERGE 0x00000020 /* 3 Add held call to multiparty */
+#define BTA_AG_CLIENT_CHLD_MERGE_DETACH 0x00000040 /* 4 Add held call to multiparty */
+typedef UINT16 tBTA_AG_CHLD_FEAT;
+
+/* HFP peer supported codec masks */
+// TODO(google) This should use common definitions
+// in hci/include/hci_audio.h
+#define BTA_AG_CODEC_NONE BTM_SCO_CODEC_NONE
+#define BTA_AG_CODEC_CVSD BTM_SCO_CODEC_CVSD /* CVSD */
+#define BTA_AG_CODEC_MSBC BTM_SCO_CODEC_MSBC /* mSBC */
+typedef UINT16 tBTA_AG_PEER_CODEC;
+
+/* AG parse mode */
+#define BTA_AG_PARSE 0 /* Perform AT command parsing in AG */
+#define BTA_AG_PASS_THROUGH 1 /* Pass data directly to phones AT command interpreter */
+typedef UINT8 tBTA_AG_PARSE_MODE;
+
+/* AG open status */
+#define BTA_AG_SUCCESS 0 /* Connection successfully opened */
+#define BTA_AG_FAIL_SDP 1 /* Open failed due to SDP */
+#define BTA_AG_FAIL_RFCOMM 2 /* Open failed due to RFCOMM */
+#define BTA_AG_FAIL_RESOURCES 3 /* out of resources failure */
+typedef UINT8 tBTA_AG_STATUS;
+
+/* handle values used with BTA_AgResult */
+#define BTA_AG_HANDLE_NONE 0
+#define BTA_AG_HANDLE_ALL 0xFFFF
+/* It is safe to use the same value as BTA_AG_HANDLE_ALL
+ * HANDLE_ALL is used for delivering indication
+ * SCO_NO_CHANGE is used for changing sco behavior
+ * They donot interfere with each other
+ */
+#define BTA_AG_HANDLE_SCO_NO_CHANGE 0xFFFF
+
+/* AG result codes used with BTA_AgResult */
+#define BTA_AG_SPK_RES 0 /* Update speaker volume */
+#define BTA_AG_MIC_RES 1 /* Update microphone volume */
+#define BTA_AG_INBAND_RING_RES 2 /* Update inband ring state AT+BSIR */
+#define BTA_AG_CIND_RES 3 /* Send indicator response for AT+CIND */
+#define BTA_AG_BINP_RES 4 /* Send phone number for voice tag for AT+BINP */
+#define BTA_AG_IND_RES 5 /* Update an indicator value +CIEV<...> */
+#define BTA_AG_BVRA_RES 6 /* Update voice recognition state for AT+BVRA */
+#define BTA_AG_CNUM_RES 7 /* Send subscriber number response for AT+CNUM */
+#define BTA_AG_BTRH_RES 8 /* Send CCAP incoming call hold */
+#define BTA_AG_CLCC_RES 9 /* Query list of calls AT+CLCC */
+#define BTA_AG_COPS_RES 10 /* Read network operator for AT+COPS */
+#define BTA_AG_IN_CALL_RES 11 /* Indicate incoming phone call */
+#define BTA_AG_IN_CALL_CONN_RES 12 /* Incoming phone call connected*/
+#define BTA_AG_CALL_WAIT_RES 13 /* Call waiting notification for AT+CCWA */
+#define BTA_AG_OUT_CALL_ORIG_RES 14 /* Outgoing phone call origination AT+ATD*/
+#define BTA_AG_OUT_CALL_ALERT_RES 15 /* Outgoing phone call alerting remote party */
+#define BTA_AG_OUT_CALL_CONN_RES 16 /* Outgoing phone call connected */
+#define BTA_AG_CALL_CANCEL_RES 17 /* Incoming/outgoing 3-way canceled before connected */
+#define BTA_AG_END_CALL_RES 18 /* End call AT+CHUP */
+#define BTA_AG_IN_CALL_HELD_RES 19 /* Incoming call held AT+CHLD */
+#define BTA_AG_UNAT_RES 20 /* Response to unknown AT command event AT+UNAT */
+#define BTA_AG_MULTI_CALL_RES 21 /* SLC at three way call */
+typedef UINT8 tBTA_AG_RES;
+
+/* AG callback events */
+#define BTA_AG_ENABLE_EVT 0 /* AG enabled */
+#define BTA_AG_REGISTER_EVT 1 /* AG registered */
+#define BTA_AG_OPEN_EVT 2 /* AG connection open */
+#define BTA_AG_CLOSE_EVT 3 /* AG connection closed */
+#define BTA_AG_CONN_EVT 4 /* Service level connection opened */
+#define BTA_AG_AUDIO_OPEN_EVT 5 /* Audio connection open */
+#define BTA_AG_AUDIO_CLOSE_EVT 6 /* Audio connection closed */
+#define BTA_AG_SPK_EVT 7 /* Speaker volume changed */
+#define BTA_AG_MIC_EVT 8 /* Microphone volume changed */
+#define BTA_AG_AT_CKPD_EVT 9 /* CKPD from the HS */
+#define BTA_AG_DISABLE_EVT 30 /* AG disabled */
+#if (BTM_WBS_INCLUDED == TRUE )
+#define BTA_AG_WBS_EVT 31 /* SCO codec nego */
+#endif
+
+/* Values below are for HFP only */
+#define BTA_AG_AT_A_EVT 10 /* Answer a incoming call */
+#define BTA_AG_AT_D_EVT 11 /* Place a call using number or memory dial */
+#define BTA_AG_AT_CHLD_EVT 12 /* Call hold */
+#define BTA_AG_AT_CHUP_EVT 13 /* Hang up a call */
+#define BTA_AG_AT_CIND_EVT 14 /* Read indicator settings */
+#define BTA_AG_AT_VTS_EVT 15 /* Transmit DTMF tone */
+#define BTA_AG_AT_BINP_EVT 16 /* Retrieve number from voice tag */
+#define BTA_AG_AT_BLDN_EVT 17 /* Place call to last dialed number */
+#define BTA_AG_AT_BVRA_EVT 18 /* Enable/disable voice recognition */
+#define BTA_AG_AT_NREC_EVT 19 /* Disable echo canceling */
+#define BTA_AG_AT_CNUM_EVT 20 /* Retrieve subscriber number */
+#define BTA_AG_AT_BTRH_EVT 21 /* CCAP-style incoming call hold */
+#define BTA_AG_AT_CLCC_EVT 22 /* Query list of current calls */
+#define BTA_AG_AT_COPS_EVT 23 /* Query Current Operator Name on AG */
+#define BTA_AG_AT_UNAT_EVT 24 /* Unknown AT command */
+#define BTA_AG_AT_CBC_EVT 25 /* Indicator Update */
+#define BTA_AG_AT_BAC_EVT 26 /* avablable codec */
+#define BTA_AG_AT_BCS_EVT 27 /* Codec select */
+typedef UINT8 tBTA_AG_EVT;
+
+/* HFP errcode - Set when BTA_AG_OK_ERROR is returned in 'ok_flag' */
+#define BTA_AG_ERR_PHONE_FAILURE 0 /* Phone Failure */
+#define BTA_AG_ERR_NO_CONN_PHONE 1 /* No connection to phone */
+#define BTA_AG_ERR_OP_NOT_ALLOWED 3 /* Operation not allowed */
+#define BTA_AG_ERR_OP_NOT_SUPPORTED 4 /* Operation not supported */
+#define BTA_AG_ERR_PHSIM_PIN_REQ 5 /* PH-SIM PIN required */
+#define BTA_AG_ERR_SIM_NOT_INSERTED 10 /* SIM not inserted */
+#define BTA_AG_ERR_SIM_PIN_REQ 11 /* SIM PIN required */
+#define BTA_AG_ERR_SIM_PUK_REQ 12 /* SIM PUK required */
+#define BTA_AG_ERR_SIM_FAILURE 13 /* SIM failure */
+#define BTA_AG_ERR_SIM_BUSY 14 /* SIM busy */
+#define BTA_AG_ERR_INCORRECT_PWD 16 /* Incorrect password */
+#define BTA_AG_ERR_SIM_PIN2_REQ 17 /* SIM PIN2 required */
+#define BTA_AG_ERR_SIM_PUK2_REQ 18 /* SIM PUK2 required */
+#define BTA_AG_ERR_MEMORY_FULL 20 /* Memory full */
+#define BTA_AG_ERR_INVALID_INDEX 21 /* Invalid index */
+#define BTA_AG_ERR_MEMORY_FAILURE 23 /* Memory failure */
+#define BTA_AG_ERR_TEXT_TOO_LONG 24 /* Text string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_TSTR 25 /* Invalid characters in text string */
+#define BTA_AG_ERR_DSTR_TOO_LONG 26 /* Dial string too long */
+#define BTA_AG_ERR_INV_CHAR_IN_DSTR 27 /* Invalid characters in dial string */
+#define BTA_AG_ERR_NO_NETWORK_SERV 30 /* No network service */
+#define BTA_AG_ERR_NETWORK_TIME_OUT 31 /* Network timeout */
+#define BTA_AG_ERR_NO_NET_EMG_ONLY 32 /* Network not allowed - emergency service only */
+#define BTA_AG_ERR_VOIP_CS_CALLS 33 /* AG cannot create simultaneous VoIP and CS calls */
+#define BTA_AG_ERR_NOT_FOR_VOIP 34 /* Not supported on this call type(VoIP) */
+#define BTA_AG_ERR_SIP_RESP_CODE 35 /* SIP 3 digit response code */
+typedef UINT8 tBTA_AG_ERR_TYPE;
+
+#if 0 /* Not Used in Bluetooth HFP 1.5 Specification */
+#define BTA_AG_ERR_PHADAP_LNK_RES 2 /* Phone-adapter link reserved */
+#define BTA_AG_ERR_PHFSIM_PIN_REQ 6 /* PH-FSIM PIN required */
+#define BTA_AG_ERR_PHFSIM_PUK_REQ 7 /* PH-FSIM PUK required */
+#define BTA_AG_ERR_SIM_WRONG 15 /* SIM wrong */
+#define BTA_AG_ERR_NOT_FOUND 22 /* Not found */
+#define BTA_AG_ERR_NETWORK_TIMEOUT 31 /* Network timeout */
+#define BTA_AG_ERR_NET_PIN_REQ 40 /* Network personalization PIN required */
+#define BTA_AG_ERR_NET_PUK_REQ 41 /* Network personalization PUK required */
+#define BTA_AG_ERR_SUBSET_PIN_REQ 42 /* Network subset personalization PIN required */
+#define BTA_AG_ERR_SUBSET_PUK_REQ 43 /* Network subset personalization PUK required */
+#define BTA_AG_ERR_SERVPRO_PIN_REQ 44 /* Service provider personalization PIN required */
+#define BTA_AG_ERR_SERVPRO_PUK_REQ 45 /* Service provider personalization PUK required */
+#define BTA_AG_ERR_CORP_PIN_REQ 46 /* Corporate personalization PIN required */
+#define BTA_AG_ERR_CORP_PUK_REQ 47 /* Corporate personalization PUK required */
+#define BTA_AG_ERR_UNKNOWN 100 /* Unknown error */
+/* GPRS-related errors */
+#define BTA_AG_ERR_ILL_MS 103 /* Illegal MS (#3) */
+#define BTA_AG_ERR_ILL_ME 106 /* Illegal ME (#6) */
+#define BTA_AG_ERR_GPRS_NOT_ALLOWED 107 /* GPRS services not allowed (#7) */
+#define BTA_AG_ERR_PLMN_NOT_ALLOWED 111 /* PLMN services not allowed (#11) */
+#define BTA_AG_ERR_LOC_NOT_ALLOWED 112 /* Location area not allowed (#12) */
+#define BTA_AG_ERR_ROAM_NOT_ALLOWED 113 /* Roaming not allowed in this location area (#13) */
+/* Errors related to a failure to Activate a Context */
+#define BTA_AG_ERR_OPT_NOT_SUPP 132 /* Service option not supported (#32) */
+#define BTA_AG_ERR_OPT_NOT_SUBSCR 133 /* Requested service option not subscribed (#33) */
+#define BTA_AG_ERR_OPT_OUT_OF_ORDER 134 /* Service option temporarily out of order (#34) */
+#define BTA_AG_ERR_PDP_AUTH_FAILURE 149 /* PDP authentication failure */
+/* Other GPRS errors */
+#define BTA_AG_ERR_INV_MOBILE_CLASS 150 /* Invalid mobile class */
+#define BTA_AG_ERR_UNSPEC_GPRS_ERR 148 /* Unspecified GPRS error */
+#endif /* Unused error codes */
+
+/* HFP result data 'ok_flag' */
+#define BTA_AG_OK_CONTINUE 0 /* Send out response (more responses coming) */
+#define BTA_AG_OK_DONE 1 /* Send out response followed by OK (finished) */
+#define BTA_AG_OK_ERROR 2 /* Error response */
+typedef UINT8 tBTA_AG_AT_RESULT_TYPE;
+
+/* BTRH values */
+#define BTA_AG_BTRH_SET_HOLD 0 /* Put incoming call on hold */
+#define BTA_AG_BTRH_SET_ACC 1 /* Accept incoming call on hold */
+#define BTA_AG_BTRH_SET_REJ 2 /* Reject incoming call on hold */
+#define BTA_AG_BTRH_READ 3 /* Read the current value */
+#define BTA_AG_BTRH_NO_RESP 4 /* Not in RH States (reply to read) */
+typedef UINT8 tBTA_AG_BTRH_TYPE;
+
+/* ASCII character string of arguments to the AT command or result */
+#ifndef BTA_AG_AT_MAX_LEN
+#define BTA_AG_AT_MAX_LEN 256
+#endif
+
+/* indicator constants HFP 1.1 and later */
+#define BTA_AG_IND_CALL 0 /* position of call indicator */
+#define BTA_AG_IND_CALLSETUP 1 /* position of callsetup indicator */
+#define BTA_AG_IND_SERVICE 2 /* position of service indicator */
+/* indicator constants HFP 1.5 and later */
+#define BTA_AG_IND_SIGNAL 3 /* position of signal strength indicator */
+#define BTA_AG_IND_ROAM 4 /* position of roaming indicator */
+#define BTA_AG_IND_BATTCHG 5 /* position of battery charge indicator */
+#define BTA_AG_IND_CALLHELD 6 /* position of callheld indicator */
+#define BTA_AG_IND_BEARER 7 /* position of bearer indicator */
+typedef UINT16 tBTA_AG_IND_TYPE;
+
+/* call indicator values */
+#define BTA_AG_CALL_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_CALL_ACTIVE 1 /* Phone call active */
+/* callsetup indicator values */
+#define BTA_AG_CALLSETUP_NONE 0 /* Not currently in call set up */
+#define BTA_AG_CALLSETUP_INCOMING 1 /* Incoming call process ongoing */
+#define BTA_AG_CALLSETUP_OUTGOING 2 /* Outgoing call set up is ongoing */
+#define BTA_AG_CALLSETUP_ALERTING 3 /* Remote party being alerted in an outgoing call */
+/* service indicator values */
+#define BTA_AG_SERVICE_NONE 0 /* Neither CS nor VoIP service is available */
+#define BTA_AG_SERVICE_CS 1 /* Only CS service is available */
+#define BTA_AG_SERVICE_VOIP 2 /* Only VoIP service is available */
+#define BTA_AG_SERVICE_CS_VOIP 3 /* Both CS and VoIP services available */
+/* callheld indicator values */
+#define BTA_AG_CALLHELD_INACTIVE 0 /* No held calls */
+#define BTA_AG_CALLHELD_ACTIVE 1 /* Call held and call active */
+#define BTA_AG_CALLHELD_NOACTIVE 2 /* Call held and no call active */
+/* signal strength indicator values */
+#define BTA_AG_ROAMING_INACTIVE 0 /* Phone call inactive */
+#define BTA_AG_ROAMING_ACTIVE 1 /* Phone call active */
+/* bearer indicator values */
+#define BTA_AG_BEARER_WLAN 0 /* WLAN */
+#define BTA_AG_BEARER_BLUETOOTH 1 /* Bluetooth */
+#define BTA_AG_BEARER_WIRED 2 /* Wired */
+#define BTA_AG_BEARER_2G3G 3 /* 2G 3G */
+#define BTA_AG_BEARER_WIMAX 4 /* WIMAX */
+#define BTA_AG_BEARER_RES1 5 /* Reserved */
+#define BTA_AG_BEARER_RES2 6 /* Reserved */
+#define BTA_AG_BEARER_RES3 7 /* Reserved */
+
+/* data associated with BTA_AG_IND_RES */
+typedef struct
+{
+ tBTA_AG_IND_TYPE type;
+ UINT16 value;
+} tBTA_AG_IND;
+
+/* data type for BTA_AgResult() */
+typedef struct
+{
+ char str[BTA_AG_AT_MAX_LEN+1]; /* used for cops,clcc,cnum... */
+ tBTA_AG_IND ind; /* used for indicator type */
+ UINT16 num; /* used for codec state */
+ UINT16 audio_handle; /* used for audio path */
+ UINT16 errcode; /* Valid only if 'ok_flag' is set to BTA_AG_OK_ERROR */
+ UINT8 ok_flag; /* Indicates if response is finished, and if error occurred */
+ BOOLEAN state;
+} tBTA_AG_RES_DATA;
+
+/* data associated with most non-AT events */
+typedef struct
+{
+ UINT16 handle;
+ UINT8 app_id;
+ tBTA_AG_STATUS status;
+} tBTA_AG_HDR;
+
+/* data associated with BTA_AG_REGISTER_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ UINT16 handle;
+ tBTA_AG_STATUS status;
+} tBTA_AG_REGISTER;
+
+/* data associated with BTA_AG_OPEN_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+ tBTA_SERVICE_ID service_id;
+ tBTA_AG_STATUS status;
+} tBTA_AG_OPEN;
+
+/* data associated with BTA_AG_CLOSE_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+} tBTA_AG_CLOSE;
+
+/* data associated with BTA_AG_CONN_EVT */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ tBTA_AG_PEER_FEAT peer_feat;
+ BD_ADDR bd_addr;
+ tBTA_AG_PEER_CODEC peer_codec;
+ tBTA_AG_CHLD_FEAT chld_feat;
+} tBTA_AG_CONN;
+
+/* data associated with AT command event */
+typedef struct
+{
+ tBTA_AG_HDR hdr;
+ BD_ADDR bd_addr;
+ char str[BTA_AG_AT_MAX_LEN+1];
+ UINT16 num; /* voice recognition state*/
+ UINT8 idx; /* call number used by CLCC and CHLD */
+ UINT16 value;
+} tBTA_AG_VAL;
+
+/* data associated with BTA_AG_CLIP_EVT and BTA_AG_CCWA_EVT*/
+#define BTA_AG_NUMBER_LEN 32
+typedef struct {
+ char number[BTA_AG_NUMBER_LEN + 1];
+} tBTA_AG_NUMBER;
+
+/* data associated with BTA_HF_CLIENT_OPERATOR_NAME_EVT */
+#define BTA_AG_COPS_LEN 16
+typedef struct {
+ char name[BTA_AG_COPS_LEN + 1];
+} tBTA_AG_COPS;
+
+/* data associated with BTA_AG_AT_RESULT_EVT event */
+typedef struct {
+ tBTA_AG_AT_RESULT_TYPE type;
+ UINT16 cme;
+} tBTA_AG_AT_RESULT;
+
+/* data associated with BTA_AG_CLCC_EVT event */
+typedef struct {
+ UINT32 idx;
+ BOOLEAN inc;
+ UINT8 status;
+ BOOLEAN mpty;
+ BOOLEAN number_present;
+ char number[BTA_AG_NUMBER_LEN + 1];
+} tBTA_AG_CLCC;
+
+/* data associated with BTA_AG_CNUM_EVT event */
+typedef struct {
+ UINT16 service;
+ char number[BTA_AG_NUMBER_LEN + 1];
+} tBTA_AG_CNUM;
+
+/* union of data associated with AG callback */
+typedef union
+{
+ tBTA_AG_HDR hdr;
+ tBTA_AG_REGISTER reg;
+ tBTA_AG_OPEN open;
+ tBTA_AG_CLOSE close;
+ tBTA_AG_CONN conn;
+ tBTA_AG_IND ind;
+ tBTA_AG_VAL val;
+ //add
+ tBTA_AG_COPS operator;
+ tBTA_AG_NUMBER number;
+ tBTA_AG_AT_RESULT result;
+ tBTA_AG_CLCC clcc;
+ tBTA_AG_CNUM cnum;
+} tBTA_AG;
+
+/* AG callback */
+typedef void (tBTA_AG_CBACK)(tBTA_AG_EVT event, tBTA_AG *p_data);
+
+/* AG configuration structure */
+typedef struct
+{
+ char *cind_info;
+ INT32 conn_tout;
+ UINT16 sco_pkt_types;
+ char *chld_val_ecc;
+ char *chld_val;
+} tBTA_AG_CFG;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+** External Function Declarations
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function BTA_AgEnable
+**
+** Description Enable the audio gateway service. When the enable
+** operation is complete the callback function will be
+** called with a BTA_AG_ENABLE_EVT. This function must
+** be called before other function in the AG API are
+** called.
+**
+** Returns BTA_SUCCESS if OK, BTA_FAILURE otherwise.
+**
+*******************************************************************************/
+tBTA_STATUS BTA_AgEnable(tBTA_AG_PARSE_MODE parse_mode, tBTA_AG_CBACK *p_cback);
+
+/*******************************************************************************
+**
+** Function BTA_AgDisable
+**
+** Description Disable the audio gateway service
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDisable(void);
+
+/*******************************************************************************
+**
+** Function BTA_AgRegister
+**
+** Description Register an Audio Gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgRegister(tBTA_SERVICE_MASK services, tBTA_SEC sec_mask,
+ tBTA_AG_FEAT features, char *p_service_names[], UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function BTA_AgDeregister
+**
+** Description Deregister an audio gateway service.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgDeregister(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgOpen
+**
+** Description Opens a connection to a headset or hands-free device.
+** When connection is open callback function is called
+** with a BTA_AG_OPEN_EVT. Only the data connection is
+** opened. The audio connection is not opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgOpen(UINT16 handle, BD_ADDR bd_addr, tBTA_SEC sec_mask, tBTA_SERVICE_MASK services);
+
+/*******************************************************************************
+**
+** Function BTA_AgClose
+**
+** Description Close the current connection to a headset or a handsfree
+** Any current audio connection will also be closed
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioOpen
+**
+** Description Opens an audio connection to the currently connected
+** headset or hnadsfree
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioOpen(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgAudioClose
+**
+** Description Close the currently active audio connection to a headset
+** or hnadsfree. The data connection remains open
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgAudioClose(UINT16 handle);
+
+/*******************************************************************************
+**
+** Function BTA_AgResult
+**
+** Description Send an AT result code to a headset or hands-free device.
+** This function is only used when the AG parse mode is set
+** to BTA_AG_PARSE.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgResult(UINT16 handle, tBTA_AG_RES result, tBTA_AG_RES_DATA *p_data);
+
+/*******************************************************************************
+**
+** Function BTA_AgSetCodec
+**
+** Description Specify the codec type to be used for the subsequent
+** audio connection.
+**
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgSetCodec(UINT16 handle, tBTA_AG_PEER_CODEC codec);
+
+
+#if (BTM_SCO_HCI_INCLUDED == TRUE )
+/*******************************************************************************
+**
+** Function BTA_AgCiData
+**
+** Description Give an EVT to BTA that tell outgoing data is ready.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void BTA_AgCiData(void);
+#endif /*#if (BTM_SCO_HCI_INCLUDED == TRUE ) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
+
+#endif /* BTA_HF_API_H */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2003-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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This is the interface file for audio gateway call-out and call-in functions.
+ *
+ ******************************************************************************/
+#ifndef BTA_AG_CIO_H
+#define BTA_AG_CIO_H
+
+#include "bta/bta_ag_api.h"
+#include "hci/hci_audio.h"
+
+#if (BTA_AG_INCLUDED == TRUE)
+/*******************************************************************************
+**
+** Function bta_ag_sco_audio_state
+**
+** Description This function is called by the AG before the audio connection
+** is brought up, after it comes up, and after it goes down.
+**
+** Parameters handle - handle of the AG instance
+** state - Audio state
+** codec - if WBS support is compiled in, codec to going to be used is provided
+** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
+** the correct platform parameters.
+** in the other states codec type should not be ignored
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_WBS_INCLUDED == TRUE )
+void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state, tBTA_AG_PEER_CODEC codec);
+#else
+void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state);
+#endif
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_init
+**
+** Description Set default data path for SCO/eSCO.
+** This callout function is executed by AG when it is
+** started by calling BTA_AgEnable(). This function can be
+** used by the phone to initialize audio paths or for other
+** initialization purposes.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+tBTA_HFP_SCO_ROUTE_TYPE bta_ag_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id);
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_open
+**
+** Description This function is executed by AG when a service level connection
+** is opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_open(UINT16 handle, tBTM_SCO_AIR_MODE_TYPE air_mode, UINT8 inout_pkt_size, UINT16 event);
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_close
+**
+** Description This function is called by AG when a service level
+** connection is closed.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_close(void);
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_out_data
+**
+** Description This function is called to send SCO data over HCI.
+**
+** Returns number of bytes got from application
+**
+*******************************************************************************/
+uint32_t bta_ag_sco_co_out_data(UINT8 *p_buf);
+
+/*******************************************************************************
+**
+** Function bta_hf_client_sco_co_in_data
+**
+** Description This function is called to send incoming SCO data to application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status);
+
+/*******************************************************************************
+**
+** Function bta_ag_co_tx_write
+**
+** Description This function is called by the AG to send data to the
+** phone when the AG is configured for AT command pass-through.
+** The implementation of this function must copy the data to
+** the phones memory.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_co_tx_write(UINT16 handle, UINT8 *p_data, UINT16 len);
+
+/*******************************************************************************
+**
+** Function bta_ag_ci_rx_write
+**
+** Description This function is called to send data to the AG when the AG
+** is configured for AT command pass-through. The function
+** copies data to an event buffer and sends it.
+**
+** Returns void
+**
+*******************************************************************************/
+extern void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len);
+
+/******************************************************************************
+**
+** Function bta_ag_ci_slc_ready
+**
+** Description This function is called to notify AG that SLC is up at
+** the application. This funcion is only used when the app
+** is running in pass-through mode.
+**
+** Returns void
+**
+******************************************************************************/
+extern void bta_ag_ci_slc_ready(UINT16 handle);
+
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
+
+#endif /* BTA_AG_CIO_H */
\ No newline at end of file
extern bt_status_t btc_av_source_execute_service(BOOLEAN b_enable);
extern bt_status_t btc_av_sink_execute_service(BOOLEAN b_enable);
#endif
+#if BTC_HF_INCLUDED
+extern bt_status_t btc_hf_execute_service(BOOLEAN b_enable);
+#endif
#if BTC_HF_CLIENT_INCLUDED
extern bt_status_t btc_hf_client_execute_service(BOOLEAN b_enable);
#endif
btc_av_sink_execute_service(b_enable);
break;
#endif
+#if BTC_HF_INCLUDED
+ case BTA_HFP_SERVICE_ID:
+ btc_hf_execute_service(b_enable);
+ break;
+#endif /* #if BTC_HF_INCLUDED */
#if BTC_HF_CLIENT_INCLUDED
case BTA_HFP_HS_SERVICE_ID:
btc_hf_client_execute_service(b_enable);
#if (BTA_AV_INCLUDED == TRUE)
#include "bta/bta_av_api.h"
#endif ///BTA_AV_INCLUDED == TRUE
+
+#if (BTA_AG_INCLUDED == TRUE)
+#include "bta/bta_ag_api.h"
+#endif ///BTA_AG_INCLUDED == TRUE
+
#include "common/bt_defs.h"
#include "stack/btm_api.h"
#include "bta/bta_api.h"
}
#endif ///BTA_AV_INCLUDED == TRUE
+#if (BTA_AG_INCLUDED == TRUE)
+const char* dump_hf_conn_state(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(ESP_HF_CONNECTION_STATE_DISCONNECTED)
+ CASE_RETURN_STR(ESP_HF_CONNECTION_STATE_CONNECTING)
+ CASE_RETURN_STR(ESP_HF_CONNECTION_STATE_CONNECTED)
+ CASE_RETURN_STR(ESP_HF_CONNECTION_STATE_SLC_CONNECTED)
+ CASE_RETURN_STR(ESP_HF_CONNECTION_STATE_DISCONNECTING)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_event(UINT16 event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(BTA_AG_ENABLE_EVT)
+ CASE_RETURN_STR(BTA_AG_REGISTER_EVT)
+ CASE_RETURN_STR(BTA_AG_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_CONN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_OPEN_EVT)
+ CASE_RETURN_STR(BTA_AG_AUDIO_CLOSE_EVT)
+ CASE_RETURN_STR(BTA_AG_SPK_EVT)
+ CASE_RETURN_STR(BTA_AG_MIC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CKPD_EVT)
+ CASE_RETURN_STR(BTA_AG_DISABLE_EVT)
+#if (BTM_WBS_INCLUDED == TRUE )
+ CASE_RETURN_STR(BTA_AG_WBS_EVT)
+#endif
+ CASE_RETURN_STR(BTA_AG_AT_A_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_D_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHLD_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CHUP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CIND_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_VTS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BINP_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BLDN_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BVRA_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_NREC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CNUM_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BTRH_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CLCC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_COPS_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_UNAT_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_CBC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BAC_EVT)
+ CASE_RETURN_STR(BTA_AG_AT_BCS_EVT)
+
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+const char* dump_hf_call_state(esp_hf_call_status_t call_state)
+{
+ switch(call_state)
+ {
+ CASE_RETURN_STR(ESP_HF_CALL_STATUS_NO_CALLS)
+ CASE_RETURN_STR(ESP_HF_CALL_STATUS_CALL_IN_PROGRESS)
+ default:
+ return "UNKNOWN CALL STATE";
+ }
+}
+
+const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state)
+{
+ switch(call_setup_state)
+ {
+ CASE_RETURN_STR(ESP_HF_CALL_SETUP_STATUS_IDLE)
+ CASE_RETURN_STR(ESP_HF_CALL_SETUP_STATUS_INCOMING)
+ CASE_RETURN_STR(ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING)
+ CASE_RETURN_STR(ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING)
+ default:
+ return "UNKNOWN CALL SETUP STATE";
+ }
+}
+
+#endif // #if (BTA_AG_INCLUDED == TRUE)
+
UINT32 devclass2uint(DEV_CLASS dev_class)
{
UINT32 cod = 0;
#include "stack/bt_types.h"
#include "common/bt_defs.h"
#include "esp_bt_defs.h"
+#include "esp_hf_defs.h"
/*******************************************************************************
** Constants & Macros
/*******************************************************************************
** Functions
********************************************************************************/
+#if(BTA_AV_INCLUDED == TRUE)
const char *dump_rc_event(UINT8 event);
const char *dump_rc_notification_event_id(UINT8 event_id);
const char *dump_rc_pdu(UINT8 pdu);
+#endif
+
+#if(BTA_AG_INCLUDED == TRUE)
+const char *dump_hf_conn_state(UINT16 event);
+const char *dump_hf_event(UINT16 event);
+const char *dump_hf_call_state(esp_hf_call_status_t call_state);
+const char* dump_hf_call_setup_state(esp_hf_call_setup_status_t call_setup_state);
+#endif
UINT32 devclass2uint(DEV_CLASS dev_class);
void uint2devclass(UINT32 dev, DEV_CLASS dev_class);
--- /dev/null
+/******************************************************************************
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_btc_bta_ag"
+
+#include "btc_hf_ag.h"
+#include "bta_ag_int.h"
+#include "bta/bta_api.h"
+#include "bta/bta_ag_api.h"
+#include "bta/bta_ag_co.h"
+#include "bta/bta_dm_co.h"
+#include "common/bt_target.h"
+#include "hci/hci_audio.h"
+#include "osi/allocator.h"
+#include <string.h>
+
+#if (BTA_AG_INCLUDED == TRUE)
+
+/*******************************************************************************
+ * CONST
+********************************************************************************/
+#if (BTM_SCO_HCI_INCLUDED == TRUE)
+#include "oi_codec_sbc.h"
+#include "oi_status.h"
+#include "sbc_encoder.h"
+
+#if (PLC_INCLUDED == TRUE)
+#include "sbc_plc.h"
+typedef struct {
+ bool first_good_frame_found;
+ sbc_plc_state_t plc_state;
+ int16_t sbc_plc_out[SBC_FS];
+} bta_hf_ct_plc_t;
+#if HFP_DYNAMIC_MEMORY == FALSE
+static bta_hf_ct_plc_t bta_hf_ct_plc;
+#else
+static bta_hf_ct_plc_t *bta_hf_ct_plc_ptr;
+#define bta_hf_ct_plc (*bta_hf_ct_plc_ptr)
+#endif ///HFP_DYNAMIC_MEMORY == FALSE
+#endif ///(PLC_INCLUDED == TRUE)
+
+#define HF_SBC_DEC_CONTEXT_DATA_LEN (CODEC_DATA_WORDS(1, SBC_CODEC_FAST_FILTER_BUFFERS))
+#define HF_SBC_DEC_RAW_DATA_SIZE 240
+#define HF_SBC_ENC_RAW_DATA_SIZE 240
+
+/* BTA-AG-CO control block to map bdaddr to BTA handle */
+typedef struct
+{
+ OI_CODEC_SBC_DECODER_CONTEXT decoder_context;
+ OI_UINT32 decoder_context_data[HF_SBC_DEC_CONTEXT_DATA_LEN];
+ OI_INT16 decode_raw_data[HF_SBC_DEC_RAW_DATA_SIZE];
+
+ SBC_ENC_PARAMS encoder;
+
+ UINT8 sequence_number;
+ bool is_bad_frame;
+ bool decode_first_pkt;
+ OI_BYTE decode_msbc_data[BTM_MSBC_FRAME_SIZE];
+ bool encode_first_pkt;
+ OI_BYTE encode_msbc_data[BTM_MSBC_FRAME_SIZE];
+} bta_ag_co_cb_t;
+
+#if HFP_DYNAMIC_MEMORY == FALSE
+static bta_ag_co_cb_t bta_ag_co_cb;
+#else
+static bta_ag_co_cb_t *bta_ag_co_cb_ptr;
+#define bta_ag_co_cb (*bta_ag_co_cb_ptr)
+#endif /* HFP_DYNAMIC_MEMORY == FALSE */
+
+static UINT8 hf_air_mode = BTM_SCO_AIR_MODE_TRANSPNT;
+static UINT8 hf_inout_pkt_size = 0;
+
+/* =========================================================================
+* AG pass-through mode handle
+*===========================================================================*/
+/*******************************************************************************
+ **
+ ** Function bta_ag_co_tx_write
+ **
+ ** Description This function is called by the AG to send data to the
+ ** phone when the AG is configured for AT command pass-through.
+ ** The implementation of this function must copy the data to
+ ** the phones memory.
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void bta_ag_co_tx_write(UINT16 handle, UNUSED_ATTR UINT8 * p_data, UINT16 len)
+{
+ BTIF_TRACE_DEBUG( "bta_ag_co_tx_write: handle: %d, len: %d", handle, len );
+}
+
+/******************************************************************************
+**
+** Function bta_ag_ci_rx_write
+**
+** Description This function is called to send data to the AG when the AG
+** is configured for AT command pass-through. The function
+** copies data to an event buffer and sends it.
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_ci_rx_write(UINT16 handle, char *p_data, UINT16 len)
+{
+ tBTA_AG_CI_RX_WRITE *p_buf;
+ UINT16 len_remaining = len;
+ char *p_data_area;
+
+ if (len > (BT_DEFAULT_BUFFER_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1)) {
+ len = BT_DEFAULT_BUFFER_SIZE - sizeof(tBTA_AG_CI_RX_WRITE) - 1;
+ }
+
+ while (len_remaining) {
+ if (len_remaining < len) {
+ len = len_remaining;
+ }
+ if ((p_buf = (tBTA_AG_CI_RX_WRITE *) osi_malloc((UINT16)(sizeof(tBTA_AG_CI_RX_WRITE) + len + 1))) != NULL) {
+ p_buf->hdr.event = BTA_AG_CI_RX_WRITE_EVT;
+ p_buf->hdr.layer_specific = handle;
+ p_data_area = (char *)(p_buf+1); /* Point to data area after header */
+ strncpy(p_data_area, p_data, len);
+ p_data_area[len] = 0;
+ bta_sys_sendmsg(p_buf);
+ } else {
+ APPL_TRACE_ERROR("ERROR: Unable to allocate buffer to hold AT response code. len=%i", len);
+ break;
+ }
+ len_remaining-=len;
+ p_data+=len;
+ }
+}
+
+/******************************************************************************
+**
+** Function bta_ag_ci_slc_ready
+**
+** Description This function is called to notify AG that SLC is up at
+** the application. This funcion is only used when the app
+** is running in pass-through mode.
+**
+** Returns void
+**
+******************************************************************************/
+void bta_ag_ci_slc_ready(UINT16 handle)
+{
+ tBTA_AG_DATA *p_buf;
+ if ((p_buf = (tBTA_AG_DATA *)osi_malloc(sizeof(tBTA_AG_DATA))) != NULL) {
+ p_buf->hdr.event = BTA_AG_CI_SLC_READY_EVT;
+ p_buf->hdr.layer_specific = handle;
+ bta_sys_sendmsg(p_buf);
+ }
+}
+
+/*******************************************************************************
+ * H2 & DEC
+********************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ag_h2_header
+**
+** Description This function is called to fill in H2 header
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_h2_header(UINT16 *p_buf)
+{
+ // H2: Header with synchronization word and sequence number
+#define BTA_HF_H2_HEADER 0x0801
+#define BTA_HF_H2_HEADER_BIT0_MASK (1 << 0)
+#define BTA_HF_H2_HEADER_BIT1_MASK (1 << 1)
+#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET1 12
+#define BTA_HF_H2_HEADER_SN0_BIT_OFFSET2 13
+#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 14
+#define BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 15
+
+ UINT16 h2_header = BTA_HF_H2_HEADER;
+ UINT8 h2_header_sn0 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT0_MASK;
+ UINT8 h2_header_sn1 = bta_ag_co_cb.sequence_number & BTA_HF_H2_HEADER_BIT1_MASK;
+ h2_header |= (h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET1
+ | h2_header_sn0 << BTA_HF_H2_HEADER_SN0_BIT_OFFSET2
+ | h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET1 - 1)
+ | h2_header_sn1 << (BTA_HF_H2_HEADER_SN1_BIT_OFFSET2 - 1)
+ );
+ bta_ag_co_cb.sequence_number++;
+ *p_buf = h2_header;
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_hf_dec_init
+ **
+ ** Description Initialize decoding task
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void bta_hf_dec_init(void)
+{
+#if (PLC_INCLUDED == TRUE)
+ sbc_plc_init(&(bta_hf_ct_plc.plc_state));
+#endif ///(PLC_INCLUDED == TRUE)
+
+ OI_STATUS status = OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data,
+ HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE);
+ if (!OI_SUCCESS(status)) {
+ APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function bta_hf_enc_init
+ **
+ ** Description Initialize encoding task for mSBC
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void bta_hf_enc_init(void)
+{
+ bta_ag_co_cb.sequence_number = 0;
+ bta_ag_co_cb.decode_first_pkt = true;
+ bta_ag_co_cb.encode_first_pkt = true;
+ bta_ag_co_cb.is_bad_frame = false;
+
+ bta_ag_co_cb.encoder.sbc_mode = SBC_MODE_MSBC;
+ bta_ag_co_cb.encoder.s16NumOfBlocks = 15;
+ bta_ag_co_cb.encoder.s16NumOfSubBands = 8;
+ bta_ag_co_cb.encoder.s16AllocationMethod = SBC_LOUDNESS;
+ bta_ag_co_cb.encoder.s16BitPool = 26;
+ bta_ag_co_cb.encoder.s16ChannelMode = SBC_MONO;
+ bta_ag_co_cb.encoder.s16NumOfChannels = 1;
+ bta_ag_co_cb.encoder.s16SamplingFreq = SBC_sf16000;
+
+ SBC_Encoder_Init(&(bta_ag_co_cb.encoder));
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_decode_msbc_frame
+**
+** Description This function is called decode a mSBC frame
+**
+** Returns void
+**
+*******************************************************************************/
+static void bta_ag_decode_msbc_frame(UINT8 **data, UINT8 *length, BOOLEAN is_bad_frame)
+{
+ OI_STATUS status;
+ const OI_BYTE *zero_signal_frame_data;
+ UINT8 zero_signal_frame_len = BTM_MSBC_FRAME_DATA_SIZE;
+ UINT32 sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
+
+ if (is_bad_frame) {
+ status = OI_CODEC_SBC_CHECKSUM_MISMATCH;
+ } else {
+ status = OI_CODEC_SBC_DecodeFrame(&bta_ag_co_cb.decoder_context, (const OI_BYTE **)data,
+ (OI_UINT32 *)length,
+ (OI_INT16 *)bta_ag_co_cb.decode_raw_data,
+ (OI_UINT32 *)&sbc_raw_data_size);
+ }
+
+// PLC_INCLUDED will be set to TRUE when enabling Wide Band Speech
+#if (PLC_INCLUDED == TRUE)
+ switch(status) {
+ case OI_OK:
+ {
+ bta_hf_ct_plc.first_good_frame_found = TRUE;
+ sbc_plc_good_frame(&(bta_hf_ct_plc.plc_state), (int16_t *)bta_ag_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
+ }
+
+ case OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA:
+ case OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA:
+ case OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA:
+ break;
+
+ case OI_CODEC_SBC_NO_SYNCWORD:
+ case OI_CODEC_SBC_CHECKSUM_MISMATCH:
+ {
+ if (!bta_hf_ct_plc.first_good_frame_found) {
+ break;
+ }
+ zero_signal_frame_data = sbc_plc_zero_signal_frame();
+ sbc_raw_data_size = HF_SBC_DEC_RAW_DATA_SIZE;
+ status = OI_CODEC_SBC_DecodeFrame(&bta_ag_co_cb.decoder_context, &zero_signal_frame_data,
+ (OI_UINT32 *)&zero_signal_frame_len,
+ (OI_INT16 *)bta_ag_co_cb.decode_raw_data,
+ (OI_UINT32 *)&sbc_raw_data_size);
+ sbc_plc_bad_frame(&(bta_hf_ct_plc.plc_state), bta_ag_co_cb.decode_raw_data, bta_hf_ct_plc.sbc_plc_out);
+ APPL_TRACE_DEBUG("bad frame, using PLC to fix it.");
+ break;
+ }
+
+ case OI_STATUS_INVALID_PARAMETERS:
+ {
+ // This caused by corrupt frames.
+ // The codec apparently does not recover from this.
+ // Re-initialize the codec.
+ APPL_TRACE_ERROR("Frame decode error: OI_STATUS_INVALID_PARAMETERS");
+
+ if (!OI_SUCCESS(OI_CODEC_SBC_DecoderReset(&bta_ag_co_cb.decoder_context, bta_ag_co_cb.decoder_context_data,
+ HF_SBC_DEC_CONTEXT_DATA_LEN * sizeof(OI_UINT32), 1, 1, FALSE, TRUE))) {
+ APPL_TRACE_ERROR("OI_CODEC_SBC_DecoderReset failed with error code %d\n", status);
+ }
+ break;
+ }
+
+ default:
+ APPL_TRACE_ERROR("Frame decode error: %d", status);
+ break;
+ }
+#endif ///(PLC_INCLUDED == TRUE)
+
+ if (OI_SUCCESS(status)) {
+ btc_hf_incoming_data_cb_to_app((const uint8_t *)(bta_hf_ct_plc.sbc_plc_out), sbc_raw_data_size);
+ }
+}
+
+/*******************************************************************************
+ * BTA AG SCO CO FUNCITONS
+********************************************************************************/
+/*******************************************************************************
+**
+** Function bta_ag_sco_audio_state
+**
+** Description This function is called by the AG before the audio connection
+** is brought up, after it comes up, and after it goes down.
+**
+** Parameters handle - handle of the AG instance
+** state - Audio state
+** codec - if WBS support is compiled in, codec to going to be used is provided
+** and when in SCO_STATE_SETUP, BTM_I2SPCMConfig() must be called with
+** the correct platform parameters.
+** in the other states codec type should not be ignored
+**
+** Returns void
+**
+*******************************************************************************/
+#if (BTM_WBS_INCLUDED == TRUE )
+void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state, tBTA_AG_PEER_CODEC codec)
+#else
+void bta_ag_sco_audio_state(UINT16 handle, UINT8 app_id, UINT8 state)
+#endif
+{
+ BTIF_TRACE_DEBUG("bta_ag_sco_audio_state: handle %d, state %d", handle, state);
+ switch (state) {
+ case SCO_STATE_ON:
+ case SCO_STATE_OFF:
+ case SCO_STATE_OFF_TRANSFER:
+ case SCO_STATE_SETUP:
+ default:
+ break;
+ }
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_init
+**
+** Description Set default data path for SCO/eSCO.
+**
+**
+** Returns Void.
+**
+*******************************************************************************/
+tBTA_HFP_SCO_ROUTE_TYPE bta_ag_sco_co_init(UINT32 rx_bw, UINT32 tx_bw, tBTA_HFP_CODEC_INFO *p_codec_info, UINT8 app_id)
+{
+ APPL_TRACE_EVENT("%s rx_bw %d, tx_bw %d, codec %d", __FUNCTION__, rx_bw, tx_bw, p_codec_info->codec_type);
+ return BTA_HFP_SCO_ROUTE_HCI;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_open
+**
+** Description This function is executed by AG when a service level connection
+** is opened.
+**
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_open(UINT16 handle, tBTM_SCO_AIR_MODE_TYPE air_mode, UINT8 inout_pkt_size, UINT16 event)
+{
+ APPL_TRACE_EVENT("%s hdl %x, pkt_sz %u, event %u", __FUNCTION__, handle, inout_pkt_size, event);
+ hf_air_mode = air_mode;
+ hf_inout_pkt_size = inout_pkt_size;
+
+ if (air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+ bta_ag_co_cb_ptr = osi_calloc(sizeof(bta_ag_co_cb_t));
+ if (!bta_ag_co_cb_ptr) {
+ APPL_TRACE_ERROR("%s allocate failed", __FUNCTION__);
+ goto error_exit;
+ }
+#if (PLC_INCLUDED == TRUE)
+ bta_hf_ct_plc_ptr = (bta_hf_ct_plc_t *)osi_calloc(sizeof(bta_hf_ct_plc_t));
+ if (!bta_hf_ct_plc_ptr) {
+ APPL_TRACE_ERROR("%s malloc fail.", __FUNCTION__);
+ goto error_exit;
+ }
+#endif ///(PLC_INCLUDED == TRUE)
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
+ bta_hf_dec_init();
+ bta_hf_enc_init();
+ return;
+ } else {
+ return; // Nothing to do
+ }
+
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+error_exit:;
+ hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
+ hf_inout_pkt_size = 0;
+ if (bta_ag_co_cb_ptr) {
+ osi_free(bta_ag_co_cb_ptr);
+ bta_ag_co_cb_ptr = NULL;
+ }
+#if (PLC_INCLUDED == TRUE)
+ if (bta_hf_ct_plc_ptr) {
+ osi_free(bta_hf_ct_plc_ptr);
+ bta_hf_ct_plc_ptr = NULL;
+ }
+#endif ///(PLC_INCLUDED == TRUE)
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
+ return;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_close
+**
+** Description Nothing but print some log.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_close(void)
+{
+ APPL_TRACE_EVENT("%s", __FUNCTION__);
+ if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+#if (PLC_INCLUDED == TRUE)
+ sbc_plc_deinit(&(bta_hf_ct_plc.plc_state));
+ bta_hf_ct_plc.first_good_frame_found = FALSE;
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+ osi_free(bta_hf_ct_plc_ptr);
+ bta_hf_ct_plc_ptr = NULL;
+#endif /// (HFP_DYNAMIC_MEMORY == TRUE)
+#endif ///(PLC_INCLUDED == TRUE)
+
+#if (HFP_DYNAMIC_MEMORY == TRUE)
+ osi_free(bta_ag_co_cb_ptr);
+ bta_ag_co_cb_ptr = NULL;
+#endif /* HFP_DYNAMIC_MEMORY == TRUE */
+ } else {
+ // Nothing to do
+ }
+ hf_air_mode = BTM_SCO_AIR_MODE_UNKNOWN;
+ hf_inout_pkt_size = 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_out_data
+**
+** Description This function is called to send SCO data over HCI.
+**
+** Returns number of bytes got from application
+**
+*******************************************************************************/
+uint32_t bta_ag_sco_co_out_data(UINT8 *p_buf)
+{
+ if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
+ // CVSD
+ uint32_t hf_raw_pkt_size = hf_inout_pkt_size;
+ return btc_hf_outgoing_data_cb_to_app(p_buf, hf_raw_pkt_size);
+ } else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+ // mSBC
+ if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
+ if (bta_ag_co_cb.encode_first_pkt) {
+ UINT32 size = btc_hf_outgoing_data_cb_to_app((UINT8 *)bta_ag_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
+ if (size != HF_SBC_ENC_RAW_DATA_SIZE) {
+ return 0;
+ }
+ bta_ag_h2_header((UINT16 *)bta_ag_co_cb.encode_msbc_data);
+ bta_ag_co_cb.encoder.pu8Packet = bta_ag_co_cb.encode_msbc_data + 2;
+
+ SBC_Encoder(&bta_ag_co_cb.encoder);
+ memcpy(p_buf, bta_ag_co_cb.encode_msbc_data, hf_inout_pkt_size);
+ bta_ag_co_cb.encode_first_pkt = !bta_ag_co_cb.encode_first_pkt;
+ return hf_inout_pkt_size;
+ } else {
+ memcpy(p_buf, bta_ag_co_cb.encode_msbc_data + hf_inout_pkt_size, hf_inout_pkt_size);
+ bta_ag_co_cb.encode_first_pkt = !bta_ag_co_cb.encode_first_pkt;
+ return hf_inout_pkt_size;
+ }
+ } else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
+ UINT32 size = btc_hf_outgoing_data_cb_to_app((UINT8 *)bta_ag_co_cb.encoder.as16PcmBuffer, HF_SBC_ENC_RAW_DATA_SIZE);
+ if (size != HF_SBC_ENC_RAW_DATA_SIZE) {
+ return 0;
+ }
+ bta_ag_h2_header((UINT16 *)p_buf);
+ bta_ag_co_cb.encoder.pu8Packet = p_buf + 2;
+
+ SBC_Encoder(&bta_ag_co_cb.encoder);
+ return hf_inout_pkt_size;
+ } else {
+ //Never run to here.
+ }
+ } else {
+ APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
+ }
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function bta_ag_sco_co_in_data
+**
+** Description This function is called to send incoming SCO data to application.
+**
+** Returns void
+**
+*******************************************************************************/
+void bta_ag_sco_co_in_data(BT_HDR *p_buf, tBTM_SCO_DATA_FLAG status)
+{
+ UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
+ UINT8 pkt_size = 0;
+ STREAM_SKIP_UINT16(p);
+ STREAM_TO_UINT8(pkt_size, p);
+
+ if (hf_air_mode == BTM_SCO_AIR_MODE_CVSD) {
+ // CVSD
+ if(status != BTM_SCO_DATA_CORRECT) {
+ APPL_TRACE_DEBUG("%s: not a correct frame(%d).", __func__, status);
+ }
+ btc_hf_incoming_data_cb_to_app(p, pkt_size);
+ } else if (hf_air_mode == BTM_SCO_AIR_MODE_TRANSPNT) {
+ // mSBC
+ UINT8 *data = NULL;
+ if (pkt_size != hf_inout_pkt_size) {
+ bta_ag_co_cb.is_bad_frame = true;
+ }
+ if (status != BTM_SCO_DATA_CORRECT) {
+ bta_ag_co_cb.is_bad_frame = true;
+ }
+ if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE / 2) {
+ if (bta_ag_co_cb.decode_first_pkt) {
+ if (!bta_ag_co_cb.is_bad_frame) {
+ memcpy(bta_ag_co_cb.decode_msbc_data, p, pkt_size);
+ }
+ } else {
+ if (!bta_ag_co_cb.is_bad_frame) {
+ memcpy(bta_ag_co_cb.decode_msbc_data + BTM_MSBC_FRAME_SIZE / 2, p, pkt_size);
+ }
+ data = bta_ag_co_cb.decode_msbc_data;
+ bta_ag_decode_msbc_frame(&data, &pkt_size, bta_ag_co_cb.is_bad_frame);
+ bta_ag_co_cb.is_bad_frame = false;
+ }
+ bta_ag_co_cb.decode_first_pkt = !bta_ag_co_cb.decode_first_pkt;
+ } else if (hf_inout_pkt_size == BTM_MSBC_FRAME_SIZE) {
+ data = p;
+ bta_ag_decode_msbc_frame(&data, &pkt_size, bta_ag_co_cb.is_bad_frame);
+ bta_ag_co_cb.is_bad_frame = false;
+ } else {
+ //Never run to here.
+ }
+ } else {
+ APPL_TRACE_ERROR("%s invaild air mode: %d", __FUNCTION__, hf_air_mode);
+ }
+}
+#endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE) */
+#endif /* #if (BTA_AG_INCLUDED == TRUE) */
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * 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: btc_hf.c
+ *
+ * Description: Handsfree Profile Bluetooth Interface
+ * *
+ ***********************************************************************************/
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "time.h"
+#include "btc/btc_dm.h"
+#include "btc_hf_ag.h"
+#include "btc/btc_profile_queue.h"
+#include "btc/btc_manage.h"
+#include "btc/btc_util.h"
+#include "btc/btc_common.h"
+#include "bta/bta_ag_api.h"
+#include "bt_common.h"
+#include "common/bt_target.h"
+#include "common/bt_trace.h"
+#include "common/bt_defs.h"
+#include "device/bdaddr.h"
+#include "esp_bt.h"
+#include "esp_hf_ag_api.h"
+#include "osi/allocator.h"
+
+
+#if (BTC_HF_INCLUDED == TRUE)
+/************************************************************************************
+** Constants & Macros
+************************************************************************************/
+/* Max HF Clients Supported From App */
+static UINT16 btc_max_hf_clients = 1;
+/* HF Param Definition */
+static hf_local_param_t hf_local_param[BTC_HF_NUM_CB];
+
+#if (BTM_WBS_INCLUDED == TRUE)
+#ifndef BTC_HF_FEATURES
+#define BTC_HF_FEATURES ( BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | \
+ BTA_AG_FEAT_EXTERR | \
+ BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_CODEC | \
+ BTA_AG_FEAT_UNAT)
+#endif
+#else
+#ifndef BTC_HF_FEATURES
+#define BTC_HF_FEATURES ( BTA_AG_FEAT_ECNR | \
+ BTA_AG_FEAT_REJECT | \
+ BTA_AG_FEAT_ECS | \
+ BTA_AG_FEAT_EXTERR | \
+ BTA_AG_FEAT_VREC | \
+ BTA_AG_FEAT_INBAND | \
+ BTA_AG_FEAT_UNAT)
+#endif
+#endif
+
+/* wide band synchronous */
+#ifndef BTC_HF_WBS_PREFERRED
+#define BTC_HF_WBS_PREFERRED FALSE
+#endif
+BOOLEAN btc_conf_hf_force_wbs = BTC_HF_WBS_PREFERRED;
+
+#define CHECK_HF_INIT() do { \
+if (! hf_local_param[idx].btc_hf_cb.initialized) { \
+BTIF_TRACE_WARNING("CHECK_HF_INIT: %s: HF AG not initialized", __FUNCTION__);\
+return BT_STATUS_NOT_READY; \
+} \
+else\
+{\
+BTIF_TRACE_EVENT("CHECK_HF_INIT: %s", __FUNCTION__);\
+}\
+} while (0)
+
+#define CHECK_HF_SLC_CONNECTED() do { \
+if (! hf_local_param[idx].btc_hf_cb.initialized || \
+ hf_local_param[idx].btc_hf_cb.connection_state != ESP_HF_CONNECTION_STATE_SLC_CONNECTED) { \
+BTIF_TRACE_WARNING("CHECK_HF_INIT: %s: HF AG not initialized", __FUNCTION__);\
+return BT_STATUS_NOT_READY; \
+} \
+else\
+{\
+BTIF_TRACE_EVENT("CHECK_HF_INIT: %s", __FUNCTION__);\
+}\
+} while (0)
+
+
+#define clear_phone_state() \
+ hf_local_param[idx].btc_hf_cb.call_state = ESP_HF_CALL_STATUS_NO_CALLS; \
+ hf_local_param[idx].btc_hf_cb.call_setup_state = ESP_HF_CALL_SETUP_STATUS_IDLE;\
+ hf_local_param[idx].btc_hf_cb.num_active = 0; \
+ hf_local_param[idx].btc_hf_cb.num_held = 0;
+
+/************************************************************************************
+** Static Function
+************************************************************************************/
+static int btc_hf_idx_by_bdaddr(bt_bdaddr_t *bd_addr)
+{
+ for (int i = 0; i < btc_max_hf_clients; ++i) {
+ if ((bdcmp(bd_addr->address, hf_local_param[i].btc_hf_cb.connected_bda.address) == 0)
+ || bd_addr->address) {
+ return i;
+ }
+ }
+ return BTC_HF_INVALID_IDX;
+}
+
+static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ if (((hf_local_param[idx].btc_hf_cb.connection_state == ESP_HF_CONNECTION_STATE_CONNECTED) ||
+ (hf_local_param[idx].btc_hf_cb.connection_state == ESP_HF_CONNECTION_STATE_SLC_CONNECTED)) &&
+ ((bd_addr == NULL) || (bdcmp(bd_addr->address,hf_local_param[idx].btc_hf_cb.connected_bda.address) == 0))) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int btc_hf_latest_connected_idx(void)
+{
+ struct timespec now, conn_time_delta;
+ int latest_conn_idx = BTC_HF_INVALID_IDX;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ conn_time_delta.tv_sec = now.tv_sec;
+
+ for (int i = 0; i < btc_max_hf_clients; i++) {
+ if (hf_local_param[i].btc_hf_cb.connection_state == ESP_HF_CONNECTION_STATE_SLC_CONNECTED) {
+ if ((now.tv_sec - hf_local_param[i].btc_hf_cb.connected_timestamp.tv_sec) < conn_time_delta.tv_sec) {
+ conn_time_delta.tv_sec = now.tv_sec - hf_local_param[i].btc_hf_cb.connected_timestamp.tv_sec;
+ latest_conn_idx = i;
+ }
+ }
+ }
+ return latest_conn_idx;
+}
+
+/************************************************************************************
+** Cb and Evt
+************************************************************************************/
+static inline void btc_hf_cb_to_app(esp_hf_cb_event_t event, esp_hf_cb_param_t *param)
+{
+ esp_hf_cb_t btc_hf_callbacks = (esp_hf_cb_t)btc_profile_cb_get(BTC_PID_HF);
+ if (btc_hf_callbacks) {
+ btc_hf_callbacks(event, param);
+ }
+}
+
+static void send_indicator_update(UINT16 indicator, UINT16 value)
+{
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.ind.type = indicator;
+ ag_res.ind.value = value;
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
+}
+
+static void btc_hf_cind_evt(tBTA_AG_IND *ind)
+{
+ esp_hf_cb_param_t param;
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+
+ switch (ind->type) {
+ case BTA_AG_IND_CALL:
+ param.cind.call_status = ind->value;
+ break;
+ case BTA_AG_IND_CALLSETUP:
+ param.cind.call_setup_status = ind->value;
+ break;
+ case BTA_AG_IND_SERVICE:
+ param.cind.svc = ind->value;
+ break;
+ case BTA_AG_IND_SIGNAL:
+ param.cind.signal_strength = ind->value;
+ break;
+ case BTA_AG_IND_ROAM:
+ param.cind.roam = ind->value;
+ break;
+ case BTA_AG_IND_BATTCHG:
+ param.cind.battery_level = ind->value;
+ break;
+ case BTA_AG_IND_CALLHELD:
+ param.cind.call_held_status = ind->value;
+ break;
+ }
+ btc_hf_cb_to_app(ESP_HF_CIND_RESPONSE_EVT, ¶m);
+}
+
+static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *param)
+{
+ int param_len = 0;
+ /* TODO: BTA sends the union members and not tBTA_AG. If using param_len=sizeof(tBTA_AG), we get a crash on memcpy */
+ if (BTA_AG_REGISTER_EVT == event) {
+ param_len = sizeof(tBTA_AG_REGISTER);
+ }
+ else if (BTA_AG_OPEN_EVT == event) {
+ param_len = sizeof(tBTA_AG_OPEN);
+ }
+ else if ((BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event)) {
+ param_len = sizeof(tBTA_AG_HDR);
+ }
+ else if (BTA_AG_CONN_EVT == event) {
+ param_len = sizeof(tBTA_AG_CONN);
+ }
+ else if (param) {
+ param_len = sizeof(tBTA_AG_VAL);
+ }
+ btc_msg_t msg;
+ msg.sig = BTC_SIG_API_CB;
+ msg.pid = BTC_PID_HF;
+ msg.act = event;
+
+ /* Switch to BTC context */
+ bt_status_t status = btc_transfer_context(&msg, param, param_len, NULL);
+ /* catch any failed context transfers */
+ BTC_ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
+}
+
+/************************************************************************************
+** Data flow control & Service management.
+************************************************************************************/
+void btc_hf_reg_data_cb(esp_hf_incoming_data_cb_t recv, esp_hf_outgoing_data_cb_t send)
+{
+ hf_local_param[0].btc_hf_incoming_data_cb = recv;
+ hf_local_param[0].btc_hf_outgoing_data_cb = send;
+}
+
+void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len)
+{
+ int idx = 0;
+ // todo: critical section protection
+ if (hf_local_param[idx].btc_hf_incoming_data_cb) {
+ hf_local_param[idx].btc_hf_incoming_data_cb(data, len);
+ }
+}
+
+uint32_t btc_hf_outgoing_data_cb_to_app(uint8_t *data, uint32_t len)
+{
+ int idx = 0;
+ // todo: critical section protection
+ if (hf_local_param[idx].btc_hf_outgoing_data_cb) {
+ return hf_local_param[idx].btc_hf_outgoing_data_cb(data, len);
+ } else {
+ return 0;
+ }
+}
+
+bt_status_t btc_hf_execute_service(BOOLEAN b_enable)
+{
+ char * p_service_names[] = BTC_HF_SERVICE_NAMES;
+ int idx;
+ if (b_enable) {
+ /* Enable and register with BTA-AG */
+ BTA_AgEnable(BTA_AG_PARSE, bte_hf_evt);
+ for (idx = 0; idx < btc_max_hf_clients; idx++) {
+ BTA_AgRegister(BTC_HF_SERVICES, BTC_HF_SECURITY, BTC_HF_FEATURES, p_service_names, BTC_HF_ID_1);
+ }
+ } else {
+ /* De-register AG */
+ for (idx = 0; idx < btc_max_hf_clients; idx++) {
+ BTA_AgDeregister(hf_local_param[idx].btc_hf_cb.handle);
+ }
+ /* Disable AG */
+ BTA_AgDisable();
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+/************************************************************************************
+** BTC HFP AG API FUNCTION
+************************************************************************************/
+/************************************************************************************
+** Initialization and Connection Handle
+************************************************************************************/
+bt_status_t btc_hf_init(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ BTC_TRACE_DEBUG("%s - max_hf_clients=%d", __func__, btc_max_hf_clients);
+ /* Invoke the enable service API to the core to set the appropriate service_id
+ * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone)
+ * othwerwise only HSP is enabled (tablet)*/
+#if (defined(BTC_HF_SERVICES) && (BTC_HF_SERVICES & BTA_HFP_SERVICE_MASK))
+ btc_dm_enable_service(BTA_HFP_SERVICE_ID);
+#else
+ btc_dm_enable_service(BTA_HSP_SERVICE_ID);
+#endif
+ clear_phone_state();
+ memset(&hf_local_param[idx].btc_hf_cb, 0, sizeof(btc_hf_cb_t));
+ // custom initialization here
+ hf_local_param[idx].btc_hf_cb.initialized = true;
+// set audio path
+#if BTM_SCO_HCI_INCLUDED
+ uint8_t data_path = ESP_SCO_DATA_PATH_HCI;
+#else
+ uint8_t data_path = ESP_SCO_DATA_PATH_PCM;
+#endif
+ esp_bredr_sco_datapath_set(data_path);
+ return BT_STATUS_SUCCESS;
+}
+
+void btc_hf_deinit(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ BTC_TRACE_EVENT("%s", __FUNCTION__);
+ btc_dm_disable_service(BTA_HFP_SERVICE_ID);
+ hf_local_param[idx].btc_hf_cb.initialized = false;
+}
+
+static bt_status_t connect_init(bt_bdaddr_t *bd_addr, uint16_t uuid)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if (idx == btc_max_hf_clients) {
+ return BT_STATUS_BUSY;
+ }
+
+ if (!is_connected(bd_addr)) {
+ hf_local_param[idx].btc_hf_cb.connection_state = ESP_HF_CONNECTION_STATE_CONNECTING;
+ bdcpy(hf_local_param[idx].btc_hf_cb.connected_bda.address, bd_addr->address);
+ BTA_AgOpen(hf_local_param[idx].btc_hf_cb.handle, hf_local_param[idx].btc_hf_cb.connected_bda.address, BTC_HF_SECURITY, BTC_HF_SERVICES);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_BUSY;
+}
+bt_status_t btc_hf_connect(bt_bdaddr_t *bd_addr)
+{
+ return btc_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_init);
+}
+
+bt_status_t btc_hf_disconnect(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ BTA_AgClose(hf_local_param[idx].btc_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t btc_hf_connect_audio(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ BTA_AgAudioOpen(hf_local_param[idx].btc_hf_cb.handle);
+ /* Inform the application that the audio connection has been initiated successfully */
+ do {
+ esp_hf_cb_param_t param;
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTING;
+ memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
+ btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
+ } while (0);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+bt_status_t btc_hf_disconnect_audio(bt_bdaddr_t *bd_addr)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ BTA_AgAudioClose(hf_local_param[idx].btc_hf_cb.handle);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+/************************************************************************************
+** AT cmd Handle
+************************************************************************************/
+//AT+VRA
+static bt_status_t btc_hf_vra(bt_bdaddr_t *bd_addr, esp_hf_vr_state_t value)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ if (hf_local_param[idx].btc_hf_cb.peer_feat & BTA_AG_PEER_FEAT_VREC) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.state = value;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_BVRA_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ } else {
+ return BT_STATUS_UNSUPPORTED;
+ }
+ }
+ return BT_STATUS_NOT_READY;
+}
+
+static bt_status_t btc_hf_volume_control(bt_bdaddr_t *bd_addr, esp_hf_volume_type_t type, int volume)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ ag_res.num = volume;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, (type == ESP_HF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+// Pre-formatted AT response, typically in response to unknown AT cmd
+static bt_status_t btc_hf_unat_response(bt_bdaddr_t *bd_addr, const char *unat)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(NULL) && (idx != BTC_HF_INVALID_IDX))
+ {
+ tBTA_AG_RES_DATA ag_res;
+ /* Format the response and send */
+ memset(&ag_res, 0, sizeof(ag_res));
+ strncpy(ag_res.str, unat, BTA_AG_AT_MAX_LEN);
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+// +CMEE:<response>
+static bt_status_t btc_hf_cmee_response(bt_bdaddr_t *bd_addr, esp_hf_at_response_code_t response_code, esp_hf_cme_err_t error_code)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ if (response_code == ESP_HF_AT_RESPONSE_CODE_OK) {
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ } else {
+ ag_res.ok_flag = BTA_AG_OK_ERROR;
+ ag_res.errcode = error_code;
+ }
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+// +CIEV<...> for device status update
+static bt_status_t btc_hf_indchange_notification(bt_bdaddr_t *bd_addr,
+ esp_hf_call_status_t call_state,
+ esp_hf_call_setup_status_t call_setup_state,
+ esp_hf_network_state_t ntk_state, int signal)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if (is_connected(bd_addr)) {
+ /* Send all indicators to BTA.
+ * BTA will make sure no duplicates are sent out*/
+ send_indicator_update(BTA_AG_IND_CALL, call_state);
+ send_indicator_update(BTA_AG_IND_CALLSETUP, call_setup_state);
+ send_indicator_update(BTA_AG_IND_SERVICE, ntk_state);
+ send_indicator_update(BTA_AG_IND_SIGNAL, signal);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_SUCCESS;
+}
+
+//AT+CIND response
+static bt_status_t btc_hf_cind_response(bt_bdaddr_t *bd_addr,
+ esp_hf_call_setup_status_t call_status,
+ esp_hf_call_setup_status_t call_setup_status,
+ esp_hf_network_state_t ntk_state, int signal, esp_hf_service_type_t roam, int batt_lev,
+ esp_hf_call_held_status_t call_held_status)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_INIT();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof (ag_res));
+ sprintf(ag_res.str, "%d,%d,%d,%d,%d,%d,%d",
+ call_status, /* Call state*/
+ call_setup_status, /* Callsetup state */
+ ntk_state, /* network service */
+ signal, /* Signal strength */
+ roam, /* Roaming indicator */
+ batt_lev, /* Battery level */
+ call_held_status /* Callheld state */
+ );
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_CIND_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+//AT+COPS response
+static bt_status_t btc_hf_cops_response(bt_bdaddr_t *bd_addr, const char *name)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset (&ag_res, 0, sizeof (ag_res));
+ /* Format the response */
+ sprintf(ag_res.str, "0,0,\"%s\"", name);
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_COPS_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+//AT+CLCC response
+static bt_status_t btc_hf_clcc_response(bt_bdaddr_t *bd_addr, int index, esp_hf_current_call_direction_t dir,
+ esp_hf_current_call_status_t current_call_state,
+ esp_hf_current_call_mode_t mode, esp_hf_current_call_mpty_type_t mpty,
+ const char *number, esp_hf_call_addr_type_t type)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return BT_STATUS_FAIL;
+ }
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset (&ag_res, 0, sizeof (ag_res));
+ if (index == 0) {
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ } else {
+ BTC_TRACE_EVENT("clcc_response: [%d] dir: %d current_call_state: %d mode: %d number: %s type: %d",
+ index, dir, current_call_state, mode, number, type);
+ int loc = sprintf (ag_res.str, "%d,%d,%d,%d,%d", index, dir, current_call_state, mode, mpty);
+ if (number) {
+ if ((type == ESP_HF_CALL_ADDR_TYPE_INTERNATIONAL) && (*number != '+')) {
+ sprintf(&ag_res.str[loc], ",\"+%s\",%d", number, type);
+ } else {
+ sprintf(&ag_res.str[loc], ",\"%s\",%d", number, type);
+ }
+ }
+ }
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_CLCC_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+//AT+CNUM
+static bt_status_t btc_hf_cnum_response(bt_bdaddr_t *bd_addr, const char *number, esp_hf_subscriber_service_type_t type)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof (ag_res));
+ BTC_TRACE_EVENT("cnum_response: number = %s, type = %d", number, type);
+ if (number) {
+ sprintf(ag_res.str, ",\"%s\",%d",number, type);
+ } else {
+ sprintf(ag_res.str, ",\"\",%d",type);
+ }
+ ag_res.ok_flag = BTA_AG_OK_DONE;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_CNUM_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+//+BSIR
+static bt_status_t btc_hf_inband_ring(bt_bdaddr_t *bd_addr, esp_hf_in_band_ring_state_t state)
+{
+ int idx = btc_hf_idx_by_bdaddr(bd_addr);
+ CHECK_HF_SLC_CONNECTED();
+
+ if (is_connected(bd_addr) && (idx != BTC_HF_INVALID_IDX)) {
+ tBTA_AG_RES_DATA ag_res;
+ memset (&ag_res, 0, sizeof (ag_res));
+ ag_res.state = state;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_INBAND_RING_RES, &ag_res);
+ return BT_STATUS_SUCCESS;
+ }
+ return BT_STATUS_FAIL;
+}
+
+//Update phone status whether AG or HF act
+static bt_status_t btc_hf_phone_state_update(bt_bdaddr_t *bd_addr,int num_active, int num_held,
+ esp_hf_call_status_t call_state, esp_hf_call_setup_status_t call_setup_state,
+ char *number, esp_hf_call_addr_type_t type)
+{
+ tBTA_AG_RES res = 0xff;
+ tBTA_AG_RES_DATA ag_res;
+ bt_status_t status = BT_STATUS_SUCCESS;
+ BOOLEAN activeCallUpdated = FALSE;
+ int idx = btc_hf_idx_by_bdaddr(bd_addr), i;
+
+ /* hf_idx is index of connected HS that sent ATA/BLDN, otherwise index of latest connected HS */
+ if (hf_local_param->hf_idx != BTC_HF_INVALID_IDX) {
+ idx = hf_local_param->hf_idx;
+ } else {
+ idx = btc_hf_latest_connected_idx();
+ }
+
+ BTC_TRACE_DEBUG("phone_state_change: idx = %d", idx);
+ CHECK_HF_SLC_CONNECTED();
+ BTC_TRACE_DEBUG("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d] call =%s [prev: %s] call_setup=%s [prev: %s]",
+ num_active, hf_local_param[idx].btc_hf_cb.num_active,
+ num_held, hf_local_param[idx].btc_hf_cb.num_held,
+ dump_hf_call_state(call_state), dump_hf_call_state(hf_local_param[idx].btc_hf_cb.call_state),
+ dump_hf_call_setup_state(call_setup_state), dump_hf_call_setup_state(hf_local_param[idx].btc_hf_cb.call_setup_state));
+
+ /* If all indicators are 0, send end call and return */
+ if (num_active == 0 && num_held == 0 && call_state == ESP_HF_CALL_STATUS_NO_CALLS && call_setup_state == ESP_HF_CALL_SETUP_STATUS_IDLE) {
+ BTC_TRACE_DEBUG("%s: Phone on hook", __FUNCTION__);
+
+ /* Record call termination timestamp if there was an active/held call or call_setup_state > ESP_HF_CALL_SETUP_STATUS_IDLE */
+ if ((hf_local_param[idx].btc_hf_cb.call_state != ESP_HF_CALL_STATUS_NO_CALLS) ||
+ (hf_local_param[idx].btc_hf_cb.call_setup_state != ESP_HF_CALL_SETUP_STATUS_IDLE) ||
+ (hf_local_param[idx].btc_hf_cb.num_active) ||
+ (hf_local_param[idx].btc_hf_cb.num_held)) {
+ BTC_TRACE_DEBUG("%s: Record call termination timestamp", __FUNCTION__);
+ clock_gettime(CLOCK_MONOTONIC, &hf_local_param[0].btc_hf_cb.call_end_timestamp);
+ }
+ BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
+ hf_local_param->hf_idx = BTC_HF_INVALID_IDX;
+
+ /* If held call was present, reset that as well. */
+ if (hf_local_param[idx].btc_hf_cb.num_held) {
+ send_indicator_update(BTA_AG_IND_CALLHELD, 0);
+ }
+ goto update_call_states;
+ }
+
+ /* Phone state can change when:
+ * 1. An outgoing/incoming call was answered.
+ * 2. A held was resumed.
+ * 3. Without callsetup notifications, call became active. (HF Unit links in during an Active call.)
+ */
+
+ /* Handle case(3) here prior to call setup handling.*/
+ if (((num_active + num_held) > 0) &&
+ (hf_local_param[idx].btc_hf_cb.num_active == 0) &&
+ (hf_local_param[idx].btc_hf_cb.num_held == 0) &&
+ (hf_local_param[idx].btc_hf_cb.call_setup_state == ESP_HF_CALL_SETUP_STATUS_IDLE)) {
+ BTC_TRACE_DEBUG("%s: Active/Held call notification received without call setup update", __FUNCTION__);
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+ ag_res.audio_handle = hf_local_param[idx].btc_hf_cb.handle;
+
+ /* Addition callsetup with the Active call. */
+ if (call_setup_state != ESP_HF_CALL_SETUP_STATUS_IDLE) {
+ res = BTA_AG_MULTI_CALL_RES;
+ } else {
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ }
+ /* CIND response should have been updated. */
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+ /* Just open SCO conenction. */
+ BTA_AgAudioOpen(ag_res.audio_handle);
+ activeCallUpdated = TRUE;
+ }
+
+ /* Handle call_setup indicator change. */
+ if (call_setup_state != hf_local_param[idx].btc_hf_cb.call_setup_state) {
+ BTC_TRACE_DEBUG("%s: Call setup states changed. old: %s new: %s", __FUNCTION__,
+ dump_hf_call_setup_state(hf_local_param[idx].btc_hf_cb.call_setup_state),
+ dump_hf_call_setup_state(call_setup_state));
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ switch(call_setup_state)
+ {
+ case ESP_HF_CALL_SETUP_STATUS_IDLE:
+ {
+ switch(hf_local_param[idx].btc_hf_cb.call_setup_state)
+ {
+ case ESP_HF_CALL_SETUP_STATUS_INCOMING:
+ {
+ if (num_active > hf_local_param[idx].btc_hf_cb.num_active) {
+ res = BTA_AG_IN_CALL_CONN_RES;
+ ag_res.audio_handle = hf_local_param[idx].btc_hf_cb.handle;
+ } else if (num_held > hf_local_param[idx].btc_hf_cb.num_held) {
+ res = BTA_AG_IN_CALL_HELD_RES;
+ } else {
+ res = BTA_AG_CALL_CANCEL_RES;
+ }
+ break;
+ }
+
+ case ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING:
+ case ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING:
+ {
+ if (num_active > hf_local_param[idx].btc_hf_cb.num_active) {
+ res = BTA_AG_OUT_CALL_CONN_RES;
+ ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
+ } else {
+ res = BTA_AG_CALL_CANCEL_RES;
+ }
+ break;
+ }
+
+ default:
+ BTC_TRACE_ERROR("%s: Call setup state no change.", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ break;
+ }
+
+ case ESP_HF_CALL_SETUP_STATUS_INCOMING:
+ {
+ if (num_active || num_held) {
+ res = BTA_AG_CALL_WAIT_RES;
+ } else {
+ res = BTA_AG_IN_CALL_RES;
+ }
+
+ if (number) {
+ int loc = 0;
+ if ((type == ESP_HF_CALL_ADDR_TYPE_INTERNATIONAL) && (*number != '+')) {
+ loc = sprintf (ag_res.str, "\"+%s\"", number);
+ } else {
+ loc = sprintf (ag_res.str, "\"%s\"", number);
+ }
+ ag_res.num = type;
+ if (res == BTA_AG_CALL_WAIT_RES) {
+ sprintf(&ag_res.str[loc], ",%d", type);
+ }
+ }
+ break;
+ }
+
+ case ESP_HF_CALL_SETUP_STATUS_OUTGOING_DIALING:
+ {
+ if (!(num_active + num_held)) {
+ ag_res.audio_handle = hf_local_param[idx].btc_hf_cb.handle;
+ }
+ res = BTA_AG_OUT_CALL_ORIG_RES;
+ break;
+ }
+
+ case ESP_HF_CALL_SETUP_STATUS_OUTGOING_ALERTING:
+ {
+ if ((hf_local_param[idx].btc_hf_cb.call_setup_state == ESP_HF_CALL_SETUP_STATUS_IDLE) &&
+ !(num_active + num_held)) {
+ ag_res.audio_handle = hf_local_param[idx].btc_hf_cb.handle;
+ /* Force SCO setup here.*/
+ BTA_AgAudioOpen(ag_res.audio_handle);
+ }
+ res = BTA_AG_OUT_CALL_ALERT_RES;
+ break;
+ }
+
+ default:
+ BTC_TRACE_ERROR("%s: Incorrect new ringing call state", __FUNCTION__);
+ status = BT_STATUS_PARM_INVALID;
+ break;
+ }
+ BTC_TRACE_DEBUG("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
+ if (res) {
+ BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
+ }
+ /* If call setup is idle, we have already updated call indicator, jump out */
+ if (call_setup_state == ESP_HF_CALL_SETUP_STATUS_IDLE) {
+ /* Check & Update call_held_state */
+ if ((num_held > 0) && (num_active > 0))
+ send_indicator_update(BTA_AG_IND_CALLHELD, ESP_HF_CALL_HELD_STATUS_HELD_AND_ACTIVE);
+ goto update_call_states;
+ }
+ }
+
+ memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
+
+ /* Handle call_state indicator change. */
+ if (!activeCallUpdated &&
+ ((num_active + num_held) != (hf_local_param[idx].btc_hf_cb.num_active + hf_local_param[idx].btc_hf_cb.num_held))) {
+ BTC_TRACE_DEBUG("%s: Active call states changed. old: %d new: %d", __FUNCTION__, hf_local_param[idx].btc_hf_cb.num_active, num_active);
+ send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
+ }
+
+ /* Handle call_held_state indicator change. */
+ if (num_held != hf_local_param[idx].btc_hf_cb.num_held ||
+ ((num_active == 0) && ((num_held + hf_local_param[idx].btc_hf_cb.num_held) > 1))) {
+ BTC_TRACE_DEBUG("%s: Held call states changed. old: %d new: %d", __FUNCTION__, hf_local_param[idx].btc_hf_cb.num_held, num_held);
+ send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
+ }
+
+ /* Handle Call Active/Held Swap indicator update.*/
+ if ((call_setup_state == hf_local_param[idx].btc_hf_cb.call_setup_state) &&
+ (num_active) &&
+ (num_held) &&
+ (num_active == hf_local_param[idx].btc_hf_cb.num_active) &&
+ (num_held == hf_local_param[idx].btc_hf_cb.num_held)) {
+ BTC_TRACE_DEBUG("%s: Calls swapped", __FUNCTION__);
+ send_indicator_update(BTA_AG_IND_CALLHELD, 1);
+ }
+
+update_call_states:
+ for (i = 0; i < btc_max_hf_clients; i++) {
+ hf_local_param[i].btc_hf_cb.num_active = num_active;
+ hf_local_param[i].btc_hf_cb.num_held = num_held;
+ hf_local_param[i].btc_hf_cb.call_state = call_state;
+ hf_local_param[i].btc_hf_cb.call_setup_state = call_setup_state;
+ }
+ return status;
+}
+
+/************************************************************************************
+** Memory malloc and release
+************************************************************************************/
+void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
+{
+ btc_hf_args_t *dst = (btc_hf_args_t *) p_dest;
+ btc_hf_args_t *src = (btc_hf_args_t *) p_src;
+
+ switch (msg->act) {
+ case BTC_HF_UNAT_RESPONSE_EVT:
+ {
+ dst->unat_rep.unat = (char *)osi_malloc(strlen(src->unat_rep.unat)+1);
+ if(dst->unat_rep.unat) {
+ memcpy(dst->unat_rep.unat, src->unat_rep.unat, strlen(src->unat_rep.unat)+1);
+ } else if (strlen(src->unat_rep.unat) == 0) {
+ BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
+ } else {
+ BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+ }
+ break;
+ }
+
+ case BTC_HF_COPS_RESPONSE_EVT:
+ {
+ dst->cops_rep.name = (char *)osi_malloc(strlen(src->cops_rep.name)+1);
+ if(dst->cops_rep.name) {
+ memcpy(dst->cops_rep.name, src->cops_rep.name, strlen(src->cops_rep.name)+1);
+ } else if (strlen(src->cops_rep.name) == 0) {
+ BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
+ } else {
+ BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+ }
+ break;
+ }
+
+ case BTC_HF_CLCC_RESPONSE_EVT:
+ {
+ dst->clcc_rep.number = (char *)osi_malloc(strlen(src->clcc_rep.number)+1);
+ if(dst->clcc_rep.number) {
+ memcpy(dst->clcc_rep.number, src->clcc_rep.number, strlen(src->clcc_rep.number)+1);
+ } else if (strlen(src->clcc_rep.number) == 0) {
+ BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
+ } else {
+ BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+ }
+ break;
+ }
+
+ case BTC_HF_CNUM_RESPONSE_EVT:
+ {
+ dst->cnum_rep.number = (char *)osi_malloc(strlen(src->cnum_rep.number)+1);
+ if(dst->cnum_rep.number) {
+ memcpy(dst->cnum_rep.number, src->cnum_rep.number, strlen(src->cnum_rep.number)+1);
+ } else if (strlen(src->cnum_rep.number) == 0) {
+ BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
+ } else {
+ BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+ }
+ break;
+ }
+
+ case BTC_HF_AC_INCALL_EVT:
+ case BTC_HF_RJ_INCALL_EVT:
+ case BTC_HF_OUT_CALL_EVT:
+ case BTC_HF_END_CALL_EVT:
+ {
+ dst->phone.number = (char *)osi_malloc(strlen(src->phone.number)+1);
+ if(dst->phone.number) {
+ memcpy(dst->phone.number, src->phone.number, strlen(src->phone.number)+1);
+ } else if (strlen(src->phone.number) == 0) {
+ BTC_TRACE_DEBUG("%s %d no mem\n", __func__, msg->act);
+ } else {
+ BTC_TRACE_ERROR("%s %d osi_malloc failed\n", __func__, msg->act);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void btc_hf_arg_deep_free(btc_msg_t *msg)
+{
+ btc_hf_args_t *arg = (btc_hf_args_t *)msg->arg;
+
+ switch (msg->act) {
+ case BTC_HF_UNAT_RESPONSE_EVT:
+ {
+ if (arg->unat_rep.unat) {
+ osi_free(arg->unat_rep.unat);
+ }
+ break;
+ }
+
+ case BTC_HF_COPS_RESPONSE_EVT:
+ {
+ if (arg->cops_rep.name) {
+ osi_free(arg->cops_rep.name);
+ }
+ break;
+ }
+
+ case BTC_HF_CLCC_RESPONSE_EVT:
+ {
+ if (arg->clcc_rep.number) {
+ osi_free(arg->clcc_rep.number);
+ }
+ break;
+ }
+
+ case BTC_HF_CNUM_RESPONSE_EVT:
+ {
+ if (arg->cnum_rep.number) {
+ osi_free(arg->cnum_rep.number);
+ }
+ break;
+ }
+
+ case BTC_HF_AC_INCALL_EVT:
+ case BTC_HF_RJ_INCALL_EVT:
+ case BTC_HF_OUT_CALL_EVT:
+ case BTC_HF_END_CALL_EVT:
+ {
+ if (arg->phone.number) {
+ osi_free(arg->phone.number);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+/************************************************************************************
+** Handler Functions (handle the cmd from app)
+************************************************************************************/
+void btc_hf_call_handler(btc_msg_t *msg)
+{
+ btc_hf_args_t *arg = (btc_hf_args_t *)(msg->arg);
+
+ switch (msg->act) {
+ case BTC_HF_INIT_EVT:
+ {
+ btc_hf_init(&arg->init);
+ break;
+ }
+
+ case BTC_HF_DEINIT_EVT:
+ {
+ btc_hf_deinit(&arg->deinit);
+ break;
+ }
+
+ case BTC_HF_CONNECT_EVT:
+ {
+ btc_hf_connect(&arg->connect);
+ break;
+ }
+
+ case BTC_HF_DISCONNECT_EVT:
+ {
+ btc_hf_disconnect(&arg->disconnect);
+ break;
+ }
+
+ case BTC_HF_CONNECT_AUDIO_EVT:
+ {
+ btc_hf_connect_audio(&arg->connect_audio);
+ break;
+ }
+
+ case BTC_HF_DISCONNECT_AUDIO_EVT:
+ {
+ btc_hf_disconnect_audio(&arg->disconnect_audio);
+ break;
+ }
+
+ case BTC_HF_VRA_EVT:
+ {
+ btc_hf_vra(&arg->vra_rep.remote_addr, arg->vra_rep.value);
+ if (arg->vra_rep.value) {
+ btc_hf_connect_audio(&arg->vra_rep.remote_addr);
+ } else {
+ btc_hf_disconnect_audio(&arg->vra_rep.remote_addr);
+ }
+ break;
+ }
+
+ case BTC_HF_VOLUME_CONTROL_EVT:
+ {
+ btc_hf_volume_control(&arg->volcon.remote_addr, arg->volcon.target_type, arg->volcon.volume);
+ break;
+ }
+
+ case BTC_HF_UNAT_RESPONSE_EVT:
+ {
+ btc_hf_unat_response(&arg->unat_rep.remote_addr, arg->unat_rep.unat);
+ }
+
+ case BTC_HF_CME_ERR_EVT:
+ {
+ btc_hf_cmee_response(&arg->ext_at.remote_addr, arg->ext_at.response_code, arg->ext_at.error_code);
+ break;
+ }
+
+ case BTC_HF_IND_NOTIFICATION_EVT:
+ {
+ btc_hf_indchange_notification(&arg->ind_change.remote_addr,
+ arg->ind_change.call_state, arg->ind_change.call_setup_state,
+ arg->ind_change.ntk_state, arg->ind_change.signal);
+ break;
+ }
+
+ case BTC_HF_CIND_RESPONSE_EVT:
+ {
+ btc_hf_cind_response(&arg->cind_rep.remote_addr,
+ arg->cind_rep.call_state, arg->cind_rep.call_setup_state,
+ arg->cind_rep.ntk_state, arg->cind_rep.signal, arg->cind_rep.roam, arg->cind_rep.batt_lev,
+ arg->cind_rep.call_held_state);
+ break;
+ }
+
+ case BTC_HF_COPS_RESPONSE_EVT:
+ {
+ btc_hf_cops_response(&arg->cops_rep.remote_addr, arg->cops_rep.name);
+ break;
+ }
+
+ case BTC_HF_CLCC_RESPONSE_EVT:
+ {
+ btc_hf_clcc_response(&arg->clcc_rep.remote_addr, arg->clcc_rep.index,
+ arg->clcc_rep.dir, arg->clcc_rep.current_call_state,
+ arg->clcc_rep.mode, arg->clcc_rep.mpty, arg->clcc_rep.number, arg->clcc_rep.type);
+ break;
+ }
+
+ case BTC_HF_CNUM_RESPONSE_EVT:
+ {
+ btc_hf_cnum_response(&arg->cnum_rep.remote_addr, arg->cnum_rep.number, arg->cnum_rep.type);
+ break;
+ }
+
+ case BTC_HF_INBAND_RING_EVT:
+ {
+ btc_hf_inband_ring(&arg->bsir.remote_addr, arg->bsir.state);
+ break;
+ }
+
+ case BTC_HF_AC_INCALL_EVT:
+ {
+ btc_hf_phone_state_update(&arg->phone.remote_addr, arg->phone.num_active, arg->phone.num_held,
+ arg->phone.call_state, arg->phone.call_setup_state, arg->phone.number,
+ arg->phone.call_addr_type);
+ break;
+ }
+
+ case BTC_HF_RJ_INCALL_EVT:
+ {
+ btc_hf_phone_state_update(&arg->phone.remote_addr, arg->phone.num_active, arg->phone.num_held,
+ arg->phone.call_state, arg->phone.call_setup_state, arg->phone.number,
+ arg->phone.call_addr_type);
+ btc_hf_disconnect_audio(&arg->phone.remote_addr);
+ break;
+ }
+
+ case BTC_HF_OUT_CALL_EVT:
+ {
+ btc_hf_connect_audio(&arg->phone.remote_addr);
+ btc_hf_phone_state_update(&arg->phone.remote_addr, arg->phone.num_active, arg->phone.num_held,
+ arg->phone.call_state, arg->phone.call_setup_state, arg->phone.number,
+ arg->phone.call_addr_type);
+ break;
+ }
+
+ case BTC_HF_END_CALL_EVT:
+ {
+ btc_hf_phone_state_update(&arg->phone.remote_addr, arg->phone.num_active, arg->phone.num_held,
+ arg->phone.call_state, arg->phone.call_setup_state, arg->phone.number,
+ arg->phone.call_addr_type);
+ btc_hf_disconnect_audio(&arg->phone.remote_addr);
+ break;
+ }
+
+ case BTC_HF_REGISTER_DATA_CALLBACK_EVT:
+ {
+ btc_hf_reg_data_cb(arg->reg_data_cb.recv, arg->reg_data_cb.send);
+ }
+ break;
+
+ default:
+ BTC_TRACE_WARNING("%s : unhandled event: %d\n", __FUNCTION__, msg->act);
+ }
+ btc_hf_arg_deep_free(msg);
+}
+
+void btc_hf_cb_handler(btc_msg_t *msg)
+{
+ uint16_t event = msg->act;
+ tBTA_AG *p_data = (tBTA_AG *)msg->arg;
+ esp_hf_cb_param_t param;
+ bdstr_t bdstr;
+ int idx;
+
+ if (p_data == NULL) {
+ idx = BTC_HF_INVALID_IDX;
+ } else {
+ idx = p_data->hdr.handle - 1;
+ }
+
+ BTC_TRACE_DEBUG("%s: event = %s", __FUNCTION__, dump_hf_event(event));
+ if ((idx < 0) || (idx >= BTC_HF_NUM_CB)) {
+ BTC_TRACE_ERROR("%s: Invalid index %d", __FUNCTION__, idx);
+ return;
+ }
+
+ switch (event) {
+ case BTA_AG_ENABLE_EVT:
+ case BTA_AG_DISABLE_EVT:
+ break;
+
+ case BTA_AG_REGISTER_EVT:
+ {
+ hf_local_param[idx].btc_hf_cb.handle = p_data->reg.hdr.handle;
+ BTC_TRACE_DEBUG("%s: BTA_AG_REGISTER_EVT," "hf_local_param[%d].btc_hf_cb.handle = %d",
+ __FUNCTION__, idx, hf_local_param[idx].btc_hf_cb.handle);
+ break;
+ }
+
+ case BTA_AG_OPEN_EVT:
+ {
+ if (p_data->open.status == BTA_AG_SUCCESS)
+ {
+ bdcpy(hf_local_param[idx].btc_hf_cb.connected_bda.address, p_data->open.bd_addr);
+ hf_local_param[idx].btc_hf_cb.connection_state = ESP_HF_CONNECTION_STATE_CONNECTED;
+ hf_local_param[idx].btc_hf_cb.peer_feat = 0;
+ hf_local_param[idx].btc_hf_cb.chld_feat = 0;
+ //clear_phone_state();
+ } else if (hf_local_param[idx].btc_hf_cb.connection_state == ESP_HF_CONNECTION_STATE_CONNECTING) {
+ hf_local_param[idx].btc_hf_cb.connection_state = ESP_HF_CONNECTION_STATE_DISCONNECTED;
+ } else {
+ BTC_TRACE_WARNING("%s: AG open failed, but another device connected. status=%d state=%d connected device=%s", __FUNCTION__,
+ p_data->open.status, hf_local_param[idx].btc_hf_cb.connection_state,
+ bdaddr_to_string(&hf_local_param[idx].btc_hf_cb.connected_bda, bdstr, sizeof(bdstr)));
+ break;
+ }
+
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ memcpy(param.conn_stat.remote_bda, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
+ param.conn_stat.state = hf_local_param[idx].btc_hf_cb.connection_state;
+ param.conn_stat.peer_feat = 0;
+ param.conn_stat.chld_feat = 0;
+ btc_hf_cb_to_app(ESP_HF_CONNECTION_STATE_EVT, ¶m);
+ } while (0);
+
+ if (hf_local_param[idx].btc_hf_cb.connection_state == ESP_HF_CONNECTION_STATE_DISCONNECTED)
+ bdsetany(hf_local_param[idx].btc_hf_cb.connected_bda.address);
+
+ if (p_data->open.status != BTA_AG_SUCCESS)
+ btc_queue_advance();
+ break;
+ }
+
+ case BTA_AG_CONN_EVT:
+ {
+ clock_gettime(CLOCK_MONOTONIC, &(hf_local_param[idx].btc_hf_cb.connected_timestamp));
+ BTC_TRACE_DEBUG("%s: BTA_AG_CONN_EVT, idx = %d ", __FUNCTION__, idx);
+ hf_local_param[idx].btc_hf_cb.peer_feat = p_data->conn.peer_feat;
+ hf_local_param[idx].btc_hf_cb.chld_feat = p_data->conn.chld_feat;
+ hf_local_param[idx].btc_hf_cb.connection_state = ESP_HF_CONNECTION_STATE_SLC_CONNECTED;
+
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.conn_stat.state = hf_local_param[idx].btc_hf_cb.connection_state;
+ param.conn_stat.peer_feat = hf_local_param[idx].btc_hf_cb.peer_feat;
+ param.conn_stat.chld_feat = hf_local_param[idx].btc_hf_cb.chld_feat;
+ memcpy(param.conn_stat.remote_bda, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
+ btc_hf_cb_to_app(ESP_HF_CONNECTION_STATE_EVT, ¶m);
+ } while(0);
+ hf_local_param[idx].hf_idx = btc_hf_latest_connected_idx();
+ btc_queue_advance();
+ break;
+ }
+
+ case BTA_AG_CLOSE_EVT:
+ {
+ hf_local_param[idx].btc_hf_cb.connected_timestamp.tv_sec = 0;
+ hf_local_param[idx].btc_hf_cb.connection_state = ESP_HF_CONNECTION_STATE_DISCONNECTED;
+ BTC_TRACE_DEBUG("%s: BTA_AG_CLOSE_EVT," "hf_local_param[%d].btc_hf_cb.handle = %d", __FUNCTION__,
+ idx, hf_local_param[idx].btc_hf_cb.handle);
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.conn_stat.state = ESP_HF_CONNECTION_STATE_DISCONNECTED;
+ param.conn_stat.peer_feat = 0;
+ param.conn_stat.chld_feat = 0;
+ memcpy(param.conn_stat.remote_bda, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
+ btc_hf_cb_to_app(ESP_HF_CONNECTION_STATE_EVT, ¶m);
+ } while(0);
+ bdsetany(hf_local_param[idx].btc_hf_cb.connected_bda.address);
+ clear_phone_state();
+ hf_local_param[idx].hf_idx = btc_hf_latest_connected_idx();
+ btc_queue_advance();
+ break;
+ }
+
+ case BTA_AG_AUDIO_OPEN_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.audio_stat.state = ESP_HF_AUDIO_STATE_CONNECTED;
+ memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda,sizeof(esp_bd_addr_t));
+ btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
+ } while(0);
+ break;
+ }
+
+ case BTA_AG_AUDIO_CLOSE_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.audio_stat.state = ESP_HF_AUDIO_STATE_DISCONNECTED;
+ memcpy(param.audio_stat.remote_addr, &hf_local_param[idx].btc_hf_cb.connected_bda, sizeof(esp_bd_addr_t));
+ btc_hf_cb_to_app(ESP_HF_AUDIO_STATE_EVT, ¶m);
+ } while(0);
+ break;
+ }
+
+ case BTA_AG_AT_BVRA_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.vra_rep.value = p_data->val.num;
+ btc_hf_cb_to_app(ESP_HF_BVRA_EVT, ¶m);
+ } while (0);
+ break;
+ }
+
+ case BTA_AG_SPK_EVT:
+ case BTA_AG_MIC_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.volume_control.type = (event == BTA_AG_SPK_EVT) ? ESP_HF_VOLUME_CONTROL_TARGET_SPK : ESP_HF_VOLUME_CONTROL_TARGET_MIC;
+ param.volume_control.volume = p_data->val.num;
+ btc_hf_cb_to_app(ESP_HF_VOLUME_CONTROL_EVT, ¶m);
+ } while (0);
+ break;
+ }
+
+ case BTA_AG_AT_UNAT_EVT:
+ {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.unat_rep.unat = p_data->val.str;
+ btc_hf_cb_to_app(ESP_HF_UNAT_RESPONSE_EVT, ¶m);
+ break;
+ }
+
+ case BTA_AG_AT_CBC_EVT:
+ case BTA_AG_AT_CIND_EVT:
+ {
+ btc_hf_cind_evt(&p_data->ind);
+ break;
+ }
+
+ case BTA_AG_AT_COPS_EVT:
+ {
+ btc_hf_cb_to_app(ESP_HF_COPS_RESPONSE_EVT, NULL);
+ break;
+ }
+
+ case BTA_AG_AT_CLCC_EVT:
+ {
+ btc_hf_cb_to_app(ESP_HF_CLCC_RESPONSE_EVT, NULL);
+ break;
+ }
+
+ case BTA_AG_AT_CNUM_EVT:
+ {
+ btc_hf_cb_to_app(ESP_HF_CNUM_RESPONSE_EVT, NULL);
+ break;
+ }
+
+ case BTA_AG_AT_VTS_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.vts_rep.code = p_data->val.str;
+ btc_hf_cb_to_app(ESP_HF_VTS_RESPONSE_EVT, ¶m);
+ } while(0);
+ break;
+ }
+
+ case BTA_AG_AT_NREC_EVT:
+ {
+ do {
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.nrec.state = p_data->val.num;
+ btc_hf_cb_to_app(ESP_HF_NREC_RESPONSE_EVT, ¶m);
+ } while(0);
+ break;
+ }
+
+ case BTA_AG_AT_A_EVT:
+ {
+ btc_hf_cb_to_app(ESP_HF_ATA_RESPONSE_EVT, NULL);
+ break;
+ }
+
+ case BTA_AG_AT_CHUP_EVT:
+ {
+ btc_hf_cb_to_app(ESP_HF_CHUP_RESPONSE_EVT, NULL);
+ break;
+ }
+
+ case BTA_AG_AT_BLDN_EVT:
+ case BTA_AG_AT_D_EVT:
+ {
+ do {
+ if (event == BTA_AG_AT_D_EVT && p_data->val.str) { // dial_number_or_memory
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.out_call.num_or_loc = osi_malloc((strlen(p_data->val.str) + 1) * sizeof(char));
+ sprintf(param.out_call.num_or_loc, p_data->val.str);
+ btc_hf_cb_to_app(ESP_HF_DIAL_EVT, ¶m);
+ send_indicator_update(BTA_AG_IND_CALLSETUP,BTA_AG_CALLSETUP_OUTGOING);
+ osi_free(param.out_call.num_or_loc);
+ } else if (event == BTA_AG_AT_BLDN_EVT) { //dial_last
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ btc_hf_cb_to_app(ESP_HF_DIAL_EVT, ¶m);
+ }
+ } while(0);
+ break;
+ }
+
+ case BTA_AG_AT_BINP_EVT:
+ case BTA_AG_AT_BTRH_EVT:
+ {
+ tBTA_AG_RES_DATA ag_res;
+ memset(&ag_res, 0, sizeof(ag_res));
+ ag_res.ok_flag = BTA_AG_OK_ERROR;
+ ag_res.errcode = BTA_AG_ERR_OP_NOT_SUPPORTED;
+ BTA_AgResult(hf_local_param[idx].btc_hf_cb.handle, BTA_AG_UNAT_RES, &ag_res);
+ break;
+ }
+
+ case BTA_AG_AT_BAC_EVT:
+ {
+ BTC_TRACE_DEBUG("AG Bitmap of peer-codecs %d", p_data->val.num);
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.codec.mode = p_data->val.num;
+ btc_hf_cb_to_app(ESP_HF_BAC_RESPONSE_EVT, ¶m);
+ break;
+ }
+
+#if (BTM_WBS_INCLUDED == TRUE )
+ case BTA_AG_WBS_EVT:
+ {
+ BTC_TRACE_DEBUG("BTA_AG_WBS_EVT Set codec status %d codec %d 1=CVSD 2=MSBC", p_data->val.hdr.status, p_data->val.num);
+ memset(¶m, 0, sizeof(esp_hf_cb_param_t));
+ param.codec.mode = p_data->val.num;
+ if(p_data->val.num == BTA_AG_CODEC_CVSD) {
+ btc_hf_cb_to_app(ESP_HF_BCS_RESPONSE_EVT, ¶m);
+ } else if(p_data->val.num == BTA_AG_CODEC_MSBC) {
+ btc_hf_cb_to_app(ESP_HF_BCS_RESPONSE_EVT, ¶m);
+ } else {
+ btc_hf_cb_to_app(ESP_HF_BCS_RESPONSE_EVT, ¶m);
+ }
+ break;
+ }
+#endif
+
+#if (BTM_WBS_INCLUDED == TRUE)
+ /* If the peer supports mSBC and the BTC prefferred codec is also mSBC, then
+ ** we should set the BTA AG Codec to mSBC. This would trigger a +BCS to mSBC at the time
+ ** of SCO connection establishment */
+ if ((btc_conf_hf_force_wbs == TRUE) && (p_data->val.num & BTA_AG_CODEC_MSBC)) {
+ BTC_TRACE_EVENT("%s btc_hf override-Preferred Codec to MSBC", __FUNCTION__);
+ BTA_AgSetCodec(hf_local_param[idx].btc_hf_cb.handle,BTA_AG_CODEC_MSBC);
+ }
+ else {
+ BTC_TRACE_EVENT("%s btif_hf override-Preferred Codec to CVSD", __FUNCTION__);
+ BTA_AgSetCodec(hf_local_param[idx].btc_hf_cb.handle,BTA_AG_CODEC_CVSD);
+ }
+#endif
+ break;
+ case BTA_AG_AT_BCS_EVT:
+ BTC_TRACE_DEBUG("AG final seleded codec is %d 1=CVSD 2=MSBC", p_data->val.num);
+ /* no ESP_HF_WBS_NONE case, becuase HF 1.6 supported device can send BCS */
+ btc_hf_cb_to_app(ESP_HF_BCS_RESPONSE_EVT, ¶m);
+ break;
+ default:
+ BTC_TRACE_WARNING("%s: Unhandled event: %d", __FUNCTION__, event);
+ break;
+ }
+}
+#endif // #if (BTC_HF_INCLUDED == TRUE)
\ No newline at end of file
--- /dev/null
+// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
+//
+// 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: btc_hf_ag.h
+ *
+ * Description: Main API header file for all BTC HF AG functions accessed
+ * from internal stack.
+ *
+ *******************************************************************************/
+
+#ifndef __BTC_HF_AG_H__
+#define __BTC_HF_AG_H__
+
+#include "common/bt_target.h"
+#include "btc/btc_task.h"
+#include "btc/btc_common.h"
+#include "bta/bta_ag_api.h"
+#include "esp_hf_ag_api.h"
+
+
+#if (BTC_HF_INCLUDED == TRUE)
+
+/*******************************************************************************
+** Type Defs
+********************************************************************************/
+/* btc_hf_act_t */
+typedef enum
+{
+ //INIT
+ BTC_HF_INIT_EVT,
+ BTC_HF_DEINIT_EVT,
+ BTC_HF_CONNECT_EVT,
+ BTC_HF_DISCONNECT_EVT,
+ BTC_HF_CONNECT_AUDIO_EVT,
+ BTC_HF_DISCONNECT_AUDIO_EVT,
+ BTC_HF_VRA_EVT,
+ BTC_HF_VOLUME_CONTROL_EVT,
+ //AT_RESPONSE
+ BTC_HF_UNAT_RESPONSE_EVT,
+ BTC_HF_CME_ERR_EVT,
+ BTC_HF_IND_NOTIFICATION_EVT,
+ BTC_HF_CIND_RESPONSE_EVT,
+ BTC_HF_COPS_RESPONSE_EVT,
+ BTC_HF_CLCC_RESPONSE_EVT,
+ BTC_HF_CNUM_RESPONSE_EVT,
+ BTC_HF_INBAND_RING_EVT,
+ //CALL_HANDLE
+ BTC_HF_AC_INCALL_EVT,
+ BTC_HF_RJ_INCALL_EVT,
+ BTC_HF_OUT_CALL_EVT,
+ BTC_HF_END_CALL_EVT,
+ //REG
+ BTC_HF_REGISTER_DATA_CALLBACK_EVT
+} btc_hf_act_t;
+
+/* btc_hf_args_t */
+typedef union
+{
+ // BTC_HF_INIT_EVT
+ bt_bdaddr_t init;
+
+ //BTC_HF_DEINIT_EVT
+ bt_bdaddr_t deinit;
+
+ // BTC_HF_CONNECT_EVT
+ bt_bdaddr_t connect;
+
+ // BTC_HF_DISCONNECT_EVT
+ bt_bdaddr_t disconnect;
+
+ // BTC_HF_CONNECT_AUDIO_EVT
+ bt_bdaddr_t connect_audio;
+
+ // BTC_HF_DISCONNECT_AUDIO_EVT
+ bt_bdaddr_t disconnect_audio;
+
+ //BTC_HF_VRA_EVT
+ struct vra_param {
+ bt_bdaddr_t remote_addr;
+ esp_hf_vr_state_t value;
+ } vra_rep;
+
+ // BTC_HF_VOLUME_CONTROL_EVT
+ struct volcon_args {
+ bt_bdaddr_t remote_addr;
+ esp_hf_volume_control_target_t target_type;
+ int volume;
+ } volcon;
+
+ //BTC_HF_UNAT_RESPONSE_EVT
+ struct unat_param {
+ bt_bdaddr_t remote_addr;
+ char *unat;
+ } unat_rep;
+
+ //BTC_HF_CME_ERR_EVT
+ struct at_ok_err_args {
+ bt_bdaddr_t remote_addr;
+ esp_hf_at_response_code_t response_code;
+ esp_hf_cme_err_t error_code;
+ } ext_at;
+
+ // BTC_HF_IND_NOTIFICATION_EVT
+ struct indchange_status {
+ bt_bdaddr_t remote_addr;
+ esp_hf_call_status_t call_state;
+ esp_hf_call_setup_status_t call_setup_state;
+ esp_hf_network_state_t ntk_state;
+ int signal;
+ } ind_change;
+
+ //BTC_HF_CIND_RESPONSE_EVT
+ struct cind_args {
+ bt_bdaddr_t remote_addr;
+ esp_hf_call_status_t call_state;
+ esp_hf_call_setup_status_t call_setup_state;
+ esp_hf_network_state_t ntk_state;
+ int signal;
+ esp_hf_roaming_status_t roam;
+ int batt_lev;
+ esp_hf_call_held_status_t call_held_state;
+ } cind_rep;
+
+ //BTC_HF_COPS_RESPONSE_EVT
+ struct cops_args {
+ bt_bdaddr_t remote_addr;
+ char *name;
+ } cops_rep;
+
+ // BTC_HF_CLCC_RESPONSE_EVT
+ struct clcc_args {
+ bt_bdaddr_t remote_addr;
+ int index;
+ esp_hf_current_call_direction_t dir;
+ esp_hf_current_call_status_t current_call_state;
+ esp_hf_current_call_mode_t mode;
+ esp_hf_current_call_mpty_type_t mpty;
+ char *number;
+ esp_hf_call_addr_type_t type;
+ } clcc_rep;
+
+ // BTC_HF_CNUM_RESPONSE_EVT
+ struct cnum_args {
+ bt_bdaddr_t remote_addr;
+ char *number;
+ esp_hf_subscriber_service_type_t type;
+ } cnum_rep;
+
+ //BTC_HF_NREC_RESPONSE_EVT
+ bt_bdaddr_t nrec_rep;
+
+ //BTC_HF_VTC_RESPONSE_EVT
+ struct bts_args {
+ bt_bdaddr_t remote_addr;
+ char *code;
+ } vts_rep;
+
+ //BTC_HF_INBAND_RING_EVT
+ struct bsir_args {
+ bt_bdaddr_t remote_addr;
+ esp_hf_in_band_ring_state_t state;
+ } bsir;
+
+ // BTC_HF_AC_INCALL_EVT
+ // BTC_HF_RJ_INCALL_EVT
+ // BTC_HF_OUT_CALL_EVT
+ // BTC_HF_END_CALL_EVT
+ struct phone_args {
+ bt_bdaddr_t remote_addr;
+ int num_active;
+ int num_held;
+ esp_hf_call_status_t call_state;
+ esp_hf_call_setup_status_t call_setup_state;
+ char *number;
+ esp_hf_call_addr_type_t call_addr_type;
+ } phone;
+
+ // BTC_HF_REGISTER_DATA_CALLBACK_EVT
+ struct reg_data_callback {
+ esp_hf_incoming_data_cb_t recv;
+ esp_hf_outgoing_data_cb_t send;
+ } reg_data_cb;
+
+} btc_hf_args_t;
+
+/************************************************************************************
+** Local definitions
+************************************************************************************/
+/* Number of BTC-HF-AG control blocks */
+#define BTC_HF_NUM_CB 1
+
+/* Handsfree AG app ids for service registration */
+/* APP ID definition*/
+#define BTC_HF_ID_1 0
+
+#if HFP_DYNAMIC_MEMORY == TRUE
+extern hf_local_param_t *hf_local_param_ptr;
+#define hf_local_param (*hf_local_param_ptr)
+#endif
+
+/* BTC-AG control block to map bdaddr to BTA handle */
+typedef struct
+{
+ bool initialized;
+ UINT16 handle;
+ bt_bdaddr_t connected_bda;
+ tBTA_AG_PEER_FEAT peer_feat;
+ tBTA_AG_CHLD_FEAT chld_feat;
+ struct timespec call_end_timestamp;
+ struct timespec connected_timestamp;
+ esp_hf_connection_state_t connection_state;
+ esp_hf_vr_state_t vr_state;
+ int num_active;
+ int num_held;
+ esp_hf_call_status_t call_state;
+ esp_hf_call_setup_status_t call_setup_state;
+} btc_hf_cb_t;
+
+typedef struct
+{
+ int hf_idx;
+ UINT32 btc_hf_features;
+ btc_hf_cb_t btc_hf_cb;
+ esp_hf_incoming_data_cb_t btc_hf_incoming_data_cb;
+ esp_hf_outgoing_data_cb_t btc_hf_outgoing_data_cb;
+} hf_local_param_t;
+
+/*******************************************************************************
+** BTC HF AG Handle Hub
+********************************************************************************/
+void btc_hf_call_handler(btc_msg_t *msg); // act the cmd from esp-application
+
+void btc_hf_cb_handler(btc_msg_t *msg); //handle the event from bta
+
+void btc_hf_incoming_data_cb_to_app(const uint8_t *data, uint32_t len);
+
+uint32_t btc_hf_outgoing_data_cb_to_app(uint8_t *data, uint32_t len);
+
+void btc_hf_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
+
+void btc_hf_arg_deep_free(btc_msg_t *msg);
+
+#endif // BTC_HF_INCLUDED == TRUE
+
+#endif /* __BTC_HF_AG_H__ */
+
#define UC_BT_SPP_ENABLED FALSE
#endif
-//HFP
+//HFP(AG)
+#ifdef CONFIG_BT_HFP_AG_ENABLE
+#define UC_BT_HFP_AG_ENABLED CONFIG_BT_HFP_AG_ENABLE
+#else
+#define UC_BT_HFP_AG_ENABLED FALSE
+#endif
+
+//HFP(Client)
#ifdef CONFIG_BT_HFP_CLIENT_ENABLE
#define UC_BT_HFP_CLIENT_ENABLED CONFIG_BT_HFP_CLIENT_ENABLE
#else
#define BTC_SPP_INCLUDED TRUE
#endif /* UC_BT_SPP_ENABLED */
+#if (UC_BT_HFP_AG_ENABLED == TRUE)
+#define BTC_HF_INCLUDED TRUE
+#define BTA_AG_INCLUDED TRUE
+#define PLC_INCLUDED TRUE
+#ifndef RFCOMM_INCLUDED
+#define RFCOMM_INCLUDED TRUE
+#endif
+#ifndef BTM_SCO_INCLUDED
+#define BTM_SCO_INCLUDED TRUE
+#endif
+#ifndef BTM_MAX_SCO_LINKS
+#define BTM_MAX_SCO_LINKS (1)
+#endif
+#ifndef SBC_DEC_INCLUDED
+#define SBC_DEC_INCLUDED TRUE
+#endif
+#ifndef SBC_ENC_INCLUDED
+#define SBC_ENC_INCLUDED TRUE
+#endif
+#endif /* UC_BT_HFP_AG_ENABLED */
+
#if (UC_BT_HFP_CLIENT_ENABLED == TRUE)
#define BTC_HF_CLIENT_INCLUDED TRUE
#define BTA_HF_INCLUDED TRUE
#if BTM_SCO_HCI_INCLUDED == TRUE
void btm_sco_process_num_bufs (UINT16 num_lm_sco_bufs)
{
- BTM_TRACE_ERROR("%s, %d", __FUNCTION__, num_lm_sco_bufs);
+ BTM_TRACE_DEBUG("%s, %d", __FUNCTION__, num_lm_sco_bufs);
btm_cb.sco_cb.num_lm_sco_bufs = btm_cb.sco_cb.xmit_window_size = num_lm_sco_bufs;
}
case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
btm_route_sco_data (p_msg);
+ osi_free(p_msg);
break;
#endif