1 /******************************************************************************
2 *
3 * Copyright (c) 2014 The Android Open Source Project
4 * Copyright 2004-2012 Broadcom Corporation
5 *
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:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 ******************************************************************************/
19
20 #include <bluetooth/log.h>
21
22 #include <cstddef>
23 #include <cstdint>
24 #include <cstring>
25
26 #include "bta/hf_client/bta_hf_client_int.h"
27 #include "bta_hf_client_api.h"
28 #include "bta_sys.h"
29 #include "btm_api_types.h"
30 #include "device/include/esco_parameters.h"
31 #include "hci_error_code.h"
32 #include "osi/include/allocator.h"
33 #include "stack/include/bt_hdr.h"
34 #include "stack/include/btm_client_interface.h"
35 #include "stack/include/btm_status.h"
36
37 #define BTA_HF_CLIENT_NO_EDR_ESCO \
38 (ESCO_PKT_TYPES_MASK_NO_2_EV3 | ESCO_PKT_TYPES_MASK_NO_3_EV3 | ESCO_PKT_TYPES_MASK_NO_2_EV5 | \
39 ESCO_PKT_TYPES_MASK_NO_3_EV5)
40
41 using namespace bluetooth;
42
43 enum {
44 BTA_HF_CLIENT_SCO_LISTEN_E,
45 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
46 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
47 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
48 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* SCO opened */
49 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* SCO closed */
50 };
51
52 /*******************************************************************************
53 *
54 * Function bta_hf_client_remove_sco
55 *
56 * Description Removes the specified SCO from the system.
57 *
58 * Returns bool - true if SCO removal was started
59 *
60 ******************************************************************************/
bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB * client_cb)61 static bool bta_hf_client_sco_remove(tBTA_HF_CLIENT_CB* client_cb) {
62 bool removed_started = false;
63 tBTM_STATUS status;
64
65 log::verbose("");
66
67 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
68 status = get_btm_client_interface().sco.BTM_RemoveSco(client_cb->sco_idx);
69
70 log::verbose("idx 0x{:04x}, status:0x{:x}", client_cb->sco_idx, status);
71
72 if (status == tBTM_STATUS::BTM_CMD_STARTED) {
73 removed_started = true;
74 } else if ((status == tBTM_STATUS::BTM_SUCCESS) || (status == tBTM_STATUS::BTM_UNKNOWN_ADDR)) {
75 /* If no connection reset the SCO handle */
76 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
77 }
78 }
79 return removed_started;
80 }
81
82 /*******************************************************************************
83 *
84 * Function bta_hf_client_cback_sco
85 *
86 * Description Call application callback function with SCO event.
87 *
88 *
89 * Returns void
90 *
91 ******************************************************************************/
bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)92 void bta_hf_client_cback_sco(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
93 tBTA_HF_CLIENT evt;
94
95 memset(&evt, 0, sizeof(evt));
96 evt.bd_addr = client_cb->peer_addr;
97
98 /* call app cback */
99 bta_hf_client_app_callback(event, &evt);
100 }
101
102 /*******************************************************************************
103 *
104 * Function bta_hf_client_sco_conn_rsp
105 *
106 * Description Process the SCO connection request
107 *
108 *
109 * Returns void
110 *
111 ******************************************************************************/
bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB * client_cb,tBTM_ESCO_CONN_REQ_EVT_DATA * p_data)112 static void bta_hf_client_sco_conn_rsp(tBTA_HF_CLIENT_CB* client_cb,
113 tBTM_ESCO_CONN_REQ_EVT_DATA* p_data) {
114 enh_esco_params_t resp;
115 tHCI_STATUS hci_status = HCI_SUCCESS;
116
117 log::verbose("");
118
119 if (client_cb->sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
120 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
121 // SCO
122 resp = esco_parameters_for_codec(SCO_CODEC_CVSD_D1, true);
123 } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) {
124 // eSCO LC3, HFP 1.9
125 resp = esco_parameters_for_codec(ESCO_CODEC_LC3_T2, true);
126 } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
127 // eSCO mSBC
128 resp = esco_parameters_for_codec(ESCO_CODEC_MSBC_T2, true);
129 } else if (bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) {
130 // eSCO CVSD, HFP 1.7 requires S4
131 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, true);
132 } else {
133 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
134 resp = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3, true);
135 }
136
137 /* tell sys to stop av if any */
138 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
139 } else {
140 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
141 }
142
143 get_btm_client_interface().sco.BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
144 }
145
146 /*******************************************************************************
147 *
148 * Function bta_hf_client_sco_connreq_cback
149 *
150 * Description BTM eSCO connection requests and eSCO change requests
151 * Only the connection requests are processed by BTA.
152 *
153 * Returns void
154 *
155 ******************************************************************************/
bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * p_data)156 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA* p_data) {
157 log::verbose("{}", event);
158
159 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(p_data->conn_evt.sco_inx);
160 if (client_cb == NULL) {
161 log::error("wrong SCO handle to control block {}", p_data->conn_evt.sco_inx);
162 return;
163 }
164
165 if (event != BTM_ESCO_CONN_REQ_EVT) {
166 return;
167 }
168
169 bta_hf_client_sco_conn_rsp(client_cb, &p_data->conn_evt);
170
171 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
172 }
173
174 /*******************************************************************************
175 *
176 * Function bta_hf_client_sco_conn_cback
177 *
178 * Description BTM SCO connection callback.
179 *
180 *
181 * Returns void
182 *
183 ******************************************************************************/
bta_hf_client_sco_conn_cback(uint16_t sco_idx)184 static void bta_hf_client_sco_conn_cback(uint16_t sco_idx) {
185 log::verbose("{}", sco_idx);
186
187 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
188 if (client_cb == NULL) {
189 log::error("wrong SCO handle to control block {}", sco_idx);
190 return;
191 }
192
193 BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
194 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
195 p_buf->layer_specific = client_cb->handle;
196 bta_sys_sendmsg(p_buf);
197 }
198
199 /*******************************************************************************
200 *
201 * Function bta_hf_client_sco_disc_cback
202 *
203 * Description BTM SCO disconnection callback.
204 *
205 *
206 * Returns void
207 *
208 ******************************************************************************/
bta_hf_client_sco_disc_cback(uint16_t sco_idx)209 static void bta_hf_client_sco_disc_cback(uint16_t sco_idx) {
210 log::verbose("sco_idx {}", sco_idx);
211
212 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_sco_handle(sco_idx);
213 if (client_cb == NULL) {
214 log::error("wrong handle to control block {}", sco_idx);
215 return;
216 }
217
218 BT_HDR_RIGID* p_buf = (BT_HDR_RIGID*)osi_malloc(sizeof(BT_HDR_RIGID));
219 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
220 p_buf->layer_specific = client_cb->handle;
221 bta_sys_sendmsg(p_buf);
222 }
223
224 /*******************************************************************************
225 *
226 * Function bta_hf_client_create_sco
227 *
228 * Description
229 *
230 *
231 * Returns void
232 *
233 ******************************************************************************/
bta_hf_client_sco_create(tBTA_HF_CLIENT_CB * client_cb,bool is_orig)234 static void bta_hf_client_sco_create(tBTA_HF_CLIENT_CB* client_cb, bool is_orig) {
235 tBTM_STATUS status;
236
237 log::verbose("{}", is_orig);
238
239 /* Make sure this SCO handle is not already in use */
240 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
241 log::warn("Index 0x{:04x} already in use", client_cb->sco_idx);
242 return;
243 }
244
245 // codec parameters
246 enh_esco_params_t params;
247 // Since HF device is not expected to receive AT+BAC send +BCS command,
248 // codec support of the connected AG device will be unknown,
249 // so HF device will always establish only CVSD connection.
250 if ((bta_hf_client_cb_arr.features & BTA_HF_CLIENT_FEAT_ESCO_S4) &&
251 (client_cb->peer_features & BTA_HF_CLIENT_PEER_ESCO_S4)) {
252 // eSCO CVSD, HFP 1.7 requires S4
253 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S4, true);
254 } else {
255 // eSCO CVSD, S3 is preferred by default(before HFP 1.7)
256 params = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3, true);
257 }
258
259 /* if initiating set current scb and peer bd addr */
260 if (is_orig) {
261 if (get_btm_client_interface().sco.BTM_SetEScoMode(¶ms) != tBTM_STATUS::BTM_SUCCESS) {
262 log::warn("Unable to set ESCO mode");
263 }
264 /* tell sys to stop av if any */
265 bta_sys_sco_use(BTA_ID_HS, 1, client_cb->peer_addr);
266 }
267
268 status = get_btm_client_interface().sco.BTM_CreateSco(
269 &client_cb->peer_addr, is_orig, params.packet_types, &client_cb->sco_idx,
270 bta_hf_client_sco_conn_cback, bta_hf_client_sco_disc_cback);
271 if (status == tBTM_STATUS::BTM_CMD_STARTED && !is_orig) {
272 if (get_btm_client_interface().sco.BTM_RegForEScoEvts(
273 client_cb->sco_idx, bta_hf_client_esco_connreq_cback) == tBTM_STATUS::BTM_SUCCESS) {
274 log::verbose("SCO registration success");
275 }
276 }
277
278 log::verbose("orig {}, inx 0x{:04x}, status 0x{:x}, pkt types 0x{:04x}", is_orig,
279 client_cb->sco_idx, status, params.packet_types);
280 }
281
282 /*******************************************************************************
283 *
284 * Function bta_hf_client_sco_event
285 *
286 * Description Handle SCO events
287 *
288 *
289 * Returns void
290 *
291 ******************************************************************************/
bta_hf_client_sco_event(tBTA_HF_CLIENT_CB * client_cb,uint8_t event)292 static void bta_hf_client_sco_event(tBTA_HF_CLIENT_CB* client_cb, uint8_t event) {
293 log::verbose("before state: {} event: {}", client_cb->sco_state, event);
294
295 switch (client_cb->sco_state) {
296 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
297 switch (event) {
298 // For WBS we only listen to SCO requests. Even for outgoing SCO
299 // requests we first do a AT+BCC and wait for remote to initiate SCO
300 case BTA_HF_CLIENT_SCO_LISTEN_E:
301 /* create SCO listen connection */
302 bta_hf_client_sco_create(client_cb, false);
303 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
304 break;
305
306 // For non WBS cases and enabling outgoing SCO requests we need to force
307 // open a SCO channel
308 case BTA_HF_CLIENT_SCO_OPEN_E:
309 /* remove listening connection */
310 bta_hf_client_sco_remove(client_cb);
311
312 /* create SCO connection to peer */
313 bta_hf_client_sco_create(client_cb, true);
314 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
315 break;
316
317 default:
318 log::warn("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event {}", event);
319 break;
320 }
321 break;
322
323 case BTA_HF_CLIENT_SCO_LISTEN_ST:
324 switch (event) {
325 case BTA_HF_CLIENT_SCO_LISTEN_E:
326 /* create SCO listen connection */
327 bta_hf_client_sco_create(client_cb, false);
328 break;
329
330 case BTA_HF_CLIENT_SCO_OPEN_E:
331 /* remove listening connection */
332 bta_hf_client_sco_remove(client_cb);
333
334 /* create SCO connection to peer */
335 bta_hf_client_sco_create(client_cb, true);
336 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
337 break;
338
339 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
340 /* remove listening connection */
341 bta_hf_client_sco_remove(client_cb);
342
343 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
344 break;
345
346 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
347 /* SCO failed; create SCO listen connection */
348 bta_hf_client_sco_create(client_cb, false);
349 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
350 break;
351
352 default:
353 log::warn("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event {}", event);
354 break;
355 }
356 break;
357
358 case BTA_HF_CLIENT_SCO_OPENING_ST:
359 switch (event) {
360 case BTA_HF_CLIENT_SCO_CLOSE_E:
361 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
362 break;
363
364 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
365 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
366 break;
367
368 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
369 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
370 break;
371
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;
376 break;
377
378 default:
379 log::warn("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event {}", event);
380 break;
381 }
382 break;
383
384 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
385 switch (event) {
386 case BTA_HF_CLIENT_SCO_OPEN_E:
387 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
388 break;
389
390 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
391 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
392 break;
393
394 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
395 /* close SCO connection */
396 bta_hf_client_sco_remove(client_cb);
397
398 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
399 break;
400
401 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
402 /* SCO failed; create SCO listen connection */
403
404 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
405 break;
406
407 default:
408 log::warn("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event {}", event);
409 break;
410 }
411 break;
412
413 case BTA_HF_CLIENT_SCO_OPEN_ST:
414 switch (event) {
415 case BTA_HF_CLIENT_SCO_CLOSE_E:
416 if (bta_hf_client_sco_remove(client_cb)) {
417 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
418 }
419 break;
420
421 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
422 /* remove listening connection */
423 bta_hf_client_sco_remove(client_cb);
424
425 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
426 break;
427
428 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
429 /* peer closed SCO */
430 bta_hf_client_sco_create(client_cb, false);
431 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
432 break;
433
434 default:
435 log::warn("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event {}", event);
436 break;
437 }
438 break;
439
440 case BTA_HF_CLIENT_SCO_CLOSING_ST:
441 switch (event) {
442 case BTA_HF_CLIENT_SCO_OPEN_E:
443 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
444 break;
445
446 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
447 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
448 break;
449
450 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
451 /* peer closed sco; create SCO listen connection */
452 bta_hf_client_sco_create(client_cb, false);
453 client_cb->sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
454 break;
455
456 default:
457 log::warn("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event {}", event);
458 break;
459 }
460 break;
461
462 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
463 switch (event) {
464 case BTA_HF_CLIENT_SCO_CLOSE_E:
465 client_cb->sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
466 break;
467
468 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
469 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
470 break;
471
472 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
473 /* open SCO connection */
474 bta_hf_client_sco_create(client_cb, true);
475 client_cb->sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
476 break;
477
478 default:
479 log::warn("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event {}", event);
480 break;
481 }
482 break;
483
484 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
485 switch (event) {
486 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
487 /* close SCO connection; wait for conn close event */
488 bta_hf_client_sco_remove(client_cb);
489 break;
490
491 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
492 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
493 break;
494
495 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
496 client_cb->sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
497 break;
498
499 default:
500 log::warn("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event {}", event);
501 break;
502 }
503 break;
504
505 default:
506 break;
507 }
508
509 log::verbose("after state: {}", client_cb->sco_state);
510 }
511
512 /*******************************************************************************
513 *
514 * Function bta_hf_client_sco_listen
515 *
516 * Description Initialize SCO listener
517 *
518 *
519 * Returns void
520 *
521 ******************************************************************************/
bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA * p_data)522 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA* p_data) {
523 log::verbose("");
524
525 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
526 if (client_cb == NULL) {
527 log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
528 return;
529 }
530
531 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_LISTEN_E);
532 }
533
534 /*******************************************************************************
535 *
536 * Function bta_hf_client_sco_shutdown
537 *
538 * Description
539 *
540 *
541 * Returns void
542 *
543 ******************************************************************************/
bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB * client_cb)544 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_CB* client_cb) {
545 log::verbose("");
546
547 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_SHUTDOWN_E);
548 }
549
550 /*******************************************************************************
551 *
552 * Function bta_hf_client_sco_conn_open
553 *
554 * Description
555 *
556 *
557 * Returns void
558 *
559 ******************************************************************************/
bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA * p_data)560 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA* p_data) {
561 log::verbose("");
562
563 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
564 if (client_cb == NULL) {
565 log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
566 return;
567 }
568
569 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_OPEN_E);
570
571 bta_sys_sco_open(BTA_ID_HS, 1, client_cb->peer_addr);
572
573 if (client_cb->negotiated_codec == BTM_SCO_CODEC_LC3) {
574 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_LC3_OPEN_EVT);
575 } else if (client_cb->negotiated_codec == BTM_SCO_CODEC_MSBC) {
576 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
577 } else {
578 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_OPEN_EVT);
579 }
580 }
581
582 /*******************************************************************************
583 *
584 * Function bta_hf_client_sco_conn_close
585 *
586 * Description
587 *
588 *
589 * Returns void
590 *
591 ******************************************************************************/
bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA * p_data)592 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA* p_data) {
593 log::verbose("");
594
595 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
596 if (client_cb == NULL) {
597 log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
598 return;
599 }
600
601 /* clear current scb */
602 client_cb->sco_idx = BTM_INVALID_SCO_INDEX;
603
604 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
605
606 bta_sys_sco_close(BTA_ID_HS, 1, client_cb->peer_addr);
607
608 bta_sys_sco_unuse(BTA_ID_HS, 1, client_cb->peer_addr);
609
610 /* call app callback */
611 bta_hf_client_cback_sco(client_cb, BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
612
613 if (client_cb->sco_close_rfc) {
614 client_cb->sco_close_rfc = false;
615 bta_hf_client_rfc_do_close(p_data);
616 }
617 }
618
619 /*******************************************************************************
620 *
621 * Function bta_hf_client_sco_open
622 *
623 * Description
624 *
625 *
626 * Returns void
627 *
628 ******************************************************************************/
bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA * p_data)629 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA* p_data) {
630 log::verbose("");
631
632 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
633 if (client_cb == NULL) {
634 log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
635 return;
636 }
637
638 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_OPEN_E);
639 }
640
641 /*******************************************************************************
642 *
643 * Function bta_hf_client_sco_close
644 *
645 * Description
646 *
647 *
648 * Returns void
649 *
650 ******************************************************************************/
bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA * p_data)651 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA* p_data) {
652 tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
653 if (client_cb == NULL) {
654 log::error("wrong handle to control block {}", p_data->hdr.layer_specific);
655 return;
656 }
657
658 log::verbose("sco_idx 0x{:x}", client_cb->sco_idx);
659
660 if (client_cb->sco_idx != BTM_INVALID_SCO_INDEX) {
661 bta_hf_client_sco_event(client_cb, BTA_HF_CLIENT_SCO_CLOSE_E);
662 }
663 }
664