1 /******************************************************************************
3 * Copyright (c) 2014 The Android Open Source Project
4 * Copyright 2004-2012 Broadcom Corporation
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 ******************************************************************************/
23 #include "bta_ag_api.h"
24 #include "bta_hf_client_api.h"
25 #include "bta_hf_client_int.h"
26 #include "device/include/esco_parameters.h"
27 #include "osi/include/osi.h"
28 #include "stack/include/btm_api.h"
30 #define BTA_HF_CLIENT_NO_EDR_ESCO \
31 (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
32 ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
35 BTA_HF_CLIENT_SCO_LISTEN_E,
36 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
37 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
38 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
39 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* SCO opened */
40 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
43 /*******************************************************************************
45 * Function bta_hf_client_remove_sco
47 * Description Removes the specified SCO from the system.
49 * Returns bool - true if SCO removal was started
51 ******************************************************************************/
52 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
53 bool removed_started = false;
56 APPL_TRACE_DEBUG("%s", __func__);
58 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
59 status = BTM_RemoveSco(client_cb->sco_idx);
61 APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__,
62 client_cb->sco_idx, status);
64 if (status == BTM_CMD_STARTED) {
65 removed_started = true;
67 /* If no connection reset the SCO handle */
68 else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
69 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
72 return removed_started;
75 /*******************************************************************************
77 * Function bta_hf_client_cback_sco
79 * Description Call application callback function with SCO event.
84 ******************************************************************************/
85 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
88 memset(&evt, 0, sizeof(evt));
89 evt.bd_addr = client_cb->peer_addr;
92 bta_hf_client_app_callback(event, &evt);
95 /*******************************************************************************
97 * Function bta_hf_client_sco_conn_rsp
99 * Description Process the SCO connection request
104 ******************************************************************************/
105 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
106 tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
107 enh_esco_params_t resp;
108 uint8_t hci_status = HCI_SUCCESS;
110 APPL_TRACE_DEBUG("%s", __func__);
112 if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
113 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
115 resp = esco_parameters_for_codec(SCO_CODEC_CVSD_D1);
116 } else if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC) {
118 resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
119 } else if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) {
120 // eSCO CVSD, HFP 1.7 requires S4
121 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4);
123 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
124 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3);
127 /* tell sys to stop av if any */
128 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
130 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
133 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
136 /*******************************************************************************
138 * Function bta_hf_client_sco_connreq_cback
140 * Description BTM eSCO connection requests and eSCO change requests
141 * Only the connection requests are processed by BTA.
145 ******************************************************************************/
146 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
147 tBTM_ESCO_EVT_DATA* p_data) {
148 APPL_TRACE_DEBUG("%s: %d", __func__, event);
150 tBTA_HF_CLIENT_CB* client_cb =
151 bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
152 if (client_cb == NULL) {
153 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
154 p_data->conn_evt.sco_inx);
158 if (event != BTM_ESCO_CONN_REQ_EVT) {
162 bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
164 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
167 /*******************************************************************************
169 * Function bta_hf_client_sco_conn_cback
171 * Description BTM SCO connection callback.
176 ******************************************************************************/
177 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
178 APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx);
180 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
181 if (client_cb == NULL) {
182 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
187 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
188 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
189 p_buf->layer_specific = client_cb->handle;
190 bta_sys_sendmsg(p_buf);
193 /*******************************************************************************
195 * Function bta_hf_client_sco_disc_cback
197 * Description BTM SCO disconnection callback.
202 ******************************************************************************/
203 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
204 APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx);
206 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
207 if (client_cb == NULL) {
208 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx);
212 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
213 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
214 p_buf->layer_specific = client_cb->handle;
215 bta_sys_sendmsg(p_buf);
218 /*******************************************************************************
220 * Function bta_hf_client_create_sco
227 ******************************************************************************/
228 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
232 APPL_TRACE_DEBUG("%s: %d", __func__, is_orig);
234 /* Make sure this SCO handle is not already in use */
235 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
236 APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
242 enh_esco_params_t params;
243 // Since HF device is not expected to receive AT+BAC send +BCS command,
244 // codec support of the connected AG device will be unknown,
245 // so HF device will always establish only CVSD connection.
246 if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) &&
247 (client_cb->peer_features & BTA_HF_CLIENT_PEER_ESCO_S4)) {
248 // eSCO CVSD, HFP 1.7 requires S4
249 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4);
251 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
252 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3);
255 /* if initiating set current scb and peer bd addr */
257 BTM_SetEScoMode(¶ms);
258 /* tell sys to stop av if any */
259 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
262 status = BTM_CreateSco(&client_cb->peer_addr, is_orig, params.packet_types,
263 &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
264 bta_hf_client_sco_disc_cback);
265 if (status == BTM_CMD_STARTED && !is_orig) {
266 if (!BTM_RegForEScoEvts(client_cb->sco_idx,
267 bta_hf_client_esco_connreq_cback))
268 APPL_TRACE_DEBUG("%s: SCO registration success", __func__);
271 APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
272 __func__, is_orig, client_cb->sco_idx, status,
273 params.packet_types);
276 /*******************************************************************************
278 * Function bta_hf_client_sco_event
280 * Description Handle SCO events
285 ******************************************************************************/
286 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
288 APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__,
289 client_cb->sco_state, event);
291 switch (client_cb->sco_state) {
292 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
294 // For WBS we only listen to SCO requests. Even for outgoing SCO
295 // requests we first do a AT+BCC and wait for remote to initiate SCO
296 case BTA_HF_CLIENT_SCO_LISTEN_E:
297 /* create SCO listen connection */
298 bta_hf_client_sco_create(client_cb, false);
299 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
302 // For non WBS cases and enabling outgoing SCO requests we need to force
303 // open a SCO channel
304 case BTA_HF_CLIENT_SCO_OPEN_E:
305 /* remove listening connection */
306 bta_hf_client_sco_remove(client_cb);
308 /* create SCO connection to peer */
309 bta_hf_client_sco_create(client_cb, true);
310 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
314 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
320 case BTA_HF_CLIENT_SCO_LISTEN_ST:
322 case BTA_HF_CLIENT_SCO_LISTEN_E:
323 /* create SCO listen connection */
324 bta_hf_client_sco_create(client_cb, false);
327 case BTA_HF_CLIENT_SCO_OPEN_E:
328 /* remove listening connection */
329 bta_hf_client_sco_remove(client_cb);
331 /* create SCO connection to peer */
332 bta_hf_client_sco_create(client_cb, true);
333 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
336 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
337 case BTA_HF_CLIENT_SCO_CLOSE_E:
338 /* remove listening connection */
339 bta_hf_client_sco_remove(client_cb);
341 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
344 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
345 /* SCO failed; create SCO listen connection */
346 bta_hf_client_sco_create(client_cb, false);
347 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
352 "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
358 case BTA_HF_CLIENT_SCO_OPENING_ST:
360 case BTA_HF_CLIENT_SCO_CLOSE_E:
361 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
364 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
365 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
368 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
369 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
372 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
373 /* SCO failed; create SCO listen connection */
374 bta_hf_client_sco_create(client_cb, false);
375 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
379 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
385 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
387 case BTA_HF_CLIENT_SCO_OPEN_E:
388 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
391 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
392 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
395 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
396 /* close SCO connection */
397 bta_hf_client_sco_remove(client_cb);
399 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
402 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
403 /* SCO failed; create SCO listen connection */
405 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
409 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
415 case BTA_HF_CLIENT_SCO_OPEN_ST:
417 case BTA_HF_CLIENT_SCO_CLOSE_E:
418 if (bta_hf_client_sco_remove(client_cb)) {
419 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
423 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
424 /* remove listening connection */
425 bta_hf_client_sco_remove(client_cb);
427 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
430 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
431 /* peer closed SCO */
432 bta_hf_client_sco_create(client_cb, false);
433 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
437 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
443 case BTA_HF_CLIENT_SCO_CLOSING_ST:
445 case BTA_HF_CLIENT_SCO_OPEN_E:
446 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
449 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
450 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
453 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
454 /* peer closed sco; create SCO listen connection */
455 bta_hf_client_sco_create(client_cb, false);
456 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
460 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
466 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
468 case BTA_HF_CLIENT_SCO_CLOSE_E:
469 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
472 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
473 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
476 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
477 /* open SCO connection */
478 bta_hf_client_sco_create(client_cb, true);
479 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
483 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
489 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
491 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
492 /* close SCO connection; wait for conn close event */
493 bta_hf_client_sco_remove(client_cb);
496 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
497 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
500 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
501 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
505 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
515 APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
518 /*******************************************************************************
520 * Function bta_hf_client_sco_listen
522 * Description Initialize SCO listener
527 ******************************************************************************/
528 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
529 APPL_TRACE_DEBUG("%s", __func__);
531 tBTA_HF_CLIENT_CB* client_cb =
532 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
533 if (client_cb == NULL) {
534 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
535 p_data->hdr.layer_specific);
539 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
542 /*******************************************************************************
544 * Function bta_hf_client_sco_shutdown
551 ******************************************************************************/
552 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
553 APPL_TRACE_DEBUG("%s", __func__);
555 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
558 /*******************************************************************************
560 * Function bta_hf_client_sco_conn_open
567 ******************************************************************************/
568 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
569 APPL_TRACE_DEBUG("%s", __func__);
571 tBTA_HF_CLIENT_CB* client_cb =
572 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
573 if (client_cb == NULL) {
574 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
575 p_data->hdr.layer_specific);
579 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
581 bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
583 if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
584 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
586 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
590 /*******************************************************************************
592 * Function bta_hf_client_sco_conn_close
599 ******************************************************************************/
600 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
601 APPL_TRACE_DEBUG("%s", __func__);
603 tBTA_HF_CLIENT_CB* client_cb =
604 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
605 if (client_cb == NULL) {
606 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
607 p_data->hdr.layer_specific);
611 /* clear current scb */
612 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
614 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
616 bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
618 bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
620 /* call app callback */
621 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
623 if (client_cb->sco_close_rfc) {
624 client_cb->sco_close_rfc = false;
625 bta_hf_client_rfc_do_close(p_data);
629 /*******************************************************************************
631 * Function bta_hf_client_sco_open
638 ******************************************************************************/
639 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
640 APPL_TRACE_DEBUG("%s", __func__);
642 tBTA_HF_CLIENT_CB* client_cb =
643 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
644 if (client_cb == NULL) {
645 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
646 p_data->hdr.layer_specific);
650 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
653 /*******************************************************************************
655 * Function bta_hf_client_sco_close
662 ******************************************************************************/
663 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
664 tBTA_HF_CLIENT_CB* client_cb =
665 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
666 if (client_cb == NULL) {
667 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
668 p_data->hdr.layer_specific);
672 APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
674 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
675 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);