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"
28 #define BTA_HF_CLIENT_NO_EDR_ESCO \
29 (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | \
30 ESCO_PKT_TYPES_MASK_NO_2_EV5 | ESCO_PKT_TYPES_MASK_NO_3_EV5)
33 BTA_HF_CLIENT_SCO_LISTEN_E,
34 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
35 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
36 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
37 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* SCO opened */
38 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
41 /*******************************************************************************
43 * Function bta_hf_client_remove_sco
45 * Description Removes the specified SCO from the system.
47 * Returns bool - true if SCO removal was started
49 ******************************************************************************/
50 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
51 bool removed_started = false;
54 APPL_TRACE_DEBUG("%s", __func__);
56 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
57 status = BTM_RemoveSco(client_cb->sco_idx);
59 APPL_TRACE_DEBUG("%s: idx 0x%04x, status:0x%x", __func__,
60 client_cb->sco_idx, status);
62 if (status == BTM_CMD_STARTED) {
63 removed_started = true;
65 /* If no connection reset the SCO handle */
66 else if ((status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR)) {
67 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
70 return removed_started;
73 /*******************************************************************************
75 * Function bta_hf_client_cback_sco
77 * Description Call application callback function with SCO event.
82 ******************************************************************************/
83 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
86 memset(&evt, 0, sizeof(evt));
87 evt.bd_addr = client_cb->peer_addr;
90 bta_hf_client_app_callback(event, &evt);
93 /*******************************************************************************
95 * Function bta_hf_client_sco_conn_rsp
97 * Description Process the SCO connection request
102 ******************************************************************************/
103 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
104 tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
105 enh_esco_params_t resp;
106 uint8_t hci_status = HCI_SUCCESS;
108 APPL_TRACE_DEBUG("%s", __func__);
110 if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
111 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
112 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
114 if (client_cb->negotiated_codec == BTA_AG_CODEC_MSBC) {
115 resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2);
118 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD);
122 /* tell sys to stop av if any */
123 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
125 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
128 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
131 /*******************************************************************************
133 * Function bta_hf_client_sco_connreq_cback
135 * Description BTM eSCO connection requests and eSCO change requests
136 * Only the connection requests are processed by BTA.
140 ******************************************************************************/
141 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,
142 tBTM_ESCO_EVT_DATA* p_data) {
143 APPL_TRACE_DEBUG("%s: %d", __func__, event);
145 tBTA_HF_CLIENT_CB* client_cb =
146 bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
147 if (client_cb == NULL) {
148 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
149 p_data->conn_evt.sco_inx);
153 if (event != BTM_ESCO_CONN_REQ_EVT) {
157 bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
159 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
162 /*******************************************************************************
164 * Function bta_hf_client_sco_conn_cback
166 * Description BTM SCO connection callback.
171 ******************************************************************************/
172 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
173 APPL_TRACE_DEBUG("%s: %d", __func__, sco_idx);
175 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
176 if (client_cb == NULL) {
177 APPL_TRACE_ERROR("%s: wrong SCO handle to control block %d", __func__,
182 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
183 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
184 p_buf->layer_specific = client_cb->handle;
185 bta_sys_sendmsg(p_buf);
188 /*******************************************************************************
190 * Function bta_hf_client_sco_disc_cback
192 * Description BTM SCO disconnection callback.
197 ******************************************************************************/
198 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
199 APPL_TRACE_DEBUG("%s: sco_idx %d", __func__, sco_idx);
201 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
202 if (client_cb == NULL) {
203 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__, sco_idx);
207 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR));
208 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
209 p_buf->layer_specific = client_cb->handle;
210 bta_sys_sendmsg(p_buf);
213 /*******************************************************************************
215 * Function bta_hf_client_create_sco
222 ******************************************************************************/
223 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb,
227 APPL_TRACE_DEBUG("%s: %d", __func__, is_orig);
229 /* Make sure this SCO handle is not already in use */
230 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
231 APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __func__,
236 enh_esco_params_t params = esco_parameters_for_codec(ESCO_CODEC_CVSD);
238 /* if initiating set current scb and peer bd addr */
240 BTM_SetEScoMode(¶ms);
241 /* tell sys to stop av if any */
242 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
245 status = BTM_CreateSco(&client_cb->peer_addr, is_orig, params.packet_types,
246 &client_cb->sco_idx, bta_hf_client_sco_conn_cback,
247 bta_hf_client_sco_disc_cback);
248 if (status == BTM_CMD_STARTED && !is_orig) {
249 if (!BTM_RegForEScoEvts(client_cb->sco_idx,
250 bta_hf_client_esco_connreq_cback))
251 APPL_TRACE_DEBUG("%s: SCO registration success", __func__);
254 APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
255 __func__, is_orig, client_cb->sco_idx, status,
256 params.packet_types);
259 /*******************************************************************************
261 * Function bta_hf_client_sco_event
263 * Description Handle SCO events
268 ******************************************************************************/
269 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb,
271 APPL_TRACE_DEBUG("%s: before state: %d event: %d", __func__,
272 client_cb->sco_state, event);
274 switch (client_cb->sco_state) {
275 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
277 // For WBS we only listen to SCO requests. Even for outgoing SCO
278 // requests we first do a AT+BCC and wait for remote to initiate SCO
279 case BTA_HF_CLIENT_SCO_LISTEN_E:
280 /* create SCO listen connection */
281 bta_hf_client_sco_create(client_cb, false);
282 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
285 // For non WBS cases and enabling outgoing SCO requests we need to force
286 // open a SCO channel
287 case BTA_HF_CLIENT_SCO_OPEN_E:
288 /* remove listening connection */
289 bta_hf_client_sco_remove(client_cb);
291 /* create SCO connection to peer */
292 bta_hf_client_sco_create(client_cb, true);
293 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
297 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d",
303 case BTA_HF_CLIENT_SCO_LISTEN_ST:
305 case BTA_HF_CLIENT_SCO_LISTEN_E:
306 /* create SCO listen connection */
307 bta_hf_client_sco_create(client_cb, false);
309 case BTA_HF_CLIENT_SCO_OPEN_E:
310 /* remove listening connection */
311 bta_hf_client_sco_remove(client_cb);
313 /* create SCO connection to peer */
314 bta_hf_client_sco_create(client_cb, true);
315 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
318 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
319 case BTA_HF_CLIENT_SCO_CLOSE_E:
320 /* remove listening connection */
321 bta_hf_client_sco_remove(client_cb);
323 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
326 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
327 /* SCO failed; create SCO listen connection */
328 bta_hf_client_sco_create(client_cb, false);
329 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
334 "%s: BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", __func__,
340 case BTA_HF_CLIENT_SCO_OPENING_ST:
342 case BTA_HF_CLIENT_SCO_CLOSE_E:
343 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
346 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
347 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
350 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
351 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
354 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
355 /* SCO failed; create SCO listen connection */
356 bta_hf_client_sco_create(client_cb, false);
357 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
361 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d",
367 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
369 case BTA_HF_CLIENT_SCO_OPEN_E:
370 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
373 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
374 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
377 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
378 /* close SCO connection */
379 bta_hf_client_sco_remove(client_cb);
381 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
384 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
385 /* SCO failed; create SCO listen connection */
387 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
391 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d",
397 case BTA_HF_CLIENT_SCO_OPEN_ST:
399 case BTA_HF_CLIENT_SCO_CLOSE_E:
400 if (bta_hf_client_sco_remove(client_cb)) {
401 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
405 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
406 /* remove listening connection */
407 bta_hf_client_sco_remove(client_cb);
409 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
412 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
413 /* peer closed SCO */
414 bta_hf_client_sco_create(client_cb, false);
415 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
419 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d",
425 case BTA_HF_CLIENT_SCO_CLOSING_ST:
427 case BTA_HF_CLIENT_SCO_OPEN_E:
428 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
431 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
432 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
435 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
436 /* peer closed sco; create SCO listen connection */
437 bta_hf_client_sco_create(client_cb, false);
438 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
442 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d",
448 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
450 case BTA_HF_CLIENT_SCO_CLOSE_E:
451 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
454 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
455 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
458 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
459 /* open SCO connection */
460 bta_hf_client_sco_create(client_cb, true);
461 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
465 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d",
471 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
473 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
474 /* close SCO connection; wait for conn close event */
475 bta_hf_client_sco_remove(client_cb);
478 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
479 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
482 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
483 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
487 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d",
497 APPL_TRACE_DEBUG("%s: after state: %d", __func__, client_cb->sco_state);
500 /*******************************************************************************
502 * Function bta_hf_client_sco_listen
504 * Description Initialize SCO listener
509 ******************************************************************************/
510 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
511 APPL_TRACE_DEBUG("%s", __func__);
513 tBTA_HF_CLIENT_CB* client_cb =
514 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
515 if (client_cb == NULL) {
516 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
517 p_data->hdr.layer_specific);
521 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
524 /*******************************************************************************
526 * Function bta_hf_client_sco_shutdown
533 ******************************************************************************/
534 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
535 APPL_TRACE_DEBUG("%s", __func__);
537 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
540 /*******************************************************************************
542 * Function bta_hf_client_sco_conn_open
549 ******************************************************************************/
550 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
551 APPL_TRACE_DEBUG("%s", __func__);
553 tBTA_HF_CLIENT_CB* client_cb =
554 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
555 if (client_cb == NULL) {
556 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
557 p_data->hdr.layer_specific);
561 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
563 bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
565 if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
566 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
568 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
572 /*******************************************************************************
574 * Function bta_hf_client_sco_conn_close
581 ******************************************************************************/
582 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
583 APPL_TRACE_DEBUG("%s", __func__);
585 tBTA_HF_CLIENT_CB* client_cb =
586 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
587 if (client_cb == NULL) {
588 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
589 p_data->hdr.layer_specific);
593 /* clear current scb */
594 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
596 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
598 bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
600 bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
602 /* call app callback */
603 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
605 if (client_cb->sco_close_rfc) {
606 client_cb->sco_close_rfc = false;
607 bta_hf_client_rfc_do_close(p_data);
611 /*******************************************************************************
613 * Function bta_hf_client_sco_open
620 ******************************************************************************/
621 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
622 APPL_TRACE_DEBUG("%s", __func__);
624 tBTA_HF_CLIENT_CB* client_cb =
625 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
626 if (client_cb == NULL) {
627 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
628 p_data->hdr.layer_specific);
632 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
635 /*******************************************************************************
637 * Function bta_hf_client_sco_close
644 ******************************************************************************/
645 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
646 tBTA_HF_CLIENT_CB* client_cb =
647 bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
648 if (client_cb == NULL) {
649 APPL_TRACE_ERROR("%s: wrong handle to control block %d", __func__,
650 p_data->hdr.layer_specific);
654 APPL_TRACE_DEBUG("%s: sco_idx 0x%x", __func__, client_cb->sco_idx);
656 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
657 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);