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_int.h"
25 #include "device/include/esco_parameters.h"
26 #include "osi/include/osi.h"
27 #include "stack/include/btm_api.h"
29 #define BTA_HF_CLIENT_NO_EDR_ESCO \
30 (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
31 ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
34 BTA_HF_CLIENT_SCO_LISTEN_E,
35 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
36 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
37 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
38 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* SCO opened */
39 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
42 /*******************************************************************************
44 * Function bta_hf_client_remove_sco
46 * Description Removes the specified SCO from the system.
48 * Returns bool - true if SCO removal was started
50 ******************************************************************************/
51 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
52 bool removed_started = false;
55 APPL_TRACE_DEBUG("%s", __func__);
57 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
58 status = BTM_RemoveSco(client_cb->sco_idx);
60 APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__,
61 client_cb->sco_idx, status);
63 if (status == BTM_CMD_STARTED) {
64 removed_started = true;
66 /* If no connection reset the SCO handle */
67 else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
68 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
71 return removed_started;
74 /*******************************************************************************
76 * Function bta_hf_client_cback_sco
78 * Description Call application callback function with SCO event.
83 ******************************************************************************/
84 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
87 memset(&evt, 0, sizeof(evt));
88 evt.bd_addr = client_cb->peer_addr;
91 bta_hf_client_app_callback(event, &evt);
94 /*******************************************************************************
96 * Function bta_hf_client_sco_conn_rsp
98 * Description Process the SCO connection request
103 ******************************************************************************/
104 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
105 tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
106 enh_esco_params_t resp;
107 uint8_t hci_status = HCI_SUCCESS;
109 APPL_TRACE_DEBUG("%s", __func__);
111 if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
112 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
113 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
115 if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC) {
116 resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
119 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
123 /* tell sys to stop av if any */
124 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
126 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
129 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
132 /*******************************************************************************
134 * Function bta_hf_client_sco_connreq_cback
136 * Description BTM eSCO connection requests and eSCO change requests
137 * Only the connection requests are processed by BTA.
141 ******************************************************************************/
142 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
143 tBTM_ESCO_EVT_DATA* p_data) {
144 APPL_TRACE_DEBUG("%s: %d", __func__, event);
146 tBTA_HF_CLIENT_CB* client_cb =
147 bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
148 if (client_cb == NULL) {
149 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
150 p_data->conn_evt.sco_inx);
154 if (event != BTM_ESCO_CONN_REQ_EVT) {
158 bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
160 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
163 /*******************************************************************************
165 * Function bta_hf_client_sco_conn_cback
167 * Description BTM SCO connection callback.
172 ******************************************************************************/
173 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
174 APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx);
176 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
177 if (client_cb == NULL) {
178 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
183 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
184 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
185 p_buf->layer_specific = client_cb->handle;
186 bta_sys_sendmsg(p_buf);
189 /*******************************************************************************
191 * Function bta_hf_client_sco_disc_cback
193 * Description BTM SCO disconnection callback.
198 ******************************************************************************/
199 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
200 APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx);
202 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
203 if (client_cb == NULL) {
204 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx);
208 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
209 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
210 p_buf->layer_specific = client_cb->handle;
211 bta_sys_sendmsg(p_buf);
214 /*******************************************************************************
216 * Function bta_hf_client_create_sco
223 ******************************************************************************/
224 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
228 APPL_TRACE_DEBUG("%s: %d", __func__, is_orig);
230 /* Make sure this SCO handle is not already in use */
231 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
232 APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
237 enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
239 /* if initiating set current scb and peer bd addr */
241 BTM_SetEScoMode(¶ms);
242 /* tell sys to stop av if any */
243 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
246 status = BTM_CreateSco(&client_cb->peer_addr, is_orig, params.packet_types,
247 &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
248 bta_hf_client_sco_disc_cback);
249 if (status == BTM_CMD_STARTED && !is_orig) {
250 if (!BTM_RegForEScoEvts(client_cb->sco_idx,
251 bta_hf_client_esco_connreq_cback))
252 APPL_TRACE_DEBUG("%s: SCO registration success", __func__);
255 APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
256 __func__, is_orig, client_cb->sco_idx, status,
257 params.packet_types);
260 /*******************************************************************************
262 * Function bta_hf_client_sco_event
264 * Description Handle SCO events
269 ******************************************************************************/
270 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
272 APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__,
273 client_cb->sco_state, event);
275 switch (client_cb->sco_state) {
276 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
278 // For WBS we only listen to SCO requests. Even for outgoing SCO
279 // requests we first do a AT+BCC and wait for remote to initiate SCO
280 case BTA_HF_CLIENT_SCO_LISTEN_E:
281 /* create SCO listen connection */
282 bta_hf_client_sco_create(client_cb, false);
283 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
286 // For non WBS cases and enabling outgoing SCO requests we need to force
287 // open a SCO channel
288 case BTA_HF_CLIENT_SCO_OPEN_E:
289 /* remove listening connection */
290 bta_hf_client_sco_remove(client_cb);
292 /* create SCO connection to peer */
293 bta_hf_client_sco_create(client_cb, true);
294 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
298 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
304 case BTA_HF_CLIENT_SCO_LISTEN_ST:
306 case BTA_HF_CLIENT_SCO_LISTEN_E:
307 /* create SCO listen connection */
308 bta_hf_client_sco_create(client_cb, false);
311 case BTA_HF_CLIENT_SCO_OPEN_E:
312 /* remove listening connection */
313 bta_hf_client_sco_remove(client_cb);
315 /* create SCO connection to peer */
316 bta_hf_client_sco_create(client_cb, true);
317 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
320 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
321 case BTA_HF_CLIENT_SCO_CLOSE_E:
322 /* remove listening connection */
323 bta_hf_client_sco_remove(client_cb);
325 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
328 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
329 /* SCO failed; create SCO listen connection */
330 bta_hf_client_sco_create(client_cb, false);
331 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
336 "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
342 case BTA_HF_CLIENT_SCO_OPENING_ST:
344 case BTA_HF_CLIENT_SCO_CLOSE_E:
345 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
348 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
349 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
352 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
353 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
356 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
357 /* SCO failed; create SCO listen connection */
358 bta_hf_client_sco_create(client_cb, false);
359 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
363 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
369 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
371 case BTA_HF_CLIENT_SCO_OPEN_E:
372 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
375 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
376 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
379 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
380 /* close SCO connection */
381 bta_hf_client_sco_remove(client_cb);
383 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
386 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
387 /* SCO failed; create SCO listen connection */
389 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
393 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
399 case BTA_HF_CLIENT_SCO_OPEN_ST:
401 case BTA_HF_CLIENT_SCO_CLOSE_E:
402 if (bta_hf_client_sco_remove(client_cb)) {
403 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
407 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
408 /* remove listening connection */
409 bta_hf_client_sco_remove(client_cb);
411 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
414 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
415 /* peer closed SCO */
416 bta_hf_client_sco_create(client_cb, false);
417 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
421 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
427 case BTA_HF_CLIENT_SCO_CLOSING_ST:
429 case BTA_HF_CLIENT_SCO_OPEN_E:
430 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
433 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
434 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
437 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
438 /* peer closed sco; create SCO listen connection */
439 bta_hf_client_sco_create(client_cb, false);
440 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
444 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
450 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
452 case BTA_HF_CLIENT_SCO_CLOSE_E:
453 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
456 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
457 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
460 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
461 /* open SCO connection */
462 bta_hf_client_sco_create(client_cb, true);
463 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
467 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
473 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
475 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
476 /* close SCO connection; wait for conn close event */
477 bta_hf_client_sco_remove(client_cb);
480 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
481 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
484 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
485 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
489 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
499 APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
502 /*******************************************************************************
504 * Function bta_hf_client_sco_listen
506 * Description Initialize SCO listener
511 ******************************************************************************/
512 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
513 APPL_TRACE_DEBUG("%s", __func__);
515 tBTA_HF_CLIENT_CB* client_cb =
516 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
517 if (client_cb == NULL) {
518 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
519 p_data->hdr.layer_specific);
523 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
526 /*******************************************************************************
528 * Function bta_hf_client_sco_shutdown
535 ******************************************************************************/
536 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
537 APPL_TRACE_DEBUG("%s", __func__);
539 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
542 /*******************************************************************************
544 * Function bta_hf_client_sco_conn_open
551 ******************************************************************************/
552 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
553 APPL_TRACE_DEBUG("%s", __func__);
555 tBTA_HF_CLIENT_CB* client_cb =
556 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
557 if (client_cb == NULL) {
558 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
559 p_data->hdr.layer_specific);
563 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
565 bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
567 if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
568 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
570 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
574 /*******************************************************************************
576 * Function bta_hf_client_sco_conn_close
583 ******************************************************************************/
584 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
585 APPL_TRACE_DEBUG("%s", __func__);
587 tBTA_HF_CLIENT_CB* client_cb =
588 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
589 if (client_cb == NULL) {
590 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
591 p_data->hdr.layer_specific);
595 /* clear current scb */
596 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
598 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
600 bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
602 bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
604 /* call app callback */
605 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
607 if (client_cb->sco_close_rfc) {
608 client_cb->sco_close_rfc = false;
609 bta_hf_client_rfc_do_close(p_data);
613 /*******************************************************************************
615 * Function bta_hf_client_sco_open
622 ******************************************************************************/
623 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
624 APPL_TRACE_DEBUG("%s", __func__);
626 tBTA_HF_CLIENT_CB* client_cb =
627 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
628 if (client_cb == NULL) {
629 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
630 p_data->hdr.layer_specific);
634 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
637 /*******************************************************************************
639 * Function bta_hf_client_sco_close
646 ******************************************************************************/
647 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
648 tBTA_HF_CLIENT_CB* client_cb =
649 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
650 if (client_cb == NULL) {
651 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
652 p_data->hdr.layer_specific);
656 APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
658 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
659 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);