blob: 418156d50e40f432e3f2447e4574cc8c424be8d6 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 2009-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/************************************************************************************
20 *
21 * Filename: btif_hf.c
22 *
23 * Description: Handsfree Profile Bluetooth Interface
24 *
25 *
26 ***********************************************************************************/
27
28#include <hardware/bluetooth.h>
29#include <hardware/bt_hf.h>
30#include <stdlib.h>
31
32#define LOG_TAG "BTIF_HF"
33#include "btif_common.h"
34#include "btif_util.h"
35#include "btif_profile_queue.h"
36
37#include "bd.h"
38#include "bta_ag_api.h"
39
40/************************************************************************************
41** Constants & Macros
42************************************************************************************/
43#ifndef BTIF_HSAG_SERVICE_NAME
44#define BTIF_HSAG_SERVICE_NAME ("Headset Gateway")
45#endif
46
47#ifndef BTIF_HFAG_SERVICE_NAME
48#define BTIF_HFAG_SERVICE_NAME ("Handsfree Gateway")
49#endif
50
51#ifndef BTIF_HF_SERVICES
52#define BTIF_HF_SERVICES (BTA_HSP_SERVICE_MASK | BTA_HFP_SERVICE_MASK )
53#endif
54
55#ifndef BTIF_HF_SERVICE_NAMES
56#define BTIF_HF_SERVICE_NAMES {BTIF_HSAG_SERVICE_NAME , BTIF_HFAG_SERVICE_NAME}
57#endif
58
59#ifndef BTIF_HF_SECURITY
60#define BTIF_HF_SECURITY (BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)
61#endif
62
63#ifndef BTIF_HF_FEATURES
64#define BTIF_HF_FEATURES ( BTA_AG_FEAT_3WAY | \
65 BTA_AG_FEAT_ECNR | \
66 BTA_AG_FEAT_REJECT | \
67 BTA_AG_FEAT_ECS | \
68 BTA_AG_FEAT_EXTERR | \
69 BTA_AG_FEAT_BTRH | \
70 BTA_AG_FEAT_VREC | \
71 BTA_AG_FEAT_UNAT)
72#endif
73
The Android Open Source Project5738f832012-12-12 16:00:35 -080074#define BTIF_HF_CALL_END_TIMEOUT 6
75
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -070076#define BTIF_HF_INVALID_IDX -1
77
78/* Number of BTIF-HF control blocks */
79#define BTIF_HF_NUM_CB 2
80
81/* Max HF clients supported from App */
82UINT16 btif_max_hf_clients = -1;
83
84/* HF app ids for service registration */
85typedef enum {
86 BTIF_HF_ID_1 = 0,
87 BTIF_HF_ID_2,
88#if (BTIF_HF_NUM_CB == 3)
89 BTIF_HF_ID_3
90#endif
91} bthf_hf_id_t;
92
93UINT16 bthf_hf_id[BTIF_HF_NUM_CB] = {BTIF_HF_ID_1, BTIF_HF_ID_2,
94 #if (BTIF_HF_NUM_CB == 3)
95 BTIF_HF_ID_3
96 #endif
97 };
98
The Android Open Source Project5738f832012-12-12 16:00:35 -080099/************************************************************************************
100** Local type definitions
101************************************************************************************/
102
103/************************************************************************************
104** Static variables
105************************************************************************************/
106static bthf_callbacks_t *bt_hf_callbacks = NULL;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700107static int hf_idx = BTIF_HF_INVALID_IDX;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800108
109#define CHECK_BTHF_INIT() if (bt_hf_callbacks == NULL)\
110 {\
111 BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
112 return BT_STATUS_NOT_READY;\
113 }\
114 else\
115 {\
116 BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
117 }
118
119#define CHECK_BTHF_SLC_CONNECTED() if (bt_hf_callbacks == NULL)\
120 {\
121 BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);\
122 return BT_STATUS_NOT_READY;\
123 }\
124 else if (btif_hf_cb.state != BTHF_CONNECTION_STATE_SLC_CONNECTED)\
125 {\
126 BTIF_TRACE_WARNING2("BTHF: %s: SLC connection not up. state=%s", __FUNCTION__, dump_hf_conn_state(btif_hf_cb.state));\
127 return BT_STATUS_NOT_READY;\
128 }\
129 else\
130 {\
131 BTIF_TRACE_EVENT1("BTHF: %s", __FUNCTION__);\
132 }
133
134/* BTIF-HF control block to map bdaddr to BTA handle */
135typedef struct _btif_hf_cb
136{
137 UINT16 handle;
138 bt_bdaddr_t connected_bda;
139 bthf_connection_state_t state;
140 bthf_vr_state_t vr_state;
141 tBTA_AG_PEER_FEAT peer_feat;
142 int num_active;
143 int num_held;
144 struct timespec call_end_timestamp;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700145 struct timespec connected_timestamp;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800146 bthf_call_state_t call_setup_state;
147} btif_hf_cb_t;
148
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700149static btif_hf_cb_t btif_hf_cb[BTIF_HF_NUM_CB];
The Android Open Source Project5738f832012-12-12 16:00:35 -0800150
151
152/************************************************************************************
153** Static functions
154************************************************************************************/
155
156/************************************************************************************
157** Externs
158************************************************************************************/
159
160/************************************************************************************
161** Functions
162************************************************************************************/
163
164/*******************************************************************************
165**
166** Function is_connected
167**
168** Description Internal function to check if HF is connected
169**
170** Returns TRUE if connected
171**
172*******************************************************************************/
173static BOOLEAN is_connected(bt_bdaddr_t *bd_addr)
174{
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700175 int i;
176 for (i = 0; i < btif_max_hf_clients; ++i)
177 {
178 if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
179 (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)) &&
180 ((bd_addr == NULL) || (bdcmp(bd_addr->address,
181 btif_hf_cb[i].connected_bda.address) == 0)))
182 return TRUE;
183 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800184 return FALSE;
185}
186
187/*******************************************************************************
188**
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700189** Function btif_hf_idx_by_bdaddr
190**
191** Description Internal function to get idx by bdaddr
192**
193** Returns idx
194**
195*******************************************************************************/
196static int btif_hf_idx_by_bdaddr(bt_bdaddr_t *bd_addr)
197{
198 int i;
199 for (i = 0; i < btif_max_hf_clients; ++i)
200 {
201 if ((bdcmp(bd_addr->address,
202 btif_hf_cb[i].connected_bda.address) == 0))
203 return i;
204 }
205 return BTIF_HF_INVALID_IDX;
206}
207
208/*******************************************************************************
209**
The Android Open Source Project5738f832012-12-12 16:00:35 -0800210** Function callstate_to_callsetup
211**
212** Description Converts HAL call state to BTA call setup indicator value
213**
214** Returns BTA call indicator value
215**
216*******************************************************************************/
217static UINT8 callstate_to_callsetup(bthf_call_state_t call_state)
218{
219 UINT8 call_setup = 0;
220 if (call_state == BTHF_CALL_STATE_INCOMING)
221 call_setup = 1;
222 if (call_state == BTHF_CALL_STATE_DIALING)
223 call_setup = 2;
224 if (call_state == BTHF_CALL_STATE_ALERTING)
225 call_setup = 3;
226
227 return call_setup;
228}
229
230/*******************************************************************************
231**
232** Function send_at_result
233**
234** Description Send AT result code (OK/ERROR)
235**
236** Returns void
237**
238*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700239static void send_at_result(UINT8 ok_flag, UINT16 errcode, int idx)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800240{
241 tBTA_AG_RES_DATA ag_res;
242 memset (&ag_res, 0, sizeof (ag_res));
243
244 ag_res.ok_flag = ok_flag;
245 if (ok_flag == BTA_AG_OK_ERROR)
246 {
247 ag_res.errcode = errcode;
248 }
249
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700250 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800251}
252
253/*******************************************************************************
254**
255** Function send_indicator_update
256**
257** Description Send indicator update (CIEV)
258**
259** Returns void
260**
261*******************************************************************************/
262static void send_indicator_update (UINT16 indicator, UINT16 value)
263{
264 tBTA_AG_RES_DATA ag_res;
265
266 memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
267 ag_res.ind.id = indicator;
268 ag_res.ind.value = value;
269
270 BTA_AgResult(BTA_AG_HANDLE_ALL, BTA_AG_IND_RES, &ag_res);
271}
272
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700273void clear_phone_state_multihf(int idx)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800274{
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700275 btif_hf_cb[idx].call_setup_state = BTHF_CALL_STATE_IDLE;
276 btif_hf_cb[idx].num_active = btif_hf_cb[idx].num_held = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800277}
278
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700279/*******************************************************************************
280**
281** Function btif_hf_latest_connected_idx
282**
283** Description Returns idx for latest connected HF
284**
285** Returns int
286**
287*******************************************************************************/
288static int btif_hf_latest_connected_idx()
289{
290 struct timespec now, conn_time_delta;
291 int latest_conn_idx = BTIF_HF_INVALID_IDX, i;
292
293 clock_gettime(CLOCK_MONOTONIC, &now);
294 conn_time_delta.tv_sec = now.tv_sec;
295
296 for (i = 0; i < btif_max_hf_clients; i++)
297 {
298 if (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)
299 {
300 if ((now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec)
301 < conn_time_delta.tv_sec)
302 {
303 conn_time_delta.tv_sec =
304 now.tv_sec - btif_hf_cb[i].connected_timestamp.tv_sec;
305 latest_conn_idx = i;
306 }
307 }
308 }
309 return latest_conn_idx;
310}
311
312/*******************************************************************************
313**
314** Function btif_hf_check_if_slc_connected
315**
316** Description Returns BT_STATUS_SUCCESS if SLC is up for any HF
317**
318** Returns bt_status_t
319**
320*******************************************************************************/
321static bt_status_t btif_hf_check_if_slc_connected()
322{
323 if (bt_hf_callbacks == NULL)
324 {
325 BTIF_TRACE_WARNING1("BTHF: %s: BTHF not initialized", __FUNCTION__);
326 return BT_STATUS_NOT_READY;
327 }
328 else
329 {
330 int i;
331 for (i = 0; i < btif_max_hf_clients; i++)
332 {
333 if ((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED))
334 {
335 BTIF_TRACE_EVENT2("BTHF: %s: slc connected for idx = %d",
336 __FUNCTION__, i);
337 return BT_STATUS_SUCCESS;
338 }
339 }
340 BTIF_TRACE_WARNING1("BTHF: %s: No SLC connection up", __FUNCTION__);
341 return BT_STATUS_NOT_READY;
342 }
343}
The Android Open Source Project5738f832012-12-12 16:00:35 -0800344
345/*****************************************************************************
346** Section name (Group of functions)
347*****************************************************************************/
348
349/*****************************************************************************
350**
351** btif hf api functions (no context switch)
352**
353*****************************************************************************/
354
355
356/*******************************************************************************
357**
358** Function btif_hf_upstreams_evt
359**
360** Description Executes HF UPSTREAMS events in btif context
361**
362** Returns void
363**
364*******************************************************************************/
365static void btif_hf_upstreams_evt(UINT16 event, char* p_param)
366{
367 tBTA_AG *p_data = (tBTA_AG *)p_param;
368 bdstr_t bdstr;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700369 bt_bdaddr_t addr;
370 int idx = p_data->hdr.handle - 1;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800371
372 BTIF_TRACE_DEBUG2("%s: event=%s", __FUNCTION__, dump_hf_event(event));
373
374 switch (event)
375 {
376 case BTA_AG_ENABLE_EVT:
377 case BTA_AG_DISABLE_EVT:
378 break;
379
380 case BTA_AG_REGISTER_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700381 btif_hf_cb[idx].handle = p_data->reg.hdr.handle;
382 BTIF_TRACE_DEBUG2("%s: BTA_AG_REGISTER_EVT,"
383 "btif_hf_cb.handle = %d", __FUNCTION__, btif_hf_cb[idx].handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800384 break;
385
386 case BTA_AG_OPEN_EVT:
387 if (p_data->open.status == BTA_AG_SUCCESS)
388 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700389 bdcpy(btif_hf_cb[idx].connected_bda.address,
390 p_data->open.bd_addr);
391 btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_CONNECTED;
392 btif_hf_cb[idx].peer_feat = 0;
393 clear_phone_state_multihf(idx);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800394 }
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700395 else if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_CONNECTING)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800396 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700397 btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800398 }
399 else
400 {
401 BTIF_TRACE_WARNING4("%s: AG open failed, but another device connected. status=%d state=%d connected device=%s",
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700402 __FUNCTION__, p_data->open.status, btif_hf_cb[idx].state,
403 bd2str(&btif_hf_cb[idx].connected_bda, &bdstr));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800404 break;
405 }
406
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700407 HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
408 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800409
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700410 if (btif_hf_cb[idx].state == BTHF_CONNECTION_STATE_DISCONNECTED)
411 bdsetany(btif_hf_cb[idx].connected_bda.address);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800412
413 if (p_data->open.status != BTA_AG_SUCCESS)
414 btif_queue_advance();
415 break;
416
417 case BTA_AG_CLOSE_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700418 btif_hf_cb[idx].connected_timestamp.tv_sec = 0;
419 btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_DISCONNECTED;
420 BTIF_TRACE_DEBUG3("%s: BTA_AG_CLOSE_EVT,"
421 "idx = %d, btif_hf_cb.handle = %d", __FUNCTION__, idx,
422 btif_hf_cb[idx].handle);
423 HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
424 &btif_hf_cb[idx].connected_bda);
425 bdsetany(btif_hf_cb[idx].connected_bda.address);
426 btif_hf_cb[idx].peer_feat = 0;
427 clear_phone_state_multihf(idx);
428 hf_idx = btif_hf_latest_connected_idx();
The Android Open Source Project5738f832012-12-12 16:00:35 -0800429 /* If AG_OPEN was received but SLC was not setup in a specified time (10 seconds),
430 ** then AG_CLOSE may be received. We need to advance the queue here
431 */
432 btif_queue_advance();
433 break;
434
435 case BTA_AG_CONN_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700436 clock_gettime(CLOCK_MONOTONIC,
437 &btif_hf_cb[idx].connected_timestamp);
438 BTIF_TRACE_DEBUG2("%s: BTA_AG_CONN_EVT, idx = %d ",
439 __FUNCTION__, idx);
440 btif_hf_cb[idx].peer_feat = p_data->conn.peer_feat;
441 btif_hf_cb[idx].state = BTHF_CONNECTION_STATE_SLC_CONNECTED;
442 hf_idx = btif_hf_latest_connected_idx();
The Android Open Source Project5738f832012-12-12 16:00:35 -0800443
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700444 HAL_CBACK(bt_hf_callbacks, connection_state_cb, btif_hf_cb[idx].state,
445 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800446 btif_queue_advance();
447 break;
448
449 case BTA_AG_AUDIO_OPEN_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700450 hf_idx = idx;
451 HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTED,
452 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800453 break;
454
455 case BTA_AG_AUDIO_CLOSE_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700456 HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_DISCONNECTED,
457 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800458 break;
459
460 /* BTA auto-responds, silently discard */
461 case BTA_AG_SPK_EVT:
462 case BTA_AG_MIC_EVT:
463 HAL_CBACK(bt_hf_callbacks, volume_cmd_cb,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700464 (event == BTA_AG_SPK_EVT) ? BTHF_VOLUME_TYPE_SPK :
465 BTHF_VOLUME_TYPE_MIC, p_data->val.num,
466 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800467 break;
468
469 case BTA_AG_AT_A_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700470 hf_idx = idx;
471 HAL_CBACK(bt_hf_callbacks, answer_call_cmd_cb,
472 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800473 break;
474
475 /* Java needs to send OK/ERROR for these commands */
476 case BTA_AG_AT_BLDN_EVT:
477 case BTA_AG_AT_D_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700478 hf_idx = idx;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800479 HAL_CBACK(bt_hf_callbacks, dial_call_cmd_cb,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700480 (event == BTA_AG_AT_D_EVT) ? p_data->val.str : NULL,
481 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800482 break;
483
484 case BTA_AG_AT_CHUP_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700485 HAL_CBACK(bt_hf_callbacks, hangup_call_cmd_cb,
486 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800487 break;
488
489 case BTA_AG_AT_CIND_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700490 HAL_CBACK(bt_hf_callbacks, cind_cmd_cb,
491 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800492 break;
493
494 case BTA_AG_AT_VTS_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700495 HAL_CBACK(bt_hf_callbacks, dtmf_cmd_cb, p_data->val.str[0],
496 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800497 break;
498
499 case BTA_AG_AT_BVRA_EVT:
500 HAL_CBACK(bt_hf_callbacks, vr_cmd_cb,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700501 (p_data->val.num == 1) ? BTHF_VR_STATE_STARTED :
502 BTHF_VR_STATE_STOPPED, &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800503 break;
504
505 case BTA_AG_AT_NREC_EVT:
506 HAL_CBACK(bt_hf_callbacks, nrec_cmd_cb,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700507 (p_data->val.num == 1) ? BTHF_NREC_START : BTHF_NREC_STOP,
508 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800509 break;
510
511 /* TODO: Add a callback for CBC */
512 case BTA_AG_AT_CBC_EVT:
513 break;
514
515 case BTA_AG_AT_CKPD_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700516 HAL_CBACK(bt_hf_callbacks, key_pressed_cmd_cb,
517 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800518 break;
519
520 /* Java needs to send OK/ERROR for these commands */
521 case BTA_AG_AT_CHLD_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700522 HAL_CBACK(bt_hf_callbacks, chld_cmd_cb, atoi(p_data->val.str),
523 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800524 break;
525
526 case BTA_AG_AT_CLCC_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700527 HAL_CBACK(bt_hf_callbacks, clcc_cmd_cb,
528 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800529 break;
530
531 case BTA_AG_AT_COPS_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700532 HAL_CBACK(bt_hf_callbacks, cops_cmd_cb,
533 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800534 break;
535
536 case BTA_AG_AT_UNAT_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700537 HAL_CBACK(bt_hf_callbacks, unknown_at_cmd_cb, p_data->val.str,
538 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800539 break;
540
541 case BTA_AG_AT_CNUM_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700542 HAL_CBACK(bt_hf_callbacks, cnum_cmd_cb,
543 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800544 break;
545
546 /* TODO: Some of these commands may need to be sent to app. For now respond with error */
547 case BTA_AG_AT_BINP_EVT:
548 case BTA_AG_AT_BTRH_EVT:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700549 send_at_result(BTA_AG_OK_ERROR, BTA_AG_ERR_OP_NOT_SUPPORTED, idx);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800550 break;
551
552
553 default:
554 BTIF_TRACE_WARNING2("%s: Unhandled event: %d", __FUNCTION__, event);
555 break;
556 }
557}
558
559/*******************************************************************************
560**
561** Function bte_hf_evt
562**
563** Description Switches context from BTE to BTIF for all HF events
564**
565** Returns void
566**
567*******************************************************************************/
568
569static void bte_hf_evt(tBTA_AG_EVT event, tBTA_AG *p_data)
570{
571 bt_status_t status;
572 int param_len = 0;
573
574 /* TODO: BTA sends the union members and not tBTA_AG. If using param_len=sizeof(tBTA_AG), we get a crash on memcpy */
575 if (BTA_AG_REGISTER_EVT == event)
576 param_len = sizeof(tBTA_AG_REGISTER);
577 else if (BTA_AG_OPEN_EVT == event)
578 param_len = sizeof(tBTA_AG_OPEN);
579 else if (BTA_AG_CONN_EVT == event)
580 param_len = sizeof(tBTA_AG_CONN);
581 else if ( (BTA_AG_CLOSE_EVT == event) || (BTA_AG_AUDIO_OPEN_EVT == event) || (BTA_AG_AUDIO_CLOSE_EVT == event))
582 param_len = sizeof(tBTA_AG_HDR);
583 else if (p_data)
584 param_len = sizeof(tBTA_AG_VAL);
585
586 /* switch context to btif task context (copy full union size for convenience) */
587 status = btif_transfer_context(btif_hf_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);
588
589 /* catch any failed context transfers */
590 ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status);
591}
592
593
594/*******************************************************************************
595**
596** Function btif_in_hf_generic_evt
597**
598** Description Processes generic events to be sent to JNI that are not triggered from the BTA.
599** Always runs in BTIF context
600**
601** Returns void
602**
603*******************************************************************************/
604static void btif_in_hf_generic_evt(UINT16 event, char *p_param)
605{
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700606 int idx = btif_hf_idx_by_bdaddr((bt_bdaddr_t *)p_param);
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800607
The Android Open Source Project5738f832012-12-12 16:00:35 -0800608 BTIF_TRACE_EVENT2("%s: event=%d", __FUNCTION__, event);
609 switch (event) {
610 case BTIF_HFP_CB_AUDIO_CONNECTING:
611 {
612 HAL_CBACK(bt_hf_callbacks, audio_state_cb, BTHF_AUDIO_STATE_CONNECTING,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700613 &btif_hf_cb[idx].connected_bda);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800614 } break;
615 default:
616 {
617 BTIF_TRACE_WARNING2("%s : Unknown event 0x%x", __FUNCTION__, event);
618 }
619 break;
620 }
621}
622
623
624/*******************************************************************************
625**
626** Function btif_hf_init
627**
628** Description initializes the hf interface
629**
630** Returns bt_status_t
631**
632*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700633static bt_status_t init( bthf_callbacks_t* callbacks, int max_hf_clients)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800634{
635 BTIF_TRACE_EVENT1("%s", __FUNCTION__);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700636 int i;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800637
638 bt_hf_callbacks = callbacks;
639
640 /* Invoke the enable service API to the core to set the appropriate service_id
641 * Internally, the HSP_SERVICE_ID shall also be enabled if HFP is enabled (phone)
642 * othwerwise only HSP is enabled (tablet)
643 */
644#if (defined(BTIF_HF_SERVICES) && (BTIF_HF_SERVICES & BTA_HFP_SERVICE_MASK))
645 btif_enable_service(BTA_HFP_SERVICE_ID);
646#else
647 btif_enable_service(BTA_HSP_SERVICE_ID);
648#endif
649
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700650 memset(&btif_hf_cb, 0, sizeof(btif_hf_cb));
651 btif_max_hf_clients = max_hf_clients;
652 BTIF_TRACE_DEBUG1("btif_max_hf_clients = %d", btif_max_hf_clients);
653 for (i = 0; i < btif_max_hf_clients; i++)
654 {
655 clear_phone_state_multihf(i);
656 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800657
658 return BT_STATUS_SUCCESS;
659}
660
661/*******************************************************************************
662**
663** Function connect
664**
665** Description connect to headset
666**
667** Returns bt_status_t
668**
669*******************************************************************************/
670static bt_status_t connect_int( bt_bdaddr_t *bd_addr )
671{
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700672 CHECK_BTHF_INIT();
673 int i;
674 for (i = 0; i < btif_max_hf_clients;)
675 {
676 if (((btif_hf_cb[i].state == BTHF_CONNECTION_STATE_CONNECTED) ||
677 (btif_hf_cb[i].state == BTHF_CONNECTION_STATE_SLC_CONNECTED)))
678 i++;
679 else
680 break;
681 }
682
683 if (i == btif_max_hf_clients)
684 return BT_STATUS_BUSY;
685
The Android Open Source Project5738f832012-12-12 16:00:35 -0800686 if (!is_connected(bd_addr))
687 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700688 btif_hf_cb[i].state = BTHF_CONNECTION_STATE_CONNECTING;
689 bdcpy(btif_hf_cb[i].connected_bda.address, bd_addr->address);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800690
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700691 BTA_AgOpen(btif_hf_cb[i].handle, btif_hf_cb[i].connected_bda.address,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800692 BTIF_HF_SECURITY, BTIF_HF_SERVICES);
693 return BT_STATUS_SUCCESS;
694 }
695
696 return BT_STATUS_BUSY;
697}
698
699static bt_status_t connect( bt_bdaddr_t *bd_addr )
700{
701 CHECK_BTHF_INIT();
702 return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);
703}
704
705/*******************************************************************************
706**
707** Function disconnect
708**
709** Description disconnect from headset
710**
711** Returns bt_status_t
712**
713*******************************************************************************/
714static bt_status_t disconnect( bt_bdaddr_t *bd_addr )
715{
716 CHECK_BTHF_INIT();
717
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700718 int idx = btif_hf_idx_by_bdaddr(bd_addr);
719
720 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800721 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700722 BTA_AgClose(btif_hf_cb[idx].handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800723 return BT_STATUS_SUCCESS;
724 }
725
726 return BT_STATUS_FAIL;
727}
728
729/*******************************************************************************
730**
731** Function connect_audio
732**
733** Description create an audio connection
734**
735** Returns bt_status_t
736**
737*******************************************************************************/
738static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
739{
740 CHECK_BTHF_INIT();
741
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700742 int idx = btif_hf_idx_by_bdaddr(bd_addr);
743
744 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800745 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700746 BTA_AgAudioOpen(btif_hf_cb[idx].handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800747
748 /* Inform the application that the audio connection has been initiated successfully */
749 btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
750 (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
751 return BT_STATUS_SUCCESS;
752 }
753
754 return BT_STATUS_FAIL;
755}
756
757/*******************************************************************************
758**
759** Function disconnect_audio
760**
761** Description close the audio connection
762**
763** Returns bt_status_t
764**
765*******************************************************************************/
766static bt_status_t disconnect_audio( bt_bdaddr_t *bd_addr )
767{
768 CHECK_BTHF_INIT();
769
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700770 int idx = btif_hf_idx_by_bdaddr(bd_addr);
771
772 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800773 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700774 BTA_AgAudioClose(btif_hf_cb[idx].handle);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800775 return BT_STATUS_SUCCESS;
776 }
777
778 return BT_STATUS_FAIL;
779}
780
781/*******************************************************************************
782**
783** Function start_voice_recognition
784**
785** Description start voice recognition
786**
787** Returns bt_status_t
788**
789*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700790static bt_status_t start_voice_recognition(bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800791{
792 CHECK_BTHF_INIT();
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700793
794 int idx = btif_hf_idx_by_bdaddr(bd_addr);
795
796 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800797 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700798 if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800799 {
800 tBTA_AG_RES_DATA ag_res;
801 memset(&ag_res, 0, sizeof(ag_res));
802 ag_res.state = 1;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700803 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800804
805 return BT_STATUS_SUCCESS;
806 }
807 else
808 {
809 return BT_STATUS_UNSUPPORTED;
810 }
811 }
812
813 return BT_STATUS_NOT_READY;
814}
815
816/*******************************************************************************
817**
818** Function stop_voice_recognition
819**
820** Description stop voice recognition
821**
822** Returns bt_status_t
823**
824*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700825static bt_status_t stop_voice_recognition(bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800826{
827 CHECK_BTHF_INIT();
828
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700829 int idx = btif_hf_idx_by_bdaddr(bd_addr);
830
831 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800832 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700833 if (btif_hf_cb[idx].peer_feat & BTA_AG_PEER_FEAT_VREC)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800834 {
835 tBTA_AG_RES_DATA ag_res;
836 memset(&ag_res, 0, sizeof(ag_res));
837 ag_res.state = 0;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700838 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_BVRA_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800839
840 return BT_STATUS_SUCCESS;
841 }
842 else
843 {
844 return BT_STATUS_UNSUPPORTED;
845 }
846 }
847
848 return BT_STATUS_NOT_READY;
849}
850
851/*******************************************************************************
852**
853** Function volume_control
854**
855** Description volume control
856**
857** Returns bt_status_t
858**
859*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700860static bt_status_t volume_control(bthf_volume_type_t type, int volume,
861 bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800862{
863 CHECK_BTHF_INIT();
864
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700865 int idx = btif_hf_idx_by_bdaddr(bd_addr);
866
The Android Open Source Project5738f832012-12-12 16:00:35 -0800867 tBTA_AG_RES_DATA ag_res;
868 memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700869 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800870 {
871 ag_res.num = volume;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700872 BTA_AgResult(btif_hf_cb[idx].handle,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800873 (type == BTHF_VOLUME_TYPE_SPK) ? BTA_AG_SPK_RES : BTA_AG_MIC_RES,
874 &ag_res);
875 return BT_STATUS_SUCCESS;
876 }
877
878 return BT_STATUS_FAIL;
879}
880
881/*******************************************************************************
882**
883** Function device_status_notification
884**
885** Description Combined device status change notification
886**
887** Returns bt_status_t
888**
889*******************************************************************************/
890static bt_status_t device_status_notification(bthf_network_state_t ntk_state,
891 bthf_service_type_t svc_type, int signal, int batt_chg)
892{
893 CHECK_BTHF_INIT();
894
895 if (is_connected(NULL))
896 {
897 /* send all indicators to BTA.
898 ** BTA will make sure no duplicates are sent out
899 */
900 send_indicator_update(BTA_AG_IND_SERVICE,
901 (ntk_state == BTHF_NETWORK_STATE_AVAILABLE) ? 1 : 0);
902 send_indicator_update(BTA_AG_IND_ROAM,
903 (svc_type == BTHF_SERVICE_TYPE_HOME) ? 0 : 1);
904 send_indicator_update(BTA_AG_IND_SIGNAL, signal);
905 send_indicator_update(BTA_AG_IND_BATTCHG, batt_chg);
906 return BT_STATUS_SUCCESS;
907 }
908
909 return BT_STATUS_SUCCESS;
910}
911
912/*******************************************************************************
913**
914** Function cops_response
915**
916** Description Response for COPS command
917**
918** Returns bt_status_t
919**
920*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700921static bt_status_t cops_response(const char *cops, bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800922{
923 CHECK_BTHF_INIT();
924
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700925 int idx = btif_hf_idx_by_bdaddr(bd_addr);
926
927 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800928 {
929 tBTA_AG_RES_DATA ag_res;
930
931 /* Format the response */
932 sprintf (ag_res.str, "0,0,\"%s\"", cops);
933 ag_res.ok_flag = BTA_AG_OK_DONE;
934
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700935 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_COPS_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800936 return BT_STATUS_SUCCESS;
937 }
938 return BT_STATUS_FAIL;
939}
940
941/*******************************************************************************
942**
943** Function cind_response
944**
945** Description Response for CIND command
946**
947** Returns bt_status_t
948**
949*******************************************************************************/
950static bt_status_t cind_response(int svc, int num_active, int num_held,
951 bthf_call_state_t call_setup_state,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700952 int signal, int roam, int batt_chg,
953 bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800954{
955 CHECK_BTHF_INIT();
956
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700957 int idx = btif_hf_idx_by_bdaddr(bd_addr);
958
959 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800960 {
961 tBTA_AG_RES_DATA ag_res;
962
963 memset (&ag_res, 0, sizeof (ag_res));
964 /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
965 ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
966 **/
967 sprintf (ag_res.str, "%d,%d,%d,%d,%d,%d,%d",
968 (num_active + num_held) ? 1 : 0, /* Call state */
969 callstate_to_callsetup(call_setup_state), /* Callsetup state */
970 svc, /* network service */
971 signal, /* Signal strength */
972 roam, /* Roaming indicator */
973 batt_chg, /* Battery level */
974 ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1))); /* Call held */
975
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700976 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_CIND_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800977
978 return BT_STATUS_SUCCESS;
979 }
980
981 return BT_STATUS_FAIL;
982}
983
984/*******************************************************************************
985**
986** Function formatted_at_response
987**
988** Description Pre-formatted AT response, typically in response to unknown AT cmd
989**
990** Returns bt_status_t
991**
992*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700993static bt_status_t formatted_at_response(const char *rsp, bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800994{
995 CHECK_BTHF_INIT();
996 tBTA_AG_RES_DATA ag_res;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700997 int idx = btif_hf_idx_by_bdaddr(bd_addr);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800998
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -0700999 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -08001000 {
1001 /* Format the response and send */
1002 memset (&ag_res, 0, sizeof (ag_res));
1003 strncpy(ag_res.str, rsp, BTA_AG_AT_MAX_LEN);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001004 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_UNAT_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001005
1006 return BT_STATUS_SUCCESS;
1007 }
1008
1009 return BT_STATUS_FAIL;
1010}
1011
1012/*******************************************************************************
1013**
1014** Function at_response
1015**
1016** Description ok/error response
1017**
1018** Returns bt_status_t
1019**
1020*******************************************************************************/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001021static bt_status_t at_response(bthf_at_response_t response_code,
1022 int error_code, bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001023{
1024 CHECK_BTHF_INIT();
1025
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001026 int idx = btif_hf_idx_by_bdaddr(bd_addr);
1027
1028 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -08001029 {
1030 send_at_result((response_code == BTHF_AT_RESPONSE_OK) ? BTA_AG_OK_DONE
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001031 : BTA_AG_OK_ERROR, error_code, idx);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001032 return BT_STATUS_SUCCESS;
1033 }
1034
1035
1036 return BT_STATUS_FAIL;
1037}
1038
1039/*******************************************************************************
1040**
1041** Function clcc_response
1042**
1043** Description response for CLCC command
1044** Can be iteratively called for each call index. Call index
1045** of 0 will be treated as NULL termination (Completes response)
1046**
1047** Returns bt_status_t
1048**
1049*******************************************************************************/
1050static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001051 bthf_call_state_t state, bthf_call_mode_t mode,
1052 bthf_call_mpty_type_t mpty, const char *number,
1053 bthf_call_addrtype_t type, bt_bdaddr_t *bd_addr)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001054{
1055 CHECK_BTHF_INIT();
1056
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001057 int idx = btif_hf_idx_by_bdaddr(bd_addr);
1058
1059 if (is_connected(bd_addr) && (idx != BTIF_HF_INVALID_IDX))
The Android Open Source Project5738f832012-12-12 16:00:35 -08001060 {
1061 tBTA_AG_RES_DATA ag_res;
1062 int xx;
1063
1064 memset (&ag_res, 0, sizeof (ag_res));
1065
1066 /* Format the response */
1067 if (index == 0)
1068 {
1069 ag_res.ok_flag = BTA_AG_OK_DONE;
1070 }
1071 else
1072 {
1073 BTIF_TRACE_EVENT6("clcc_response: [%d] dir %d state %d mode %d number = %s type = %d",
1074 index, dir, state, mode, number, type);
1075 xx = sprintf (ag_res.str, "%d,%d,%d,%d,%d",
1076 index, dir, state, mode, mpty);
1077
1078 if (number)
1079 {
1080 if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
1081 sprintf (&ag_res.str[xx], ",\"+%s\",%d", number, type);
1082 else
1083 sprintf (&ag_res.str[xx], ",\"%s\",%d", number, type);
1084 }
1085 }
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001086 BTA_AgResult (btif_hf_cb[idx].handle, BTA_AG_CLCC_RES, &ag_res);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001087
1088 return BT_STATUS_SUCCESS;
1089 }
1090
1091 return BT_STATUS_FAIL;
1092}
1093
1094/*******************************************************************************
1095**
1096** Function phone_state_change
1097**
1098** Description notify of a call state change
1099** number & type: valid only for incoming & waiting call
1100**
1101** Returns bt_status_t
1102**
1103*******************************************************************************/
1104
1105static bt_status_t phone_state_change(int num_active, int num_held, bthf_call_state_t call_setup_state,
1106 const char *number, bthf_call_addrtype_t type)
1107{
1108 tBTA_AG_RES res = 0xff;
1109 tBTA_AG_RES_DATA ag_res;
1110 bt_status_t status = BT_STATUS_SUCCESS;
1111 BOOLEAN activeCallUpdated = FALSE;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001112 int idx, i;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001113
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001114 /* Set idx to index of HF which sent ATA/BLDN else latest connected HF */
1115 idx = (hf_idx == BTIF_HF_INVALID_IDX) ?
1116 btif_hf_latest_connected_idx(): hf_idx;
1117 BTIF_TRACE_DEBUG1("phone_state_change: idx = %d", idx);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001118
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001119 /* Check if SLC is connected */
1120 if (btif_hf_check_if_slc_connected() != BT_STATUS_SUCCESS)
1121 return BT_STATUS_NOT_READY;
1122
1123 BTIF_TRACE_DEBUG6("phone_state_change: num_active=%d [prev: %d] num_held=%d[prev: %d]"
1124 " call_setup=%s [prev: %s]", num_active, btif_hf_cb[idx].num_active,
1125 num_held, btif_hf_cb[idx].num_held, dump_hf_call_state(call_setup_state),
1126 dump_hf_call_state(btif_hf_cb[idx].call_setup_state));
The Android Open Source Project5738f832012-12-12 16:00:35 -08001127
1128 /* if all indicators are 0, send end call and return */
1129 if (num_active == 0 && num_held == 0 && call_setup_state == BTHF_CALL_STATE_IDLE)
1130 {
1131 BTIF_TRACE_DEBUG1("%s: Phone on hook", __FUNCTION__);
1132
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001133 /* record call termination timestamp if there was an active/held call or
1134 callsetup state > BTHF_CALL_STATE_IDLE */
1135 if ((btif_hf_cb[idx].call_setup_state != BTHF_CALL_STATE_IDLE ) ||
1136 (btif_hf_cb[idx].num_active) ||(btif_hf_cb[idx].num_held))
The Android Open Source Project5738f832012-12-12 16:00:35 -08001137 {
1138 BTIF_TRACE_DEBUG1("%s: Record call termination timestamp", __FUNCTION__);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001139 clock_gettime(CLOCK_MONOTONIC, &btif_hf_cb[0].call_end_timestamp);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001140 }
1141 BTA_AgResult (BTA_AG_HANDLE_ALL, BTA_AG_END_CALL_RES, NULL);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001142 hf_idx = BTIF_HF_INVALID_IDX;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001143
1144 /* if held call was present, reset that as well */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001145 if (btif_hf_cb[idx].num_held)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001146 send_indicator_update(BTA_AG_IND_CALLHELD, 0);
1147
1148 goto update_call_states;
1149 }
1150
1151 /* active state can change when:
1152 ** 1. an outgoing/incoming call was answered
1153 ** 2. an held was resumed
1154 ** 3. without callsetup notifications, call became active
1155 ** (3) can happen if call is active and a headset connects to us
1156 **
1157 ** In the case of (3), we will have to notify the stack of an active
1158 ** call, instead of sending an indicator update. This will also
1159 ** force the SCO to be setup. Handle this special case here prior to
1160 ** call setup handling
1161 */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001162 if ( (num_active == 1) && (btif_hf_cb[idx].num_active == 0) && (btif_hf_cb[idx].num_held == 0)
1163 && (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE) )
The Android Open Source Project5738f832012-12-12 16:00:35 -08001164 {
1165 BTIF_TRACE_DEBUG1("%s: Active call notification received without call setup update",
1166 __FUNCTION__);
1167
1168 memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001169 ag_res.audio_handle = btif_hf_cb[idx].handle;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001170 res = BTA_AG_OUT_CALL_CONN_RES;
1171 BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
1172 activeCallUpdated = TRUE;
1173 }
1174
1175 /* Ringing call changed? */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001176 if (call_setup_state != btif_hf_cb[idx].call_setup_state)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001177 {
1178 BTIF_TRACE_DEBUG3("%s: Call setup states changed. old: %s new: %s",
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001179 __FUNCTION__, dump_hf_call_state(btif_hf_cb[idx].call_setup_state),
The Android Open Source Project5738f832012-12-12 16:00:35 -08001180 dump_hf_call_state(call_setup_state));
1181 memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
1182
1183 switch (call_setup_state)
1184 {
1185 case BTHF_CALL_STATE_IDLE:
1186 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001187 switch (btif_hf_cb[idx].call_setup_state)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001188 {
1189 case BTHF_CALL_STATE_INCOMING:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001190 if (num_active > btif_hf_cb[idx].num_active)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001191 {
1192 res = BTA_AG_IN_CALL_CONN_RES;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001193 ag_res.audio_handle = btif_hf_cb[idx].handle;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001194 }
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001195 else if (num_held > btif_hf_cb[idx].num_held)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001196 res = BTA_AG_IN_CALL_HELD_RES;
1197 else
1198 res = BTA_AG_CALL_CANCEL_RES;
1199 break;
1200 case BTHF_CALL_STATE_DIALING:
1201 case BTHF_CALL_STATE_ALERTING:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001202 if (num_active > btif_hf_cb[idx].num_active)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001203 {
1204 ag_res.audio_handle = BTA_AG_HANDLE_SCO_NO_CHANGE;
1205 res = BTA_AG_OUT_CALL_CONN_RES;
1206 }
1207 else
1208 res = BTA_AG_CALL_CANCEL_RES;
1209 break;
1210 default:
1211 BTIF_TRACE_ERROR1("%s: Incorrect Call setup state transition", __FUNCTION__);
1212 status = BT_STATUS_PARM_INVALID;
1213 break;
1214 }
1215 } break;
1216
1217 case BTHF_CALL_STATE_INCOMING:
1218 if (num_active || num_held)
1219 res = BTA_AG_CALL_WAIT_RES;
1220 else
1221 res = BTA_AG_IN_CALL_RES;
1222 if (number)
1223 {
1224 int xx = 0;
1225 if ((type == BTHF_CALL_ADDRTYPE_INTERNATIONAL) && (*number != '+'))
1226 xx = sprintf (ag_res.str, "\"+%s\"", number);
1227 else
1228 xx = sprintf (ag_res.str, "\"%s\"", number);
1229 ag_res.num = type;
1230
1231 if (res == BTA_AG_CALL_WAIT_RES)
1232 sprintf(&ag_res.str[xx], ",%d", type);
1233 }
1234 break;
1235 case BTHF_CALL_STATE_DIALING:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001236 ag_res.audio_handle = btif_hf_cb[idx].handle;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001237 res = BTA_AG_OUT_CALL_ORIG_RES;
1238 break;
1239 case BTHF_CALL_STATE_ALERTING:
1240 /* if we went from idle->alert, force SCO setup here. dialing usually triggers it */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001241 if (btif_hf_cb[idx].call_setup_state == BTHF_CALL_STATE_IDLE)
1242 ag_res.audio_handle = btif_hf_cb[idx].handle;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001243 res = BTA_AG_OUT_CALL_ALERT_RES;
1244 break;
1245 default:
1246 BTIF_TRACE_ERROR1("%s: Incorrect new ringing call state", __FUNCTION__);
1247 status = BT_STATUS_PARM_INVALID;
1248 break;
1249 }
1250 BTIF_TRACE_DEBUG3("%s: Call setup state changed. res=%d, audio_handle=%d", __FUNCTION__, res, ag_res.audio_handle);
1251
1252 if (res)
1253 BTA_AgResult(BTA_AG_HANDLE_ALL, res, &ag_res);
1254
1255 /* if call setup is idle, we have already updated call indicator, jump out */
1256 if (call_setup_state == BTHF_CALL_STATE_IDLE)
1257 {
1258 /* check & update callheld */
1259 if ((num_held > 0) && (num_active > 0))
1260 send_indicator_update(BTA_AG_IND_CALLHELD, 1);
1261 goto update_call_states;
1262 }
1263 }
1264
1265 memset(&ag_res, 0, sizeof(tBTA_AG_RES_DATA));
1266
1267 /* per the errata 2043, call=1 implies atleast one call is in progress (active/held)
1268 ** https://www.bluetooth.org/errata/errata_view.cfm?errata_id=2043
1269 ** Handle call indicator change
1270 **/
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001271 if (!activeCallUpdated && ((num_active + num_held) !=
1272 (btif_hf_cb[idx].num_active + btif_hf_cb[idx].num_held)) )
The Android Open Source Project5738f832012-12-12 16:00:35 -08001273 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001274 BTIF_TRACE_DEBUG3("%s: Active call states changed. old: %d new: %d", __FUNCTION__, btif_hf_cb[idx].num_active, num_active);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001275 send_indicator_update(BTA_AG_IND_CALL, ((num_active + num_held) > 0) ? 1 : 0);
1276 }
1277
1278 /* Held Changed? */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001279 if (num_held != btif_hf_cb[idx].num_held)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001280 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001281 BTIF_TRACE_DEBUG3("%s: Held call states changed. old: %d new: %d",
1282 __FUNCTION__, btif_hf_cb[idx].num_held, num_held);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001283 send_indicator_update(BTA_AG_IND_CALLHELD, ((num_held == 0) ? 0 : ((num_active == 0) ? 2 : 1)));
1284 }
1285
1286 /* Calls Swapped? */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001287 if ( (call_setup_state == btif_hf_cb[idx].call_setup_state) &&
The Android Open Source Project5738f832012-12-12 16:00:35 -08001288 (num_active && num_held) &&
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001289 (num_active == btif_hf_cb[idx].num_active) &&
1290 (num_held == btif_hf_cb[idx].num_held) )
The Android Open Source Project5738f832012-12-12 16:00:35 -08001291 {
1292 BTIF_TRACE_DEBUG1("%s: Calls swapped", __FUNCTION__);
1293 send_indicator_update(BTA_AG_IND_CALLHELD, 1);
1294 }
1295
1296update_call_states:
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001297 for (i = 0; i < btif_max_hf_clients; i++)
1298 {
1299 btif_hf_cb[i].num_active = num_active;
1300 btif_hf_cb[i].num_held = num_held;
1301 btif_hf_cb[i].call_setup_state = call_setup_state;
1302 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001303 return status;
1304}
1305
1306
1307/*******************************************************************************
1308**
1309** Function btif_hf_call_terminated_recently
1310**
1311** Description Checks if a call has been terminated
1312**
1313** Returns bt_status_t
1314**
1315*******************************************************************************/
1316BOOLEAN btif_hf_call_terminated_recently()
1317{
1318 struct timespec now;
1319
1320 clock_gettime(CLOCK_MONOTONIC, &now);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001321 if (now.tv_sec < btif_hf_cb[0].call_end_timestamp.tv_sec +
1322 BTIF_HF_CALL_END_TIMEOUT)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001323 {
1324 return TRUE;
1325 }
1326 else
1327 {
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001328 btif_hf_cb[0].call_end_timestamp.tv_sec = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001329 return FALSE;
1330 }
1331}
1332
1333/*******************************************************************************
1334**
1335** Function cleanup
1336**
1337** Description Closes the HF interface
1338**
1339** Returns bt_status_t
1340**
1341*******************************************************************************/
1342static void cleanup( void )
1343{
1344 BTIF_TRACE_EVENT1("%s", __FUNCTION__);
1345
1346 if (bt_hf_callbacks)
1347 {
1348 btif_disable_service(BTA_HFP_SERVICE_ID);
1349 bt_hf_callbacks = NULL;
1350 }
1351}
1352
1353static const bthf_interface_t bthfInterface = {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001354 sizeof(bthfInterface),
The Android Open Source Project5738f832012-12-12 16:00:35 -08001355 init,
1356 connect,
1357 disconnect,
1358 connect_audio,
1359 disconnect_audio,
1360 start_voice_recognition,
1361 stop_voice_recognition,
1362 volume_control,
1363 device_status_notification,
1364 cops_response,
1365 cind_response,
1366 formatted_at_response,
1367 at_response,
1368 clcc_response,
1369 phone_state_change,
1370 cleanup,
1371};
1372
1373/*******************************************************************************
1374**
1375** Function btif_hf_execute_service
1376**
1377** Description Initializes/Shuts down the service
1378**
1379** Returns BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
1380**
1381*******************************************************************************/
1382bt_status_t btif_hf_execute_service(BOOLEAN b_enable)
1383{
1384 char * p_service_names[] = BTIF_HF_SERVICE_NAMES;
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001385 int i;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001386 if (b_enable)
1387 {
1388 /* Enable and register with BTA-AG */
1389 BTA_AgEnable (BTA_AG_PARSE, bte_hf_evt);
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001390 for (i = 0; i < btif_max_hf_clients; i++)
1391 {
1392 BTA_AgRegister(BTIF_HF_SERVICES, BTIF_HF_SECURITY,
1393 BTIF_HF_FEATURES, p_service_names, bthf_hf_id[i]);
1394 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001395 }
1396 else {
1397 /* De-register AG */
Nitin Srivastava2cb90bc2014-03-14 16:19:58 -07001398 for (i = 0; i < btif_max_hf_clients; i++)
1399 {
1400 BTA_AgDeregister(btif_hf_cb[i].handle);
1401 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001402 /* Disable AG */
1403 BTA_AgDisable();
1404 }
1405 return BT_STATUS_SUCCESS;
1406}
1407
1408/*******************************************************************************
1409**
1410** Function btif_hf_get_interface
1411**
1412** Description Get the hf callback interface
1413**
1414** Returns bthf_interface_t
1415**
1416*******************************************************************************/
1417const bthf_interface_t *btif_hf_get_interface()
1418{
1419 BTIF_TRACE_EVENT1("%s", __FUNCTION__);
1420 return &bthfInterface;
1421}