New Clean Commit for AG.

Only Support single AG control block.
This commit is contained in:
weitianhua 2019-10-09 17:24:30 +08:00 committed by bot
parent 8fbece32a9
commit 26b69f1363
32 changed files with 11714 additions and 29 deletions

View file

@ -33,6 +33,7 @@ if(CONFIG_BT_ENABLED)
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
@ -74,6 +75,7 @@ if(CONFIG_BT_ENABLED)
"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"
@ -116,6 +118,15 @@ if(CONFIG_BT_ENABLED)
"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"
@ -151,6 +162,8 @@ if(CONFIG_BT_ENABLED)
"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"

View file

@ -47,6 +47,9 @@
#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 */
@ -108,6 +111,9 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = {
#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 */

View file

@ -63,6 +63,9 @@ typedef enum {
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 */

View file

@ -27,6 +27,7 @@ ifdef CONFIG_BT_BLUEDROID_ENABLED
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 \
@ -77,6 +78,7 @@ COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
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 \
@ -94,6 +96,7 @@ COMPONENT_SRCDIRS += host/bluedroid/bta/dm \
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 \

View file

@ -72,6 +72,9 @@ choice BT_HFP_ROLE
config BT_HFP_CLIENT_ENABLE
bool "Hands Free Unit"
config BT_HFP_AG_ENABLE
bool "Audio Gateway"
endchoice
choice BT_HFP_AUDIO_DATA_PATH

View file

@ -0,0 +1,529 @@
// 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

View file

@ -0,0 +1,535 @@
// 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__

View file

@ -126,7 +126,7 @@ typedef union {
* @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 */
/**

View file

@ -21,6 +21,44 @@
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 {
@ -28,11 +66,32 @@ 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 {
@ -42,12 +101,18 @@ 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 */
@ -55,12 +120,6 @@ typedef enum {
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 */
@ -118,23 +177,35 @@ typedef enum {
ESP_HF_BTRH_CMD_REJECT = 2, /*!< reject a held incoming call */
} esp_hf_btrh_cmd_t;
/// response indication codes for AT commands
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;
/* +NREC */
typedef enum
{
ESP_HF_NREC_STOP = 0,
ESP_HF_NREC_START
} esp_hf_nrec_t;
/// voice recognition state
///+CCWA resposne 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_CALL_WAITING_INACTIVE,
ESP_HF_CALL_WAITING_ACTIVE,
} esp_hf_call_waiting_status_t;
/* 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_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 {
@ -147,6 +218,24 @@ 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 */
@ -174,6 +263,84 @@ typedef enum {
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

View file

@ -0,0 +1,818 @@
/******************************************************************************
*
* 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 *) &reg);
}
/*******************************************************************************
**
** 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) */

View file

@ -0,0 +1,322 @@
/******************************************************************************
*
* 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)*/

View file

@ -0,0 +1,201 @@
/******************************************************************************
*
* 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) */

View file

@ -0,0 +1,60 @@
/******************************************************************************
*
* 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) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,972 @@
/******************************************************************************
*
* 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 *) &reg);
}
}
/*******************************************************************************
**
** 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) */

View file

@ -0,0 +1,403 @@
/******************************************************************************
*
* 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) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,446 @@
/******************************************************************************
*
* 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) */

View file

@ -0,0 +1,126 @@
/******************************************************************************
*
* 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 */

View file

@ -0,0 +1,446 @@
/******************************************************************************
*
* 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 */

View file

@ -0,0 +1,594 @@
/******************************************************************************
*
* 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 */

View file

@ -0,0 +1,160 @@
/******************************************************************************
*
* 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 */

View file

@ -57,6 +57,9 @@ btc_dm_cb_t *btc_dm_cb_ptr;
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
@ -510,6 +513,11 @@ static bt_status_t btc_in_execute_service_request(tBTA_SERVICE_ID service_id,
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);

View file

@ -30,6 +30,11 @@
#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"
@ -121,6 +126,89 @@ const char *dump_rc_pdu(UINT8 pdu)
}
#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;

View file

@ -19,6 +19,7 @@
#include "stack/bt_types.h"
#include "common/bt_defs.h"
#include "esp_bt_defs.h"
#include "esp_hf_defs.h"
/*******************************************************************************
** Constants & Macros
@ -34,9 +35,18 @@ typedef char bdstr_t[18];
/*******************************************************************************
** 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);

View file

@ -0,0 +1,590 @@
/******************************************************************************
*
* 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) */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,259 @@
// 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__ */

View file

@ -53,7 +53,14 @@
#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

View file

@ -80,6 +80,27 @@
#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

View file

@ -215,7 +215,7 @@ static void btm_esco_conn_rsp (UINT16 sco_inx, UINT8 hci_status, BD_ADDR bda,
#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;
}

View file

@ -152,6 +152,7 @@ static void btu_hci_msg_process(void *param)
case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
btm_route_sco_data (p_msg);
osi_free(p_msg);
break;
#endif