1/****************************************************************************** 2 * 3 * Copyright (C) 2004-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#define LOG_TAG "bta_ag_cmd" 20 21#include <ctype.h> 22#include <stdio.h> 23#include <string.h> 24 25#include "bt_common.h" 26#include "bt_target.h" 27#include "bt_types.h" 28#include "bta_ag_api.h" 29#include "bta_ag_at.h" 30#include "bta_ag_int.h" 31#include "bta_api.h" 32#include "bta_sys.h" 33#include "osi/include/log.h" 34#include "osi/include/osi.h" 35#include "port_api.h" 36#include "utl.h" 37 38/***************************************************************************** 39 * Constants 40 ****************************************************************************/ 41 42/* Ring timeout */ 43#define BTA_AG_RING_TIMEOUT_MS (5 * 1000) /* 5 seconds */ 44 45#define BTA_AG_CMD_MAX_VAL 32767 /* Maximum value is signed 16-bit value */ 46 47/* Invalid Chld command */ 48#define BTA_AG_INVALID_CHLD 255 49 50/* clip type constants */ 51#define BTA_AG_CLIP_TYPE_MIN 128 52#define BTA_AG_CLIP_TYPE_MAX 175 53#define BTA_AG_CLIP_TYPE_DEFAULT 129 54#define BTA_AG_CLIP_TYPE_VOIP 255 55 56#define COLON_IDX_4_VGSVGM 4 57 58/* Local events which will not trigger a higher layer callback */ 59enum { 60 BTA_AG_LOCAL_EVT_FIRST = 0x100, 61 BTA_AG_LOCAL_EVT_CCWA, 62 BTA_AG_LOCAL_EVT_CLIP, 63 BTA_AG_LOCAL_EVT_CMER, 64 BTA_AG_LOCAL_EVT_BRSF, 65 BTA_AG_LOCAL_EVT_CMEE, 66 BTA_AG_LOCAL_EVT_BIA, 67 BTA_AG_LOCAL_EVT_BCC, 68}; 69 70/* AT command interpreter table for HSP */ 71const tBTA_AG_AT_CMD bta_ag_hsp_cmd[] = { 72 {"+CKPD", BTA_AG_AT_CKPD_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 200, 200}, 73 {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, 74 {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, 75 /* End-of-table marker used to stop lookup iteration */ 76 {"", 0, 0, 0, 0, 0}}; 77 78/* AT command interpreter table for HFP */ 79const tBTA_AG_AT_CMD bta_ag_hfp_cmd[] = { 80 {"A", BTA_AG_AT_A_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 81 {"D", BTA_AG_AT_D_EVT, BTA_AG_AT_NONE | BTA_AG_AT_FREE, BTA_AG_AT_STR, 0, 82 0}, 83 {"+VGS", BTA_AG_SPK_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, 84 {"+VGM", BTA_AG_MIC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 15}, 85 {"+CCWA", BTA_AG_LOCAL_EVT_CCWA, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, 86 /* Consider CHLD as str to take care of indexes for ECC */ 87 {"+CHLD", BTA_AG_AT_CHLD_EVT, BTA_AG_AT_SET | BTA_AG_AT_TEST, BTA_AG_AT_STR, 88 0, 4}, 89 {"+CHUP", BTA_AG_AT_CHUP_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 90 {"+CIND", BTA_AG_AT_CIND_EVT, BTA_AG_AT_READ | BTA_AG_AT_TEST, 91 BTA_AG_AT_STR, 0, 0}, 92 {"+CLIP", BTA_AG_LOCAL_EVT_CLIP, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, 93 {"+CMER", BTA_AG_LOCAL_EVT_CMER, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, 94 {"+VTS", BTA_AG_AT_VTS_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, 95 {"+BINP", BTA_AG_AT_BINP_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 1, 1}, 96 {"+BLDN", BTA_AG_AT_BLDN_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 97 {"+BVRA", BTA_AG_AT_BVRA_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, 98 {"+BRSF", BTA_AG_LOCAL_EVT_BRSF, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 99 BTA_AG_CMD_MAX_VAL}, 100 {"+NREC", BTA_AG_AT_NREC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 0}, 101 {"+CNUM", BTA_AG_AT_CNUM_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 102 {"+BTRH", BTA_AG_AT_BTRH_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_INT, 103 0, 2}, 104 {"+CLCC", BTA_AG_AT_CLCC_EVT, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 105 {"+COPS", BTA_AG_AT_COPS_EVT, BTA_AG_AT_READ | BTA_AG_AT_SET, BTA_AG_AT_STR, 106 0, 0}, 107 {"+CMEE", BTA_AG_LOCAL_EVT_CMEE, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 1}, 108 {"+BIA", BTA_AG_LOCAL_EVT_BIA, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 20}, 109 {"+CBC", BTA_AG_AT_CBC_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 100}, 110 {"+BCC", BTA_AG_LOCAL_EVT_BCC, BTA_AG_AT_NONE, BTA_AG_AT_STR, 0, 0}, 111 {"+BCS", BTA_AG_AT_BCS_EVT, BTA_AG_AT_SET, BTA_AG_AT_INT, 0, 112 BTA_AG_CMD_MAX_VAL}, 113 {"+BIND", BTA_AG_AT_BIND_EVT, 114 BTA_AG_AT_SET | BTA_AG_AT_READ | BTA_AG_AT_TEST, BTA_AG_AT_STR, 0, 0}, 115 {"+BIEV", BTA_AG_AT_BIEV_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, 116 {"+BAC", BTA_AG_AT_BAC_EVT, BTA_AG_AT_SET, BTA_AG_AT_STR, 0, 0}, 117 /* End-of-table marker used to stop lookup iteration */ 118 {"", 0, 0, 0, 0, 0}}; 119 120/* AT result code table element */ 121typedef struct { 122 const char* result_string; /* AT result string */ 123 size_t result_id; /* Local or BTA result id */ 124 uint8_t arg_type; /* whether argument is int or string */ 125} tBTA_AG_RESULT; 126 127/* AT result code argument types */ 128enum { 129 BTA_AG_RES_FMT_NONE, /* no argument */ 130 BTA_AG_RES_FMT_INT, /* integer argument */ 131 BTA_AG_RES_FMT_STR /* string argument */ 132}; 133 134/* Local AT command result codes not defined in bta_ag_api.h */ 135enum { 136 BTA_AG_LOCAL_RES_FIRST = 0x0100, 137 BTA_AG_LOCAL_RES_OK, 138 BTA_AG_LOCAL_RES_ERROR, 139 BTA_AG_LOCAL_RES_RING, 140 BTA_AG_LOCAL_RES_CLIP, 141 BTA_AG_LOCAL_RES_BRSF, 142 BTA_AG_LOCAL_RES_CMEE, 143 BTA_AG_LOCAL_RES_BCS 144}; 145 146/* AT result code constant table */ 147const tBTA_AG_RESULT bta_ag_result_tbl[] = { 148 {"OK", BTA_AG_LOCAL_RES_OK, BTA_AG_RES_FMT_NONE}, 149 {"ERROR", BTA_AG_LOCAL_RES_ERROR, BTA_AG_RES_FMT_NONE}, 150 {"RING", BTA_AG_LOCAL_RES_RING, BTA_AG_RES_FMT_NONE}, 151 {"+VGS: ", BTA_AG_SPK_RES, BTA_AG_RES_FMT_INT}, 152 {"+VGM: ", BTA_AG_MIC_RES, BTA_AG_RES_FMT_INT}, 153 {"+CCWA: ", BTA_AG_CALL_WAIT_RES, BTA_AG_RES_FMT_STR}, 154 {"+CHLD: ", BTA_AG_IN_CALL_HELD_RES, BTA_AG_RES_FMT_STR}, 155 {"+CIND: ", BTA_AG_CIND_RES, BTA_AG_RES_FMT_STR}, 156 {"+CLIP: ", BTA_AG_LOCAL_RES_CLIP, BTA_AG_RES_FMT_STR}, 157 {"+CIEV: ", BTA_AG_IND_RES, BTA_AG_RES_FMT_STR}, 158 {"+BINP: ", BTA_AG_BINP_RES, BTA_AG_RES_FMT_STR}, 159 {"+BVRA: ", BTA_AG_BVRA_RES, BTA_AG_RES_FMT_INT}, 160 {"+BRSF: ", BTA_AG_LOCAL_RES_BRSF, BTA_AG_RES_FMT_INT}, 161 {"+BSIR: ", BTA_AG_INBAND_RING_RES, BTA_AG_RES_FMT_INT}, 162 {"+CNUM: ", BTA_AG_CNUM_RES, BTA_AG_RES_FMT_STR}, 163 {"+BTRH: ", BTA_AG_BTRH_RES, BTA_AG_RES_FMT_INT}, 164 {"+CLCC: ", BTA_AG_CLCC_RES, BTA_AG_RES_FMT_STR}, 165 {"+COPS: ", BTA_AG_COPS_RES, BTA_AG_RES_FMT_STR}, 166 {"+CME ERROR: ", BTA_AG_LOCAL_RES_CMEE, BTA_AG_RES_FMT_INT}, 167 {"+BCS: ", BTA_AG_LOCAL_RES_BCS, BTA_AG_RES_FMT_INT}, 168 {"+BIND: ", BTA_AG_BIND_RES, BTA_AG_RES_FMT_STR}, 169 {"", BTA_AG_UNAT_RES, BTA_AG_RES_FMT_STR}}; 170 171static const tBTA_AG_RESULT* bta_ag_result_by_code(size_t code) { 172 for (size_t i = 0; 173 i != sizeof(bta_ag_result_tbl) / sizeof(bta_ag_result_tbl[0]); ++i) { 174 if (code == bta_ag_result_tbl[i].result_id) return &bta_ag_result_tbl[i]; 175 } 176 return 0; 177} 178 179const tBTA_AG_AT_CMD* bta_ag_at_tbl[BTA_AG_NUM_IDX] = {bta_ag_hsp_cmd, 180 bta_ag_hfp_cmd}; 181 182typedef struct { 183 size_t result_code; 184 size_t indicator; 185} tBTA_AG_INDICATOR_MAP; 186 187/* callsetup indicator value lookup table */ 188const tBTA_AG_INDICATOR_MAP callsetup_indicator_map[] = { 189 {BTA_AG_IN_CALL_RES, BTA_AG_CALLSETUP_INCOMING}, 190 {BTA_AG_CALL_WAIT_RES, BTA_AG_CALLSETUP_INCOMING}, 191 {BTA_AG_OUT_CALL_ORIG_RES, BTA_AG_CALLSETUP_OUTGOING}, 192 {BTA_AG_OUT_CALL_ALERT_RES, BTA_AG_CALLSETUP_ALERTING}}; 193 194static size_t bta_ag_indicator_by_result_code(size_t code) { 195 for (size_t i = 0; 196 i != 197 sizeof(callsetup_indicator_map) / sizeof(callsetup_indicator_map[0]); 198 ++i) { 199 if (code == callsetup_indicator_map[i].result_code) 200 return callsetup_indicator_map[i].indicator; 201 } 202 return BTA_AG_CALLSETUP_NONE; 203} 204 205/******************************************************************************* 206 * 207 * Function bta_ag_send_result 208 * 209 * Description Send an AT result code. 210 * 211 * 212 * Returns void 213 * 214 ******************************************************************************/ 215static void bta_ag_send_result(tBTA_AG_SCB* p_scb, size_t code, 216 const char* p_arg, int16_t int_arg) { 217 const tBTA_AG_RESULT* result = bta_ag_result_by_code(code); 218 if (result == 0) { 219 LOG_ERROR(LOG_TAG, "%s Unable to lookup result for code %zu", __func__, 220 code); 221 return; 222 } 223 224 char buf[BTA_AG_AT_MAX_LEN + 16]; 225 char* p = buf; 226 memset(buf, 0, sizeof(buf)); 227 228 /* init with \r\n */ 229 *p++ = '\r'; 230 *p++ = '\n'; 231 232 /* copy result code string */ 233 strlcpy(p, result->result_string, sizeof(buf) - 2); 234 235 if (p_scb->conn_service == BTA_AG_HSP) { 236 /* If HSP then ":"symbol should be changed as "=" for HSP compatibility */ 237 switch (code) { 238 case BTA_AG_SPK_RES: 239 case BTA_AG_MIC_RES: 240 if (*(p + COLON_IDX_4_VGSVGM) == ':') { 241 *(p + COLON_IDX_4_VGSVGM) = '='; 242 } 243 break; 244 } 245 } 246 247 p += strlen(result->result_string); 248 249 /* copy argument if any */ 250 if (result->arg_type == BTA_AG_RES_FMT_INT) { 251 p += utl_itoa((uint16_t)int_arg, p); 252 } else if (result->arg_type == BTA_AG_RES_FMT_STR) { 253 strcpy(p, p_arg); 254 p += strlen(p_arg); 255 } 256 257 /* finish with \r\n */ 258 *p++ = '\r'; 259 *p++ = '\n'; 260 261 /* send to RFCOMM */ 262 uint16_t len = 0; 263 PORT_WriteData(p_scb->conn_handle, buf, (uint16_t)(p - buf), &len); 264} 265 266/******************************************************************************* 267 * 268 * Function bta_ag_send_ok 269 * 270 * Description Send an OK result code. 271 * 272 * 273 * Returns void 274 * 275 ******************************************************************************/ 276static void bta_ag_send_ok(tBTA_AG_SCB* p_scb) { 277 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_OK, NULL, 0); 278} 279 280/******************************************************************************* 281 * 282 * Function bta_ag_send_error 283 * 284 * Description Send an ERROR result code. 285 * errcode - used to send verbose errocode 286 * 287 * 288 * Returns void 289 * 290 ******************************************************************************/ 291static void bta_ag_send_error(tBTA_AG_SCB* p_scb, int16_t errcode) { 292 /* If HFP and extended audio gateway error codes are enabled */ 293 if (p_scb->conn_service == BTA_AG_HFP && p_scb->cmee_enabled) 294 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CMEE, NULL, errcode); 295 else 296 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_ERROR, NULL, 0); 297} 298 299/******************************************************************************* 300 * 301 * Function bta_ag_send_ind 302 * 303 * Description Send an indicator CIEV result code. 304 * 305 * 306 * Returns void 307 * 308 ******************************************************************************/ 309static void bta_ag_send_ind(tBTA_AG_SCB* p_scb, uint16_t id, uint16_t value, 310 bool on_demand) { 311 char str[12]; 312 char* p = str; 313 314 /* If the indicator is masked out, just return */ 315 /* Mandatory indicators can not be masked out. */ 316 if ((p_scb->bia_masked_out & ((uint32_t)1 << id)) && 317 ((id != BTA_AG_IND_CALL) && (id != BTA_AG_IND_CALLSETUP) && 318 (id != BTA_AG_IND_CALLHELD))) 319 return; 320 321 /* Ensure we do not send duplicate indicators if not requested by app */ 322 /* If it was requested by app, transmit CIEV even if it is duplicate. */ 323 if (id == BTA_AG_IND_CALL) { 324 if ((value == p_scb->call_ind) && (on_demand == false)) return; 325 326 p_scb->call_ind = (uint8_t)value; 327 } 328 329 if ((id == BTA_AG_IND_CALLSETUP) && (on_demand == false)) { 330 if (value == p_scb->callsetup_ind) return; 331 332 p_scb->callsetup_ind = (uint8_t)value; 333 } 334 335 if ((id == BTA_AG_IND_SERVICE) && (on_demand == false)) { 336 if (value == p_scb->service_ind) return; 337 338 p_scb->service_ind = (uint8_t)value; 339 } 340 if ((id == BTA_AG_IND_SIGNAL) && (on_demand == false)) { 341 if (value == p_scb->signal_ind) return; 342 343 p_scb->signal_ind = (uint8_t)value; 344 } 345 if ((id == BTA_AG_IND_ROAM) && (on_demand == false)) { 346 if (value == p_scb->roam_ind) return; 347 348 p_scb->roam_ind = (uint8_t)value; 349 } 350 if ((id == BTA_AG_IND_BATTCHG) && (on_demand == false)) { 351 if (value == p_scb->battchg_ind) return; 352 353 p_scb->battchg_ind = (uint8_t)value; 354 } 355 356 if ((id == BTA_AG_IND_CALLHELD) && (on_demand == false)) { 357 /* call swap could result in sending callheld=1 multiple times */ 358 if ((value != 1) && (value == p_scb->callheld_ind)) return; 359 360 p_scb->callheld_ind = (uint8_t)value; 361 } 362 363 if (p_scb->cmer_enabled) { 364 p += utl_itoa(id, p); 365 *p++ = ','; 366 utl_itoa(value, p); 367 bta_ag_send_result(p_scb, BTA_AG_IND_RES, str, 0); 368 } 369} 370 371/******************************************************************************* 372 * 373 * Function bta_ag_parse_cmer 374 * 375 * Description Parse AT+CMER parameter string. 376 * 377 * 378 * Returns true if parsed ok, false otherwise. 379 * 380 ******************************************************************************/ 381static bool bta_ag_parse_cmer(char* p_s, bool* p_enabled) { 382 int16_t n[4] = {-1, -1, -1, -1}; 383 int i; 384 char* p; 385 386 for (i = 0; i < 4; i++) { 387 /* skip to comma delimiter */ 388 for (p = p_s; *p != ',' && *p != 0; p++) 389 ; 390 391 /* get integer value */ 392 *p = 0; 393 n[i] = utl_str2int(p_s); 394 p_s = p + 1; 395 if (p_s == 0) { 396 break; 397 } 398 } 399 400 /* process values */ 401 if (n[0] < 0 || n[3] < 0) { 402 return false; 403 } 404 405 if ((n[0] == 3) && ((n[3] == 1) || (n[3] == 0))) { 406 *p_enabled = (bool)n[3]; 407 } 408 409 return true; 410} 411 412/******************************************************************************* 413 * 414 * Function bta_ag_parse_chld 415 * 416 * Description Parse AT+CHLD parameter string. 417 * 418 * 419 * Returns Returns idx (1-7), 0 if ECC not enabled or 420 BTA_AG_INVALID_CHLD 421 if idx doesn't exist/1st character of argument is not a 422 digit 423 * 424 ******************************************************************************/ 425static uint8_t bta_ag_parse_chld(UNUSED_ATTR tBTA_AG_SCB* p_scb, char* p_s) { 426 uint8_t retval = 0; 427 int16_t idx = -1; 428 429 if (!isdigit(p_s[0])) { 430 return BTA_AG_INVALID_CHLD; 431 } 432 433 if (p_s[1] != 0) { 434 /* p_idxstr++; point to beginning of call number */ 435 idx = utl_str2int(&p_s[1]); 436 if (idx != -1 && idx < 255) { 437 retval = (uint8_t)idx; 438 } else { 439 retval = BTA_AG_INVALID_CHLD; 440 } 441 } 442 443 return (retval); 444} 445 446/******************************************************************************* 447 * 448 * Function bta_ag_parse_bac 449 * 450 * Description Parse AT+BAC parameter string. 451 * 452 * Returns Returns bitmap of supported codecs. 453 * 454 ******************************************************************************/ 455static tBTA_AG_PEER_CODEC bta_ag_parse_bac(tBTA_AG_SCB* p_scb, char* p_s) { 456 tBTA_AG_PEER_CODEC retval = BTA_AG_CODEC_NONE; 457 uint16_t uuid_codec; 458 bool cont = false; /* Continue processing */ 459 char* p; 460 461 while (p_s) { 462 /* skip to comma delimiter */ 463 for (p = p_s; *p != ',' && *p != 0; p++) 464 ; 465 466 /* get integre value */ 467 if (*p != 0) { 468 *p = 0; 469 cont = true; 470 } else 471 cont = false; 472 473 uuid_codec = utl_str2int(p_s); 474 switch (uuid_codec) { 475 case UUID_CODEC_CVSD: 476 retval |= BTA_AG_CODEC_CVSD; 477 break; 478 case UUID_CODEC_MSBC: 479 retval |= BTA_AG_CODEC_MSBC; 480 break; 481 default: 482 APPL_TRACE_ERROR("Unknown Codec UUID(%d) received", uuid_codec); 483 break; 484 } 485 486 if (cont) 487 p_s = p + 1; 488 else 489 break; 490 } 491 492 return (retval); 493} 494 495/******************************************************************************* 496 * 497 * Function bta_ag_process_unat_res 498 * 499 * Description Process the unat response data and remove extra carriage 500 * return and line feed 501 * 502 * 503 * Returns void 504 * 505 ******************************************************************************/ 506 507static void bta_ag_process_unat_res(char* unat_result) { 508 uint8_t str_leng; 509 uint8_t i = 0; 510 uint8_t j = 0; 511 uint8_t pairs_of_nl_cr; 512 char trim_data[BTA_AG_AT_MAX_LEN]; 513 514 str_leng = strlen(unat_result); 515 516 /* If no extra CR and LF, just return */ 517 if (str_leng < 4) return; 518 519 /* Remove the carriage return and left feed */ 520 while (unat_result[0] == '\r' && unat_result[1] == '\n' && 521 unat_result[str_leng - 2] == '\r' && 522 unat_result[str_leng - 1] == '\n') { 523 pairs_of_nl_cr = 1; 524 for (i = 0; i < (str_leng - 4 * pairs_of_nl_cr); i++) { 525 trim_data[j++] = unat_result[i + pairs_of_nl_cr * 2]; 526 } 527 /* Add EOF */ 528 trim_data[j] = '\0'; 529 str_leng = str_leng - 4; 530 strlcpy(unat_result, trim_data, str_leng + 1); 531 i = 0; 532 j = 0; 533 534 if (str_leng < 4) return; 535 } 536 return; 537} 538 539/******************************************************************************* 540 * 541 * Function bta_ag_inband_enabled 542 * 543 * Description Determine whether in-band ring can be used. 544 * 545 * 546 * Returns void 547 * 548 ******************************************************************************/ 549bool bta_ag_inband_enabled(tBTA_AG_SCB* p_scb) { 550 /* if feature is enabled and no other scbs connected */ 551 if (p_scb->inband_enabled && !bta_ag_other_scb_open(p_scb)) { 552 return true; 553 } else { 554 return false; 555 } 556} 557 558/******************************************************************************* 559 * 560 * Function bta_ag_send_call_inds 561 * 562 * Description Send call and callsetup indicators. 563 * 564 * 565 * Returns void 566 * 567 ******************************************************************************/ 568void bta_ag_send_call_inds(tBTA_AG_SCB* p_scb, tBTA_AG_RES result) { 569 uint8_t call = p_scb->call_ind; 570 571 /* set new call and callsetup values based on BTA_AgResult */ 572 size_t callsetup = bta_ag_indicator_by_result_code(result); 573 574 if (result == BTA_AG_END_CALL_RES) { 575 call = BTA_AG_CALL_INACTIVE; 576 } else if (result == BTA_AG_IN_CALL_CONN_RES || 577 result == BTA_AG_OUT_CALL_CONN_RES || 578 result == BTA_AG_IN_CALL_HELD_RES) { 579 call = BTA_AG_CALL_ACTIVE; 580 } else { 581 call = p_scb->call_ind; 582 } 583 584 /* Send indicator function tracks if the values have actually changed */ 585 bta_ag_send_ind(p_scb, BTA_AG_IND_CALL, call, false); 586 bta_ag_send_ind(p_scb, BTA_AG_IND_CALLSETUP, callsetup, false); 587} 588 589/******************************************************************************* 590 * 591 * Function bta_ag_at_hsp_cback 592 * 593 * Description AT command processing callback for HSP. 594 * 595 * 596 * Returns void 597 * 598 ******************************************************************************/ 599void bta_ag_at_hsp_cback(tBTA_AG_SCB* p_scb, uint16_t command_id, 600 uint8_t arg_type, char* p_arg, int16_t int_arg) { 601 APPL_TRACE_DEBUG("AT cmd:%d arg_type:%d arg:%d arg:%s", command_id, arg_type, 602 int_arg, p_arg); 603 604 bta_ag_send_ok(p_scb); 605 606 tBTA_AG_VAL val; 607 val.hdr.handle = bta_ag_scb_to_idx(p_scb); 608 val.hdr.app_id = p_scb->app_id; 609 val.num = (uint16_t)int_arg; 610 strlcpy(val.str, p_arg, sizeof(val.str)); 611 612 /* call callback with event */ 613 (*bta_ag_cb.p_cback)(command_id, (tBTA_AG*)&val); 614} 615 616/******************************************************************************* 617 * 618 * Function bta_ag_find_empty_hf_ind) 619 * 620 * Description This function returns the index of an empty HF indicator 621 * structure. 622 * 623 * Returns int : index of the empty HF indicator structure or 624 * -1 if no empty indicator 625 * is available. 626 * 627 ******************************************************************************/ 628static int bta_ag_find_empty_hf_ind(tBTA_AG_SCB* p_scb) { 629 for (int index = 0; index < BTA_AG_MAX_NUM_PEER_HF_IND; index++) { 630 if (p_scb->peer_hf_indicators[index].ind_id == 0) return index; 631 } 632 633 return -1; 634} 635 636/******************************************************************************* 637 * 638 * Function bta_ag_find_hf_ind_by_id 639 * 640 * Description This function returns the index of the HF indicator 641 * structure by the indicator id 642 * 643 * Returns int : index of the HF indicator structure 644 * -1 if the indicator 645 * was not found. 646 * 647 ******************************************************************************/ 648static int bta_ag_find_hf_ind_by_id(tBTA_AG_HF_IND* p_hf_ind, int size, 649 uint32_t ind_id) { 650 for (int index = 0; index < size; index++) { 651 if (p_hf_ind[index].ind_id == ind_id) return index; 652 } 653 654 return -1; 655} 656 657/******************************************************************************* 658 * 659 * Function bta_ag_parse_bind_set 660 * 661 * Description Parse AT+BIND set command and save the indicators 662 * 663 * Returns true if successful 664 * 665 ******************************************************************************/ 666static bool bta_ag_parse_bind_set(tBTA_AG_SCB* p_scb, tBTA_AG_VAL val) { 667 char* p_token = strtok(val.str, ","); 668 if (p_token == NULL) return false; 669 670 while (p_token != NULL) { 671 uint16_t rcv_ind_id = atoi(p_token); 672 int index = bta_ag_find_empty_hf_ind(p_scb); 673 if (index == -1) { 674 APPL_TRACE_WARNING("%s Can't save more indicators", __func__); 675 return false; 676 } 677 678 p_scb->peer_hf_indicators[index].ind_id = rcv_ind_id; 679 APPL_TRACE_DEBUG("%s peer_hf_ind[%d] = %d", __func__, index, rcv_ind_id); 680 681 p_token = strtok(NULL, ","); 682 } 683 684 return true; 685} 686 687/******************************************************************************* 688 * 689 * Function bta_ag_bind_response 690 * 691 * Description Send response for the AT+BIND command (HFP 1.7) received 692 * from the headset based on the argument types. 693 * 694 * Returns Void 695 * 696 ******************************************************************************/ 697static void bta_ag_bind_response(tBTA_AG_SCB* p_scb, uint8_t arg_type) { 698 char buffer[BTA_AG_AT_MAX_LEN]; 699 memset(buffer, 0, BTA_AG_AT_MAX_LEN); 700 701 if (arg_type == BTA_AG_AT_TEST) { 702 int index = 0; 703 buffer[index++] = '('; 704 705 for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) { 706 if (bta_ag_local_hf_ind_cfg[i + 1].is_supported) { 707 /* Add ',' from second indicator */ 708 if (index > 1) buffer[index++] = ','; 709 snprintf(&buffer[index++], 2, "%d", 710 bta_ag_local_hf_ind_cfg[i + 1].ind_id); 711 } 712 } 713 714 buffer[index++] = ')'; 715 716 bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0); 717 bta_ag_send_ok(p_scb); 718 } else if (arg_type == BTA_AG_AT_READ) { 719 char* p = buffer; 720 721 /* bta_ag_local_hf_ind_cfg[0].ind_id is used as BTA_AG_NUM_LOCAL_HF_IND */ 722 for (uint32_t i = 0; i < bta_ag_local_hf_ind_cfg[0].ind_id; i++) { 723 if (i == BTA_AG_MAX_NUM_LOCAL_HF_IND) { 724 APPL_TRACE_WARNING("%s No space for more HF indicators", __func__); 725 break; 726 } 727 728 p_scb->local_hf_indicators[i].ind_id = 729 bta_ag_local_hf_ind_cfg[i + 1].ind_id; 730 p_scb->local_hf_indicators[i].is_supported = 731 bta_ag_local_hf_ind_cfg[i + 1].is_supported; 732 p_scb->local_hf_indicators[i].is_enable = 733 bta_ag_local_hf_ind_cfg[i + 1].is_enable; 734 735 int peer_index = bta_ag_find_hf_ind_by_id( 736 p_scb->peer_hf_indicators, BTA_AG_MAX_NUM_PEER_HF_IND, 737 p_scb->local_hf_indicators[i].ind_id); 738 739 /* Check whether local and peer sides support this indicator */ 740 if (p_scb->local_hf_indicators[i].is_supported == true && 741 peer_index != -1) { 742 /* In the format of ind, state */ 743 p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].ind_id, p); 744 *p++ = ','; 745 p += utl_itoa((uint16_t)p_scb->local_hf_indicators[i].is_enable, p); 746 747 bta_ag_send_result(p_scb, BTA_AG_BIND_RES, buffer, 0); 748 749 memset(buffer, 0, sizeof(buffer)); 750 p = buffer; 751 } else { 752 /* If indicator is not supported, also set it to disable */ 753 p_scb->local_hf_indicators[i].is_enable = false; 754 } 755 } 756 757 bta_ag_send_ok(p_scb); 758 759 /* If the service level connection wan't already open, now it's open */ 760 if (!p_scb->svc_conn) bta_ag_svc_conn_open(p_scb, NULL); 761 } 762} 763 764/******************************************************************************* 765 * 766 * Function bta_ag_parse_biev_response 767 * 768 * Description Send response for AT+BIEV command (HFP 1.7) received from 769 * the headset based on the argument types. 770 * 771 * Returns true if the response was parsed successfully 772 * 773 ******************************************************************************/ 774static bool bta_ag_parse_biev_response(tBTA_AG_SCB* p_scb, tBTA_AG_VAL* val) { 775 char* p_token = strtok(val->str, ","); 776 uint16_t rcv_ind_id = atoi(p_token); 777 778 p_token = strtok(NULL, ","); 779 uint16_t rcv_ind_val = atoi(p_token); 780 781 APPL_TRACE_DEBUG("%s BIEV indicator id %d, value %d", __func__, rcv_ind_id, 782 rcv_ind_val); 783 784 /* Check whether indicator ID is valid or not */ 785 if (rcv_ind_id > BTA_AG_NUM_LOCAL_HF_IND) { 786 APPL_TRACE_WARNING("%s received invalid indicator id %d", __func__, 787 rcv_ind_id); 788 return false; 789 } 790 791 /* Check this indicator is support or not and enabled or not */ 792 int local_index = bta_ag_find_hf_ind_by_id( 793 p_scb->local_hf_indicators, BTA_AG_MAX_NUM_LOCAL_HF_IND, rcv_ind_id); 794 if (local_index == -1 || 795 p_scb->local_hf_indicators[local_index].is_supported != true || 796 p_scb->local_hf_indicators[local_index].is_enable != true) { 797 APPL_TRACE_WARNING("%s indicator id %d not supported or disabled", __func__, 798 rcv_ind_id); 799 return false; 800 } 801 802 /* For each indicator ID, check whether the indicator value is in range */ 803 if (rcv_ind_val < bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_min_val || 804 rcv_ind_val > bta_ag_local_hf_ind_cfg[rcv_ind_id].ind_max_val) { 805 APPL_TRACE_WARNING("%s invalid ind_val %d", __func__, rcv_ind_val); 806 return false; 807 } 808 809 val->lidx = rcv_ind_id; 810 val->num = rcv_ind_val; 811 812 return true; 813} 814 815/******************************************************************************* 816 * 817 * Function bta_ag_at_hfp_cback 818 * 819 * Description AT command processing callback for HFP. 820 * 821 * 822 * Returns void 823 * 824 ******************************************************************************/ 825void bta_ag_at_hfp_cback(tBTA_AG_SCB* p_scb, uint16_t cmd, uint8_t arg_type, 826 char* p_arg, int16_t int_arg) { 827 tBTA_AG_VAL val; 828 tBTA_AG_SCB* ag_scb; 829 uint32_t i, ind_id; 830 uint32_t bia_masked_out; 831 if (p_arg == NULL) { 832 APPL_TRACE_ERROR("%s: p_arg is null, send error and return", __func__); 833 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); 834 return; 835 } 836 837 APPL_TRACE_DEBUG("%s: AT command %d, arg_type %d, int_arg %d, arg %s", 838 __func__, cmd, arg_type, int_arg, p_arg); 839 840 memset(&val, 0, sizeof(tBTA_AG_VAL)); 841 val.hdr.handle = bta_ag_scb_to_idx(p_scb); 842 val.hdr.app_id = p_scb->app_id; 843 val.hdr.status = BTA_AG_SUCCESS; 844 val.num = int_arg; 845 bdcpy(val.bd_addr, p_scb->peer_addr); 846 strlcpy(val.str, p_arg, sizeof(val.str)); 847 848 /** 849 * Unless this this is a local event, by default we'll forward 850 * the event code to the application. 851 * If |event| is 0 at the end of this function, the application 852 * callback is NOT invoked. 853 */ 854 tBTA_AG_EVT event = 0; 855 if (cmd < BTA_AG_LOCAL_EVT_FIRST) event = cmd; 856 857 switch (cmd) { 858 case BTA_AG_AT_A_EVT: 859 case BTA_AG_SPK_EVT: 860 case BTA_AG_MIC_EVT: 861 case BTA_AG_AT_CHUP_EVT: 862 case BTA_AG_AT_CBC_EVT: 863 /* send OK */ 864 bta_ag_send_ok(p_scb); 865 break; 866 867 case BTA_AG_AT_BLDN_EVT: 868 /* Do not send OK, App will send error or OK depending on 869 ** last dial number enabled or not */ 870 break; 871 872 case BTA_AG_AT_D_EVT: 873 /* Do not send OK for Dial cmds 874 ** Let application decide whether to send OK or ERROR*/ 875 876 /* if mem dial cmd, make sure string contains only digits */ 877 if (p_arg[0] == '>') { 878 if (!utl_isintstr(p_arg + 1)) { 879 event = 0; 880 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR); 881 } 882 } else if (p_arg[0] == 'V') /* ATDV : Dial VoIP Call */ 883 { 884 /* We do not check string. Code will be added later if needed. */ 885 if (!((p_scb->peer_features & BTA_AG_PEER_FEAT_VOIP) && 886 (p_scb->features & BTA_AG_FEAT_VOIP))) { 887 event = 0; 888 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 889 } 890 } 891 /* If dial cmd, make sure string contains only dial digits 892 ** Dial digits are 0-9, A-C, *, #, + */ 893 else { 894 if (!utl_isdialstr(p_arg)) { 895 event = 0; 896 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_DSTR); 897 } 898 } 899 break; 900 901 case BTA_AG_LOCAL_EVT_CCWA: 902 /* store setting */ 903 p_scb->ccwa_enabled = (bool)int_arg; 904 905 /* send OK */ 906 bta_ag_send_ok(p_scb); 907 break; 908 909 case BTA_AG_AT_CHLD_EVT: 910 if (arg_type == BTA_AG_AT_TEST) { 911 /* don't call callback */ 912 event = 0; 913 914 /* send CHLD string */ 915 /* Form string based on supported 1.5 feature */ 916 if ((p_scb->peer_version >= HFP_VERSION_1_5) && 917 (p_scb->features & BTA_AG_FEAT_ECC) && 918 (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC)) 919 bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES, 920 p_bta_ag_cfg->chld_val_ecc, 0); 921 else 922 bta_ag_send_result(p_scb, BTA_AG_IN_CALL_HELD_RES, 923 p_bta_ag_cfg->chld_val, 0); 924 925 /* send OK */ 926 bta_ag_send_ok(p_scb); 927 928 /* if service level conn. not already open, now it's open */ 929 bta_ag_svc_conn_open(p_scb, NULL); 930 } else { 931 val.idx = bta_ag_parse_chld(p_scb, val.str); 932 933 if (val.idx == BTA_AG_INVALID_CHLD) { 934 event = 0; 935 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 936 break; 937 } 938 if (val.idx && 939 !((p_scb->features & BTA_AG_FEAT_ECC) && 940 (p_scb->peer_features & BTA_AG_PEER_FEAT_ECC))) { 941 /* we do not support ECC, but HF is sending us a CHLD with call 942 * index*/ 943 event = 0; 944 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 945 946 } else { 947 /* If it is swap between calls, set call held indicator to 3(out of 948 *valid 0-2) 949 ** Application will set it back to 1 950 ** callheld indicator will be sent across to the peer. */ 951 if (val.str[0] == '2') { 952 for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; 953 i++, ag_scb++) { 954 if (ag_scb->in_use) { 955 if ((ag_scb->call_ind == BTA_AG_CALL_ACTIVE) && 956 (ag_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE)) 957 ag_scb->callheld_ind = BTA_AG_CALLHELD_NOACTIVE + 1; 958 } 959 } 960 } 961 } 962 963 /* Do not send OK. Let app decide after parsing the val str */ 964 /* bta_ag_send_ok(p_scb); */ 965 } 966 break; 967 968 case BTA_AG_AT_BIND_EVT: 969 APPL_TRACE_DEBUG("%s BTA_AG_AT_BIND_EVT arg_type: %d", __func__, 970 arg_type); 971 if (arg_type == BTA_AG_AT_SET) { 972 if (bta_ag_parse_bind_set(p_scb, val)) { 973 bta_ag_send_ok(p_scb); 974 } else { 975 event = 0; /* don't call callback */ 976 bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX); 977 } 978 } else { 979 bta_ag_bind_response(p_scb, arg_type); 980 981 /* Need not pass this command beyond BTIF.*/ 982 /* Stack handles it internally */ 983 event = 0; /* don't call callback */ 984 } 985 break; 986 987 case BTA_AG_AT_BIEV_EVT: 988 if (bta_ag_parse_biev_response(p_scb, &val)) { 989 bta_ag_send_ok(p_scb); 990 } else { 991 bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX); 992 /* don't call callback receiving invalid indicator */ 993 event = 0; 994 } 995 break; 996 997 case BTA_AG_AT_CIND_EVT: 998 if (arg_type == BTA_AG_AT_TEST) { 999 /* don't call callback */ 1000 event = 0; 1001 1002 /* send CIND string, send OK */ 1003 bta_ag_send_result(p_scb, BTA_AG_CIND_RES, p_bta_ag_cfg->cind_info, 0); 1004 bta_ag_send_ok(p_scb); 1005 } 1006 break; 1007 1008 case BTA_AG_LOCAL_EVT_CLIP: 1009 /* store setting, send OK */ 1010 p_scb->clip_enabled = (bool)int_arg; 1011 bta_ag_send_ok(p_scb); 1012 break; 1013 1014 case BTA_AG_LOCAL_EVT_CMER: 1015 /* if parsed ok store setting, send OK */ 1016 if (bta_ag_parse_cmer(p_arg, &p_scb->cmer_enabled)) { 1017 bta_ag_send_ok(p_scb); 1018 1019 /* if service level conn. not already open and our features and 1020 ** peer features do not have 3-way, service level conn. now open 1021 */ 1022 if (!p_scb->svc_conn && 1023 !((p_scb->features & BTA_AG_FEAT_3WAY) && 1024 (p_scb->peer_features & BTA_AG_PEER_FEAT_3WAY))) { 1025 bta_ag_svc_conn_open(p_scb, NULL); 1026 } 1027 } else { 1028 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); 1029 } 1030 break; 1031 1032 case BTA_AG_AT_VTS_EVT: 1033 /* check argument */ 1034 if (strlen(p_arg) == 1) { 1035 bta_ag_send_ok(p_scb); 1036 } else { 1037 event = 0; 1038 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); 1039 } 1040 break; 1041 1042 case BTA_AG_AT_BINP_EVT: 1043 /* if feature not set don't call callback, send ERROR */ 1044 if (!(p_scb->features & BTA_AG_FEAT_VTAG)) { 1045 event = 0; 1046 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1047 } 1048 break; 1049 1050 case BTA_AG_AT_BVRA_EVT: 1051 /* if feature not supported don't call callback, send ERROR. App will send 1052 * OK */ 1053 if (!(p_scb->features & BTA_AG_FEAT_VREC)) { 1054 event = 0; 1055 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1056 } 1057 break; 1058 1059 case BTA_AG_LOCAL_EVT_BRSF: { 1060 /* store peer features */ 1061 p_scb->peer_features = (uint16_t)int_arg; 1062 1063 tBTA_AG_FEAT features = p_scb->features; 1064 if (p_scb->peer_version < HFP_VERSION_1_7) { 1065 features &= HFP_1_6_FEAT_MASK; 1066 } 1067 1068 APPL_TRACE_DEBUG("%s BRSF HF: 0x%x, phone: 0x%x", __func__, 1069 p_scb->peer_features, features); 1070 1071 /* send BRSF, send OK */ 1072 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BRSF, NULL, (int16_t)features); 1073 bta_ag_send_ok(p_scb); 1074 break; 1075 } 1076 1077 case BTA_AG_AT_NREC_EVT: 1078 /* if feature send OK, else don't call callback, send ERROR */ 1079 if (p_scb->features & BTA_AG_FEAT_ECNR) { 1080 bta_ag_send_ok(p_scb); 1081 } else { 1082 event = 0; 1083 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1084 } 1085 break; 1086 1087 case BTA_AG_AT_BTRH_EVT: 1088 /* if feature send BTRH, send OK:, else don't call callback, send ERROR */ 1089 if (p_scb->features & BTA_AG_FEAT_BTRH) { 1090 /* If set command; send response and notify app */ 1091 if (arg_type == BTA_AG_AT_SET) { 1092 for (i = 0, ag_scb = &bta_ag_cb.scb[0]; i < BTA_AG_NUM_SCB; 1093 i++, ag_scb++) { 1094 if (ag_scb->in_use) { 1095 bta_ag_send_result(ag_scb, BTA_AG_BTRH_RES, NULL, int_arg); 1096 } 1097 } 1098 bta_ag_send_ok(p_scb); 1099 } else /* Read Command */ 1100 { 1101 val.num = BTA_AG_BTRH_READ; 1102 } 1103 } else { 1104 event = 0; 1105 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1106 } 1107 break; 1108 1109 case BTA_AG_AT_COPS_EVT: 1110 if (arg_type == BTA_AG_AT_SET) { 1111 /* don't call callback */ 1112 event = 0; 1113 1114 /* send OK */ 1115 bta_ag_send_ok(p_scb); 1116 } 1117 break; 1118 1119 case BTA_AG_LOCAL_EVT_CMEE: 1120 if (p_scb->features & BTA_AG_FEAT_EXTERR) { 1121 /* store setting */ 1122 p_scb->cmee_enabled = (bool)int_arg; 1123 1124 /* send OK */ 1125 bta_ag_send_ok(p_scb); 1126 } else { 1127 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1128 } 1129 /* don't call callback */ 1130 event = 0; 1131 break; 1132 1133 case BTA_AG_LOCAL_EVT_BIA: 1134 /* don't call callback */ 1135 event = 0; 1136 1137 bia_masked_out = p_scb->bia_masked_out; 1138 1139 /* Parse the indicator mask */ 1140 for (i = 0, ind_id = 1; (val.str[i] != 0) && (ind_id <= 20); 1141 i++, ind_id++) { 1142 if (val.str[i] == ',') continue; 1143 1144 if (val.str[i] == '0') 1145 bia_masked_out |= ((uint32_t)1 << ind_id); 1146 else if (val.str[i] == '1') 1147 bia_masked_out &= ~((uint32_t)1 << ind_id); 1148 else 1149 break; 1150 1151 i++; 1152 if ((val.str[i] == 0) || (val.str[i] != ',')) break; 1153 } 1154 if (val.str[i] == 0) { 1155 p_scb->bia_masked_out = bia_masked_out; 1156 bta_ag_send_ok(p_scb); 1157 } else 1158 bta_ag_send_error(p_scb, BTA_AG_ERR_INVALID_INDEX); 1159 break; 1160 1161 case BTA_AG_AT_CNUM_EVT: 1162 break; 1163 1164 case BTA_AG_AT_CLCC_EVT: 1165 if (!(p_scb->features & BTA_AG_FEAT_ECS)) { 1166 event = 0; 1167 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1168 } 1169 break; 1170 1171 case BTA_AG_AT_BAC_EVT: 1172 bta_ag_send_ok(p_scb); 1173 1174 /* store available codecs from the peer */ 1175 if ((p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC) && 1176 (p_scb->features & BTA_AG_FEAT_CODEC)) { 1177 p_scb->peer_codecs = bta_ag_parse_bac(p_scb, p_arg); 1178 p_scb->codec_updated = true; 1179 1180 if (p_scb->peer_codecs & BTA_AG_CODEC_MSBC) { 1181 p_scb->sco_codec = UUID_CODEC_MSBC; 1182 APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to MSBC"); 1183 } else { 1184 p_scb->sco_codec = UUID_CODEC_CVSD; 1185 APPL_TRACE_DEBUG("Received AT+BAC, updating sco codec to CVSD"); 1186 } 1187 /* The above logic sets the stack preferred codec based on local and 1188 peer codec 1189 capabilities. This can be overridden by the application depending on its 1190 preference 1191 using the bta_ag_setcodec API. We send the peer_codecs to the 1192 application. */ 1193 val.num = p_scb->peer_codecs; 1194 /* Received BAC while in codec negotiation. */ 1195 if ((bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST) && 1196 (bta_ag_cb.sco.p_curr_scb == p_scb)) { 1197 bta_ag_codec_negotiate(p_scb); 1198 } 1199 } else { 1200 p_scb->peer_codecs = BTA_AG_CODEC_CVSD; 1201 APPL_TRACE_ERROR( 1202 "Unexpected CMD:AT+BAC, Codec Negotiation is not supported"); 1203 } 1204 break; 1205 1206 case BTA_AG_AT_BCS_EVT: { 1207 tBTA_AG_PEER_CODEC codec_type, codec_sent; 1208 bta_ag_send_ok(p_scb); 1209 alarm_cancel(p_scb->codec_negotiation_timer); 1210 1211 switch (int_arg) { 1212 case UUID_CODEC_CVSD: 1213 codec_type = BTA_AG_CODEC_CVSD; 1214 break; 1215 case UUID_CODEC_MSBC: 1216 codec_type = BTA_AG_CODEC_MSBC; 1217 break; 1218 default: 1219 APPL_TRACE_ERROR("Unknown codec_uuid %d", int_arg); 1220 codec_type = 0xFFFF; 1221 break; 1222 } 1223 1224 if (p_scb->codec_fallback) 1225 codec_sent = BTA_AG_CODEC_CVSD; 1226 else 1227 codec_sent = p_scb->sco_codec; 1228 1229 if (codec_type == codec_sent) 1230 bta_ag_sco_codec_nego(p_scb, true); 1231 else 1232 bta_ag_sco_codec_nego(p_scb, false); 1233 1234 /* send final codec info to callback */ 1235 val.num = codec_sent; 1236 break; 1237 } 1238 case BTA_AG_LOCAL_EVT_BCC: 1239 bta_ag_send_ok(p_scb); 1240 bta_ag_sco_open(p_scb, NULL); 1241 break; 1242 1243 default: 1244 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1245 break; 1246 } 1247 1248 /* call callback */ 1249 if (event != 0) { 1250 (*bta_ag_cb.p_cback)(event, (tBTA_AG*)&val); 1251 } 1252} 1253 1254/******************************************************************************* 1255 * 1256 * Function bta_ag_at_err_cback 1257 * 1258 * Description AT command parser error callback. 1259 * 1260 * 1261 * Returns void 1262 * 1263 ******************************************************************************/ 1264void bta_ag_at_err_cback(tBTA_AG_SCB* p_scb, bool unknown, char* p_arg) { 1265 tBTA_AG_VAL val; 1266 1267 if (unknown && (!strlen(p_arg))) { 1268 APPL_TRACE_DEBUG("Empty AT cmd string received"); 1269 bta_ag_send_ok(p_scb); 1270 return; 1271 } 1272 1273 /* if unknown AT command and configured to pass these to app */ 1274 if (unknown && (p_scb->features & BTA_AG_FEAT_UNAT)) { 1275 val.hdr.handle = bta_ag_scb_to_idx(p_scb); 1276 val.hdr.app_id = p_scb->app_id; 1277 val.hdr.status = BTA_AG_SUCCESS; 1278 val.num = 0; 1279 strlcpy(val.str, p_arg, sizeof(val.str)); 1280 (*bta_ag_cb.p_cback)(BTA_AG_AT_UNAT_EVT, (tBTA_AG*)&val); 1281 } else { 1282 bta_ag_send_error(p_scb, BTA_AG_ERR_OP_NOT_SUPPORTED); 1283 } 1284} 1285 1286/******************************************************************************* 1287 * 1288 * Function bta_ag_hsp_result 1289 * 1290 * Description Handle API result for HSP connections. 1291 * 1292 * 1293 * Returns void 1294 * 1295 ******************************************************************************/ 1296void bta_ag_hsp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) { 1297 APPL_TRACE_DEBUG("bta_ag_hsp_result : res = %d", p_result->result); 1298 1299 switch (p_result->result) { 1300 case BTA_AG_SPK_RES: 1301 case BTA_AG_MIC_RES: 1302 bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num); 1303 break; 1304 1305 case BTA_AG_IN_CALL_RES: 1306 /* tell sys to stop av if any */ 1307 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); 1308 1309 /* if sco already opened or no inband ring send ring now */ 1310 if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) || 1311 (p_scb->features & BTA_AG_FEAT_NOSCO)) { 1312 bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result); 1313 } else { 1314 /* else open sco, send ring after sco opened */ 1315 /* HSPv1.2: AG shall not send RING if using in-band ring tone. */ 1316 if (p_scb->peer_version >= HSP_VERSION_1_2) { 1317 p_scb->post_sco = BTA_AG_POST_SCO_NONE; 1318 } else { 1319 p_scb->post_sco = BTA_AG_POST_SCO_RING; 1320 } 1321 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1322 } 1323 break; 1324 1325 case BTA_AG_IN_CALL_CONN_RES: 1326 case BTA_AG_OUT_CALL_ORIG_RES: 1327 /* if incoming call connected stop ring timer */ 1328 if (p_result->result == BTA_AG_IN_CALL_CONN_RES) { 1329 alarm_cancel(p_scb->ring_timer); 1330 } 1331 1332 if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1333 /* if audio connected to this scb AND sco is not opened, open sco */ 1334 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && 1335 !bta_ag_sco_is_open(p_scb)) { 1336 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1337 } 1338 /* else if no audio at call close sco */ 1339 else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE && 1340 bta_ag_sco_is_open(p_scb)) { 1341 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1342 } 1343 } 1344 break; 1345 1346 case BTA_AG_END_CALL_RES: 1347 alarm_cancel(p_scb->ring_timer); 1348 1349 /* close sco */ 1350 if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && 1351 !(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1352 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1353 } else { 1354 /* if av got suspended by this call, let it resume. */ 1355 bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); 1356 } 1357 break; 1358 1359 case BTA_AG_INBAND_RING_RES: 1360 p_scb->inband_enabled = p_result->data.state; 1361 APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled); 1362 break; 1363 1364 case BTA_AG_UNAT_RES: 1365 if (p_result->data.ok_flag != BTA_AG_OK_ERROR) { 1366 if (p_result->data.str[0] != 0) { 1367 bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0); 1368 } 1369 1370 if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb); 1371 } else { 1372 bta_ag_send_error(p_scb, BTA_AG_ERR_INV_CHAR_IN_TSTR); 1373 } 1374 break; 1375 1376 default: 1377 /* ignore all others */ 1378 break; 1379 } 1380} 1381 1382/******************************************************************************* 1383 * 1384 * Function bta_ag_hfp_result 1385 * 1386 * Description Handle API result for HFP connections. 1387 * 1388 * 1389 * Returns void 1390 * 1391 ******************************************************************************/ 1392void bta_ag_hfp_result(tBTA_AG_SCB* p_scb, tBTA_AG_API_RESULT* p_result) { 1393 APPL_TRACE_DEBUG("bta_ag_hfp_result : res = %d", p_result->result); 1394 1395 switch (p_result->result) { 1396 case BTA_AG_SPK_RES: 1397 case BTA_AG_MIC_RES: 1398 bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num); 1399 break; 1400 1401 case BTA_AG_IN_CALL_RES: 1402 /* tell sys to stop av if any */ 1403 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); 1404 1405 /* store caller id string. 1406 * append type info at the end. 1407 * make sure a valid type info is passed. 1408 * otherwise add 129 as default type */ 1409 if ((p_result->data.num < BTA_AG_CLIP_TYPE_MIN) || 1410 (p_result->data.num > BTA_AG_CLIP_TYPE_MAX)) { 1411 if (p_result->data.num != BTA_AG_CLIP_TYPE_VOIP) 1412 p_result->data.num = BTA_AG_CLIP_TYPE_DEFAULT; 1413 } 1414 1415 APPL_TRACE_DEBUG("CLIP type :%d", p_result->data.num); 1416 p_scb->clip[0] = 0; 1417 if (p_result->data.str[0] != 0) 1418 snprintf(p_scb->clip, sizeof(p_scb->clip), "%s,%d", p_result->data.str, 1419 p_result->data.num); 1420 1421 /* send callsetup indicator */ 1422 if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END) { 1423 /* Need to sent 2 callsetup IND's(Call End and Incoming call) after SCO 1424 * close. */ 1425 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END_INCALL; 1426 } else { 1427 bta_ag_send_call_inds(p_scb, p_result->result); 1428 1429 /* if sco already opened or no inband ring send ring now */ 1430 if (bta_ag_sco_is_open(p_scb) || !bta_ag_inband_enabled(p_scb) || 1431 (p_scb->features & BTA_AG_FEAT_NOSCO)) { 1432 bta_ag_send_ring(p_scb, (tBTA_AG_DATA*)p_result); 1433 } else { 1434 /* else open sco, send ring after sco opened */ 1435 p_scb->post_sco = BTA_AG_POST_SCO_RING; 1436 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1437 } 1438 } 1439 break; 1440 1441 case BTA_AG_IN_CALL_CONN_RES: 1442 alarm_cancel(p_scb->ring_timer); 1443 1444 /* if sco not opened and we need to open it, send indicators first 1445 ** then open sco. 1446 */ 1447 bta_ag_send_call_inds(p_scb, p_result->result); 1448 1449 if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1450 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && 1451 !bta_ag_sco_is_open(p_scb)) { 1452 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1453 } else if ((p_result->data.audio_handle == BTA_AG_HANDLE_NONE) && 1454 bta_ag_sco_is_open(p_scb)) { 1455 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1456 } 1457 } 1458 break; 1459 1460 case BTA_AG_IN_CALL_HELD_RES: 1461 alarm_cancel(p_scb->ring_timer); 1462 1463 bta_ag_send_call_inds(p_scb, p_result->result); 1464 1465 break; 1466 1467 case BTA_AG_OUT_CALL_ORIG_RES: 1468 bta_ag_send_call_inds(p_scb, p_result->result); 1469 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && 1470 !(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1471 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1472 } 1473 break; 1474 1475 case BTA_AG_OUT_CALL_ALERT_RES: 1476 /* send indicators */ 1477 bta_ag_send_call_inds(p_scb, p_result->result); 1478 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb) && 1479 !(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1480 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1481 } 1482 break; 1483 1484 case BTA_AG_MULTI_CALL_RES: 1485 /* open SCO at SLC for this three way call */ 1486 APPL_TRACE_DEBUG("Headset Connected in three way call"); 1487 if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1488 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) 1489 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1490 else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) 1491 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1492 } 1493 break; 1494 1495 case BTA_AG_OUT_CALL_CONN_RES: 1496 /* send indicators */ 1497 bta_ag_send_call_inds(p_scb, p_result->result); 1498 1499 /* open or close sco */ 1500 if (!(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1501 if (p_result->data.audio_handle == bta_ag_scb_to_idx(p_scb)) { 1502 bta_ag_sco_open(p_scb, (tBTA_AG_DATA*)p_result); 1503 } else if (p_result->data.audio_handle == BTA_AG_HANDLE_NONE) { 1504 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1505 } 1506 } 1507 break; 1508 1509 case BTA_AG_CALL_CANCEL_RES: 1510 /* send indicators */ 1511 bta_ag_send_call_inds(p_scb, p_result->result); 1512 break; 1513 1514 case BTA_AG_END_CALL_RES: 1515 alarm_cancel(p_scb->ring_timer); 1516 1517 /* if sco open, close sco then send indicator values */ 1518 if ((bta_ag_sco_is_open(p_scb) || bta_ag_sco_is_opening(p_scb)) && 1519 !(p_scb->features & BTA_AG_FEAT_NOSCO)) { 1520 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END; 1521 bta_ag_sco_close(p_scb, (tBTA_AG_DATA*)p_result); 1522 } else if (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END_INCALL) { 1523 /* sco closing for outgoing call because of incoming call */ 1524 /* Send only callsetup end indicator after sco close */ 1525 p_scb->post_sco = BTA_AG_POST_SCO_CALL_END; 1526 } else { 1527 bta_ag_send_call_inds(p_scb, p_result->result); 1528 1529 /* if av got suspended by this call, let it resume. */ 1530 bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr); 1531 } 1532 break; 1533 1534 case BTA_AG_INBAND_RING_RES: 1535 p_scb->inband_enabled = p_result->data.state; 1536 APPL_TRACE_DEBUG("inband_enabled set to %d", p_scb->inband_enabled); 1537 bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state); 1538 break; 1539 1540 case BTA_AG_CIND_RES: 1541 /* store local values */ 1542 p_scb->call_ind = p_result->data.str[0] - '0'; 1543 p_scb->callsetup_ind = p_result->data.str[2] - '0'; 1544 p_scb->service_ind = p_result->data.str[4] - '0'; 1545 p_scb->signal_ind = p_result->data.str[6] - '0'; 1546 p_scb->roam_ind = p_result->data.str[8] - '0'; 1547 p_scb->battchg_ind = p_result->data.str[10] - '0'; 1548 p_scb->callheld_ind = p_result->data.str[12] - '0'; 1549 APPL_TRACE_DEBUG("cind call:%d callsetup:%d", p_scb->call_ind, 1550 p_scb->callsetup_ind); 1551 1552 bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0); 1553 bta_ag_send_ok(p_scb); 1554 break; 1555 1556 case BTA_AG_BINP_RES: 1557 case BTA_AG_CNUM_RES: 1558 case BTA_AG_CLCC_RES: 1559 case BTA_AG_COPS_RES: 1560 if (p_result->data.ok_flag != BTA_AG_OK_ERROR) { 1561 if (p_result->data.str[0] != 0) { 1562 bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0); 1563 } 1564 1565 if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb); 1566 } else { 1567 bta_ag_send_error(p_scb, p_result->data.errcode); 1568 } 1569 break; 1570 1571 case BTA_AG_UNAT_RES: 1572 if (p_result->data.ok_flag != BTA_AG_OK_ERROR) { 1573 if (p_result->data.str[0] != 0) { 1574 bta_ag_process_unat_res(p_result->data.str); 1575 APPL_TRACE_DEBUG("BTA_AG_RES :%s", p_result->data.str); 1576 bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0); 1577 } 1578 1579 if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb); 1580 } else { 1581 bta_ag_send_error(p_scb, p_result->data.errcode); 1582 } 1583 break; 1584 1585 case BTA_AG_CALL_WAIT_RES: 1586 if (p_scb->ccwa_enabled) { 1587 bta_ag_send_result(p_scb, p_result->result, p_result->data.str, 0); 1588 } 1589 bta_ag_send_call_inds(p_scb, p_result->result); 1590 break; 1591 1592 case BTA_AG_IND_RES: 1593 bta_ag_send_ind(p_scb, p_result->data.ind.id, p_result->data.ind.value, 1594 false); 1595 break; 1596 1597 case BTA_AG_BVRA_RES: 1598 bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.state); 1599 break; 1600 1601 case BTA_AG_BTRH_RES: 1602 if (p_result->data.ok_flag != BTA_AG_OK_ERROR) { 1603 /* Don't respond to read if not in response & hold state */ 1604 if (p_result->data.num != BTA_AG_BTRH_NO_RESP) { 1605 bta_ag_send_result(p_scb, p_result->result, NULL, p_result->data.num); 1606 } 1607 1608 /* In case of a response to a read request we need to send OK */ 1609 if (p_result->data.ok_flag == BTA_AG_OK_DONE) bta_ag_send_ok(p_scb); 1610 } else { 1611 bta_ag_send_error(p_scb, p_result->data.errcode); 1612 } 1613 break; 1614 1615 case BTA_AG_BIND_RES: { 1616 /* Find whether ind_id is supported by local device or not */ 1617 int local_index = bta_ag_find_hf_ind_by_id(p_scb->local_hf_indicators, 1618 BTA_AG_MAX_NUM_LOCAL_HF_IND, 1619 p_result->data.ind.id); 1620 if (local_index == -1) { 1621 APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__, 1622 p_result->data.ind.id); 1623 return; 1624 } 1625 1626 /* Find whether ind_id is supported by peer device or not */ 1627 int peer_index = bta_ag_find_hf_ind_by_id(p_scb->peer_hf_indicators, 1628 BTA_AG_MAX_NUM_PEER_HF_IND, 1629 p_result->data.ind.id); 1630 if (peer_index == -1) { 1631 APPL_TRACE_WARNING("%s Invalid HF Indicator ID %d", __func__, 1632 p_result->data.ind.id); 1633 return; 1634 } else { 1635 /* If the current state is different from the one upper layer request 1636 change current state and send out the result */ 1637 if (p_scb->local_hf_indicators[local_index].is_enable != 1638 p_result->data.ind.on_demand) { 1639 char buffer[BTA_AG_AT_MAX_LEN] = {0}; 1640 char* p = buffer; 1641 1642 p_scb->local_hf_indicators[local_index].is_enable = 1643 p_result->data.ind.on_demand; 1644 p += utl_itoa(p_result->data.ind.id, p); 1645 *p++ = ','; 1646 p += utl_itoa(p_scb->local_hf_indicators[local_index].is_enable, p); 1647 1648 bta_ag_send_result(p_scb, p_result->result, buffer, 0); 1649 } else { 1650 APPL_TRACE_DEBUG( 1651 "%s HF Indicator %d already %s", p_result->data.ind.id, 1652 (p_result->data.ind.on_demand == true) ? "Enabled" : "Disabled"); 1653 } 1654 } 1655 break; 1656 } 1657 1658 default: 1659 break; 1660 } 1661} 1662 1663/******************************************************************************* 1664 * 1665 * Function bta_ag_result 1666 * 1667 * Description Handle API result. 1668 * 1669 * 1670 * Returns void 1671 * 1672 ******************************************************************************/ 1673void bta_ag_result(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) { 1674 if (p_scb->conn_service == BTA_AG_HSP) { 1675 bta_ag_hsp_result(p_scb, &p_data->api_result); 1676 } else { 1677 bta_ag_hfp_result(p_scb, &p_data->api_result); 1678 } 1679} 1680 1681/******************************************************************************* 1682 * 1683 * Function bta_ag_send_bcs 1684 * 1685 * Description Send +BCS AT command to peer. 1686 * 1687 * Returns void 1688 * 1689 ******************************************************************************/ 1690void bta_ag_send_bcs(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) { 1691 uint16_t codec_uuid; 1692 1693 if (p_scb->codec_fallback) { 1694 codec_uuid = UUID_CODEC_CVSD; 1695 } else { 1696 switch (p_scb->sco_codec) { 1697 case BTA_AG_CODEC_NONE: 1698 codec_uuid = UUID_CODEC_CVSD; 1699 break; 1700 case BTA_AG_CODEC_CVSD: 1701 codec_uuid = UUID_CODEC_CVSD; 1702 break; 1703 case BTA_AG_CODEC_MSBC: 1704 codec_uuid = UUID_CODEC_MSBC; 1705 break; 1706 default: 1707 APPL_TRACE_ERROR("bta_ag_send_bcs: unknown codec %d, use CVSD", 1708 p_scb->sco_codec); 1709 codec_uuid = UUID_CODEC_CVSD; 1710 break; 1711 } 1712 } 1713 1714 /* send +BCS */ 1715 APPL_TRACE_DEBUG("send +BCS codec is %d", codec_uuid); 1716 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_BCS, NULL, codec_uuid); 1717} 1718 1719/******************************************************************************* 1720 * 1721 * Function bta_ag_send_ring 1722 * 1723 * Description Send RING result code to peer. 1724 * 1725 * 1726 * Returns void 1727 * 1728 ******************************************************************************/ 1729void bta_ag_send_ring(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) { 1730 /* send RING */ 1731 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_RING, NULL, 0); 1732 1733 /* if HFP and clip enabled and clip data send CLIP */ 1734 if (p_scb->conn_service == BTA_AG_HFP && p_scb->clip_enabled && 1735 p_scb->clip[0] != 0) { 1736 bta_ag_send_result(p_scb, BTA_AG_LOCAL_RES_CLIP, p_scb->clip, 0); 1737 } 1738 1739 bta_sys_start_timer(p_scb->ring_timer, BTA_AG_RING_TIMEOUT_MS, 1740 BTA_AG_RING_TIMEOUT_EVT, bta_ag_scb_to_idx(p_scb)); 1741} 1742