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