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