1 /******************************************************************************
2 *
3 * Copyright (c) 2014 The Android Open Source Project
4 * Copyright (C) 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 "bta_hf_client_int.h"
21 #include "bta/bta_hf_client_api.h"
22 #include "common/bt_trace.h"
23 #include <string.h>
24 #include "common/bt_defs.h"
25 #include "common/bt_target.h"
26 #include "osi/allocator.h"
27 #if (BTM_SCO_HCI_INCLUDED == TRUE )
28 #include "bta/bta_hf_client_co.h"
29 #include "hci/hci_audio.h"
30 #endif
31
32 #if BT_HF_CLIENT_BQB_INCLUDED
33 static BOOLEAN s_bta_hf_client_bqb_esco_s1_flag = false;
34 #endif /* BT_HF_CLIENT_BQB_INCLUDED */
35
36 #if (BTA_HF_INCLUDED == TRUE)
37 #define BTA_HF_CLIENT_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
38 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
39 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
40 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
41
42 #define BTA_HF_CLIENT_SCO_PARAM_IDX_CVSD 0 /* SCO setting for CVSD */
43 #define BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S3 1 /* eSCO setting for CVSD S3 */
44 #define BTA_HF_CLIENT_ESCO_PARAM_IDX_MSBC_T2 2 /* eSCO setting for mSBC T2 */
45 #define BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S4 3 /* eSCO setting for CVSD S4 */
46 #define BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S1 4 /* eSCO setting for CVSD S1 */
47
48 static const tBTM_ESCO_PARAMS bta_hf_client_esco_params[] = {
49 /* SCO CVSD */
50 {
51 .rx_bw = BTM_64KBITS_RATE,
52 .tx_bw = BTM_64KBITS_RATE,
53 .max_latency = 10,
54 .voice_contfmt = BTM_VOICE_SETTING_CVSD,
55 .packet_types = (BTM_SCO_PKT_TYPES_MASK_HV1 |
56 BTM_SCO_PKT_TYPES_MASK_HV3 |
57 BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
58 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
59 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
60 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
61 .retrans_effort = BTM_ESCO_RETRANS_OFF,
62 },
63 /* ESCO CVSD */
64 {
65 .rx_bw = BTM_64KBITS_RATE,
66 .tx_bw = BTM_64KBITS_RATE,
67 .max_latency = 10,
68 .voice_contfmt = BTM_VOICE_SETTING_CVSD,
69 /* Packet Types : 2-EV3 */
70 .packet_types = (BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
71 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
72 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
73 .retrans_effort = BTM_ESCO_RETRANS_POWER,
74 },
75 /* ESCO mSBC */
76 {
77 .rx_bw = BTM_64KBITS_RATE,
78 .tx_bw = BTM_64KBITS_RATE,
79 .max_latency = 13,
80 .voice_contfmt = BTM_VOICE_SETTING_TRANS,
81 /* Packet Types : 2-EV3 */
82 .packet_types = (BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
83 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
84 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
85 .retrans_effort = BTM_ESCO_RETRANS_QUALITY,
86 },
87 /* HFP 1.7+ */
88 /* ESCO CVSD S4 */
89 {
90 .rx_bw = BTM_64KBITS_RATE,
91 .tx_bw = BTM_64KBITS_RATE,
92 .max_latency = 12,
93 .voice_contfmt = BTM_VOICE_SETTING_CVSD,
94 /* Packet Types : 2-EV3 */
95 .packet_types = (BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
96 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
97 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
98 .retrans_effort = BTM_ESCO_RETRANS_QUALITY,
99 },
100 /* ESCO CVSD S1 */
101 #if BT_HF_CLIENT_BQB_INCLUDED
102 {
103 .rx_bw = BTM_64KBITS_RATE,
104 .tx_bw = BTM_64KBITS_RATE,
105 .max_latency = 7,
106 .voice_contfmt = BTM_VOICE_SETTING_CVSD,
107 /* Packet Types : EV3 */
108 .packet_types = (HCI_ESCO_PKT_TYPES_MASK_EV3 |
109 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
110 BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
111 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
112 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
113 .retrans_effort = BTM_ESCO_RETRANS_POWER,
114 }
115 #endif /* BT_HF_CLIENT_BQB_INCLUDED */
116 };
117
118 enum {
119 BTA_HF_CLIENT_SCO_LISTEN_E,
120 BTA_HF_CLIENT_SCO_OPEN_E, /* open request */
121 BTA_HF_CLIENT_SCO_CLOSE_E, /* close request */
122 BTA_HF_CLIENT_SCO_SHUTDOWN_E, /* shutdown request */
123 BTA_HF_CLIENT_SCO_CONN_OPEN_E, /* sco opened */
124 BTA_HF_CLIENT_SCO_CONN_CLOSE_E, /* sco closed */
125 #if (BTM_SCO_HCI_INCLUDED == TRUE )
126 BTA_HF_CLIENT_SCO_CI_DATA_E, /* sco data ready */
127 #endif /* #if (BTM_SCO_HCI_INCLUDED == TRUE ) */
128 };
129
130 /*******************************************************************************
131 **
132 ** Function bta_hf_client_bqb_esco_s1_ctrl
133 **
134 ** Description Control the usage of CVSD eSCO S1 parameter for BQB test
135 **
136 ** Returns void
137 **
138 *******************************************************************************/
139 #if BT_HF_CLIENT_BQB_INCLUDED
bta_hf_client_bqb_esco_s1_ctrl(BOOLEAN enable)140 void bta_hf_client_bqb_esco_s1_ctrl(BOOLEAN enable)
141 {
142 s_bta_hf_client_bqb_esco_s1_flag = enable;
143 }
144 #endif /* BT_HF_CLIENT_BQB_INCLUDED */
145
146 static void bta_hf_client_sco_event(UINT8 event);
147 /*******************************************************************************
148 **
149 ** Function bta_hf_client_remove_sco
150 **
151 ** Description Removes the specified SCO from the system.
152 ** If only_active is TRUE, then SCO is only removed if connected
153 **
154 ** Returns BOOLEAN - TRUE if Sco removal was started
155 **
156 *******************************************************************************/
bta_hf_client_sco_remove(BOOLEAN only_active)157 static BOOLEAN bta_hf_client_sco_remove(BOOLEAN only_active)
158 {
159 BOOLEAN removed_started = FALSE;
160 tBTM_STATUS status;
161
162 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, only_active);
163
164 if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
165 status = BTM_RemoveSco(bta_hf_client_cb.scb.sco_idx);
166
167 APPL_TRACE_DEBUG("%s idx 0x%04x, status:0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx, status);
168
169 if (status == BTM_CMD_STARTED) {
170 removed_started = TRUE;
171 }
172 /* If no connection reset the sco handle */
173 else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) ) {
174 bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
175 }
176 }
177 return removed_started;
178 }
179
180 /*******************************************************************************
181 **
182 ** Function bta_hf_client_cback_sco
183 **
184 ** Description Call application callback function with SCO event.
185 **
186 **
187 ** Returns void
188 **
189 *******************************************************************************/
bta_hf_client_cback_sco(UINT8 event)190 void bta_hf_client_cback_sco(UINT8 event)
191 {
192 tBTA_HF_CLIENT_HDR evt;
193
194 memset(&evt, 0, sizeof(evt));
195 evt.sync_conn_handle = BTM_ReadScoHandle(bta_hf_client_cb.scb.sco_idx);
196
197 /* call app cback */
198 (*bta_hf_client_cb.p_cback)(event, (tBTA_HF_CLIENT_HDR *) &evt);
199 }
200
201 #if (BTM_SCO_HCI_INCLUDED == TRUE )
202 /*******************************************************************************
203 **
204 ** Function bta_hf_client_sco_read_cback
205 **
206 ** Description Callback function is the callback function for incoming
207 ** SCO data over HCI.
208 **
209 ** Returns void
210 **
211 *******************************************************************************/
bta_hf_client_sco_read_cback(UINT16 sco_idx,BT_HDR * p_data,tBTM_SCO_DATA_FLAG status)212 static void bta_hf_client_sco_read_cback (UINT16 sco_idx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
213 {
214 if (status != BTM_SCO_DATA_CORRECT)
215 {
216 APPL_TRACE_DEBUG("%s: status(%d)", __FUNCTION__, status);
217 }
218
219 bta_hf_client_sco_co_in_data (p_data, status);
220 osi_free(p_data);
221 }
222 #endif /* BTM_SCO_HCI_INCLUDED */
223
224 /*******************************************************************************
225 **
226 ** Function bta_hf_client_sco_conn_rsp
227 **
228 ** Description Process the SCO connection request
229 **
230 **
231 ** Returns void
232 **
233 *******************************************************************************/
bta_hf_client_sco_conn_rsp(tBTM_ESCO_CONN_REQ_EVT_DATA * p_data)234 static void bta_hf_client_sco_conn_rsp(tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
235 {
236 tBTM_ESCO_PARAMS resp;
237 UINT8 hci_status = HCI_SUCCESS;
238 UINT8 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S3;
239 #if (BTM_SCO_HCI_INCLUDED == TRUE )
240 tBTA_HFP_CODEC_INFO codec_info = {BTA_HFP_SCO_CODEC_PCM};
241 UINT32 pcm_sample_rate;
242 #endif
243
244 APPL_TRACE_DEBUG("%s: negotiated codec = %d", __FUNCTION__, bta_hf_client_cb.scb.negotiated_codec);
245
246 if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_LISTEN_ST) {
247 if (p_data->link_type == BTM_LINK_TYPE_SCO) {
248 index = BTA_HF_CLIENT_SCO_PARAM_IDX_CVSD;
249 } else {
250 if ((bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_CVSD) &&
251 (bta_hf_client_cb.scb.features && BTA_HF_CLIENT_FEAT_ESCO_S4) &&
252 (bta_hf_client_cb.scb.peer_features && BTA_HF_CLIENT_PEER_ESCO_S4)) {
253 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S4;
254 #if BT_HF_CLIENT_BQB_INCLUDED
255 if (s_bta_hf_client_bqb_esco_s1_flag == true) {
256 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S1;
257 }
258 #endif /* BT_HF_CLIENT_BQB_INCLUDED */
259 } else if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
260 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_MSBC_T2;
261 }
262 }
263 resp = bta_hf_client_esco_params[index];
264
265 /* tell sys to stop av if any */
266 bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
267
268 #if (BTM_SCO_HCI_INCLUDED == TRUE )
269 bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_SETUP, 0);
270 pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
271
272 /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
273 BTM_ConfigScoPath(bta_hf_client_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, 0),
274 bta_hf_client_sco_read_cback, NULL, TRUE);
275 #endif
276 } else {
277 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
278 }
279
280 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
281 }
282
283 #if (BTM_SCO_HCI_INCLUDED == TRUE)
284 /*******************************************************************************
285 **
286 ** Function bta_hf_client_pkt_stat_nums
287 **
288 ** Description Get the packet status number
289 **
290 **
291 ** Returns void
292 **
293 *******************************************************************************/
bta_hf_client_pkt_stat_nums(tBTA_HF_CLIENT_DATA * p_data)294 void bta_hf_client_pkt_stat_nums(tBTA_HF_CLIENT_DATA *p_data)
295 {
296 tBTA_SCO_PKT_STAT_NUMS pkt_stat_nums;
297 uint16_t sync_conn_handle = p_data->pkt_stat.sync_conn_handle;
298 BTM_PktStatNumsGet(sync_conn_handle, (tBTM_SCO_PKT_STAT_NUMS *) &pkt_stat_nums);
299
300 /* call app cback */
301 if (bta_hf_client_cb.p_cback) {
302 (*bta_hf_client_cb.p_cback)(BTA_HF_CLIENT_PKT_STAT_NUMS_GET_EVT, (void*) &pkt_stat_nums);
303 }
304 }
305
306 /*******************************************************************************
307 **
308 ** Function bta_hf_client_ci_sco_data
309 **
310 ** Description Process the SCO data ready callin event
311 **
312 **
313 ** Returns void
314 **
315 *******************************************************************************/
bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA * p_data)316 void bta_hf_client_ci_sco_data(tBTA_HF_CLIENT_DATA *p_data)
317 {
318 UNUSED(p_data);
319 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CI_DATA_E);
320 }
321 #endif
322
323 /*******************************************************************************
324 **
325 ** Function bta_hf_client_sco_connreq_cback
326 **
327 ** Description BTM eSCO connection requests and eSCO change requests
328 ** Only the connection requests are processed by BTA.
329 **
330 ** Returns void
331 **
332 *******************************************************************************/
bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * p_data)333 static void bta_hf_client_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
334 {
335 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, event);
336
337 if (event != BTM_ESCO_CONN_REQ_EVT) {
338 return;
339 }
340
341 /* TODO check remote bdaddr, should allow connect only from device with
342 * active SLC */
343
344 bta_hf_client_cb.scb.sco_idx = p_data->conn_evt.sco_inx;
345
346 bta_hf_client_sco_conn_rsp(&p_data->conn_evt);
347
348 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
349 }
350
351 /*******************************************************************************
352 **
353 ** Function bta_hf_client_sco_conn_cback
354 **
355 ** Description BTM SCO connection callback.
356 **
357 **
358 ** Returns void
359 **
360 *******************************************************************************/
bta_hf_client_sco_conn_cback(UINT16 sco_idx)361 static void bta_hf_client_sco_conn_cback(UINT16 sco_idx)
362 {
363 BT_HDR *p_buf;
364 UINT8 *rem_bd;
365 tBTM_ESCO_DATA sco_data;
366
367 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
368
369 rem_bd = BTM_ReadScoBdAddr(sco_idx);
370 BTM_ReadEScoLinkParms (sco_idx, &sco_data);
371
372 if (rem_bd && bdcmp(bta_hf_client_cb.scb.peer_addr, rem_bd) == 0 &&
373 bta_hf_client_cb.scb.svc_conn && bta_hf_client_cb.scb.sco_idx == sco_idx) {
374
375 bta_hf_client_cb.scb.link_type = sco_data.link_type;
376 bta_hf_client_cb.scb.tx_interval = sco_data.tx_interval;
377 bta_hf_client_cb.scb.retrans_window = sco_data.retrans_window;
378 bta_hf_client_cb.scb.air_mode = sco_data.air_mode;
379 if (sco_data.air_mode == BTM_SCO_AIR_MODE_CVSD) {
380 bta_hf_client_cb.scb.out_pkt_len = sco_data.tx_pkt_len * 2;
381 bta_hf_client_cb.scb.in_pkt_len = sco_data.rx_pkt_len * 2;
382 } else {
383 bta_hf_client_cb.scb.out_pkt_len = sco_data.tx_pkt_len;
384 bta_hf_client_cb.scb.in_pkt_len = sco_data.rx_pkt_len;
385 }
386
387 if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
388 p_buf->event = BTA_HF_CLIENT_SCO_OPEN_EVT;
389 p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;
390 bta_sys_sendmsg(p_buf);
391 }
392 }
393 /* no match found; disconnect sco, init sco variables */
394 else {
395 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
396 BTM_RemoveSco(sco_idx);
397 }
398 }
399
400 /*******************************************************************************
401 **
402 ** Function bta_hf_client_sco_disc_cback
403 **
404 ** Description BTM SCO disconnection callback.
405 **
406 **
407 ** Returns void
408 **
409 *******************************************************************************/
bta_hf_client_sco_disc_cback(UINT16 sco_idx)410 static void bta_hf_client_sco_disc_cback(UINT16 sco_idx)
411 {
412 BT_HDR *p_buf;
413
414 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, sco_idx);
415
416 if (bta_hf_client_cb.scb.sco_idx == sco_idx) {
417 #if (BTM_SCO_HCI_INCLUDED == TRUE )
418 tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
419 APPL_TRACE_DEBUG("%s close config status = %d", __FUNCTION__, status);
420 UNUSED(status);
421 /* SCO clean up here */
422 bta_hf_client_sco_co_close();
423 #endif
424 if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
425 p_buf->event = BTA_HF_CLIENT_SCO_CLOSE_EVT;
426 p_buf->layer_specific = bta_hf_client_cb.scb.conn_handle;;
427 bta_sys_sendmsg(p_buf);
428 }
429 }
430 }
431
432 /*******************************************************************************
433 **
434 ** Function bta_hf_client_sco_create
435 **
436 ** Description
437 **
438 **
439 ** Returns void
440 **
441 *******************************************************************************/
bta_hf_client_sco_create(BOOLEAN is_orig)442 static void bta_hf_client_sco_create(BOOLEAN is_orig)
443 {
444 tBTM_STATUS status;
445 UINT8 *p_bd_addr = NULL;
446 tBTM_ESCO_PARAMS params;
447 UINT8 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S3;
448 #if (BTM_SCO_HCI_INCLUDED == TRUE )
449 tBTM_SCO_ROUTE_TYPE sco_route;
450 tBTA_HFP_CODEC_INFO codec_info = {BTA_HFP_SCO_CODEC_PCM};
451 UINT32 pcm_sample_rate;
452 #endif
453 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, is_orig);
454
455 /* Make sure this sco handle is not already in use */
456 if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
457 APPL_TRACE_WARNING("%s: Index 0x%04x already in use", __FUNCTION__,
458 bta_hf_client_cb.scb.sco_idx);
459 return;
460 }
461
462 if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_CVSD) {
463 if ((bta_hf_client_cb.scb.features && BTA_HF_CLIENT_FEAT_ESCO_S4) &&
464 (bta_hf_client_cb.scb.peer_features && BTA_HF_CLIENT_PEER_ESCO_S4)) {
465 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_CVSD_S4;
466 }
467 } else if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
468 index = BTA_HF_CLIENT_ESCO_PARAM_IDX_MSBC_T2;
469 }
470 params = bta_hf_client_esco_params[index];
471
472 /* if initiating set current scb and peer bd addr */
473 if (is_orig) {
474 /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
475 if (bta_hf_client_cb.scb.peer_version >= HFP_VERSION_1_5 && !bta_hf_client_cb.scb.retry_with_sco_only) {
476 BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms);
477 /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
478 if ((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
479 || !((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_HF_CLIENT_NO_EDR_ESCO)) {
480 bta_hf_client_cb.scb.retry_with_sco_only = TRUE;
481 APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
482 }
483 } else {
484 if (bta_hf_client_cb.scb.retry_with_sco_only) {
485 APPL_TRACE_API("retrying with SCO only");
486 }
487 bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
488
489 BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms);
490 }
491
492 /* tell sys to stop av if any */
493 bta_sys_sco_use(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
494
495 #if (BTM_SCO_HCI_INCLUDED == TRUE )
496 /* Allow any platform specific pre-SCO set up to take place */
497 bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_SETUP, 0);
498
499 pcm_sample_rate = BTA_HFP_SCO_SAMP_RATE_8K;
500 sco_route = bta_hf_client_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, 0);
501
502 /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
503 BTM_ConfigScoPath(sco_route, bta_hf_client_sco_read_cback, NULL, TRUE);
504 #endif
505
506 } else {
507 bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
508 }
509
510 p_bd_addr = bta_hf_client_cb.scb.peer_addr;
511
512 status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
513 &bta_hf_client_cb.scb.sco_idx, bta_hf_client_sco_conn_cback,
514 bta_hf_client_sco_disc_cback);
515 if (status == BTM_CMD_STARTED && !is_orig) {
516 if (!BTM_RegForEScoEvts(bta_hf_client_cb.scb.sco_idx, bta_hf_client_esco_connreq_cback)) {
517 APPL_TRACE_DEBUG("%s SCO registration success", __FUNCTION__);
518 }
519 }
520
521 APPL_TRACE_API("%s: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
522 __FUNCTION__, is_orig, bta_hf_client_cb.scb.sco_idx,
523 status, params.packet_types);
524 }
525
526
527 /*******************************************************************************
528 **
529 ** Function bta_hf_client_sco_event
530 **
531 ** Description Handle SCO events
532 **
533 **
534 ** Returns void
535 **
536 *******************************************************************************/
bta_hf_client_sco_event(UINT8 event)537 static void bta_hf_client_sco_event(UINT8 event)
538 {
539 APPL_TRACE_DEBUG("%s state: %d event: %d", __FUNCTION__,
540 bta_hf_client_cb.scb.sco_state, event);
541
542 #if (BTM_SCO_HCI_INCLUDED == TRUE )
543 tBTA_HF_CLIENT_SCB *p_scb = &bta_hf_client_cb.scb;
544 BT_HDR *p_buf;
545 #endif
546
547 #if (BTM_SCO_HCI_INCLUDED == TRUE )
548 if (event == BTA_HF_CLIENT_SCO_CI_DATA_E) {
549 UINT16 pkt_offset = 1 + HCI_SCO_PREAMBLE_SIZE;
550 UINT16 len_to_send = 0;
551 while (true)
552 {
553 p_buf = osi_calloc(sizeof(BT_HDR) + pkt_offset + p_scb->out_pkt_len);
554 if (!p_buf) {
555 APPL_TRACE_WARNING("%s, no mem", __FUNCTION__);
556 break;
557 }
558
559 p_buf->offset = pkt_offset;
560 len_to_send = bta_hf_client_sco_co_out_data(p_buf->data + pkt_offset);
561 p_buf->len = len_to_send;
562 if (len_to_send == p_scb->out_pkt_len) {
563 // expect to get the exact size of data from upper layer
564 if (bta_hf_client_cb.scb.sco_state == BTA_HF_CLIENT_SCO_OPEN_ST) {
565 tBTM_STATUS write_stat = BTM_WriteScoData(p_scb->sco_idx, p_buf);
566 if (write_stat != BTM_SUCCESS) {
567 break;
568 }
569 } else {
570 osi_free(p_buf);
571 }
572 } else {
573 osi_free(p_buf);
574 break;
575 }
576 }
577
578 return;
579 }
580 #endif
581
582 switch (bta_hf_client_cb.scb.sco_state) {
583 case BTA_HF_CLIENT_SCO_SHUTDOWN_ST:
584 switch (event) {
585 case BTA_HF_CLIENT_SCO_LISTEN_E:
586 /* create sco listen connection */
587 bta_hf_client_sco_create(FALSE);
588 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
589 break;
590
591 default:
592 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTDOWN_ST: Ignoring event %d", event);
593 break;
594 }
595 break;
596
597 case BTA_HF_CLIENT_SCO_LISTEN_ST:
598 switch (event) {
599 case BTA_HF_CLIENT_SCO_LISTEN_E:
600 /* create sco listen connection (Additional channel) */
601 bta_hf_client_sco_create(FALSE);
602 break;
603
604 case BTA_HF_CLIENT_SCO_OPEN_E:
605 /* remove listening connection */
606 bta_hf_client_sco_remove(FALSE);
607
608 /* create sco connection to peer */
609 bta_hf_client_sco_create(TRUE);
610 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
611 break;
612
613 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
614 /* remove listening connection */
615 bta_hf_client_sco_remove(FALSE);
616
617 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
618 break;
619
620 case BTA_HF_CLIENT_SCO_CLOSE_E:
621 /* remove listening connection */
622 /* Ignore the event. We need to keep listening SCO for the active SLC */
623 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
624 break;
625
626 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
627 /* sco failed; create sco listen connection */
628 bta_hf_client_sco_create(FALSE);
629 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
630 break;
631
632 default:
633 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_LISTEN_ST: Ignoring event %d", event);
634 break;
635 }
636 break;
637
638 case BTA_HF_CLIENT_SCO_OPENING_ST:
639 switch (event) {
640 case BTA_HF_CLIENT_SCO_CLOSE_E:
641 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_CL_ST;
642 break;
643
644 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
645 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
646 break;
647
648 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
649 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPEN_ST;
650 break;
651
652 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
653 /* sco failed; create sco listen connection */
654 bta_hf_client_sco_create(FALSE);
655 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
656 break;
657
658 default:
659 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPENING_ST: Ignoring event %d", event);
660 break;
661 }
662 break;
663
664 case BTA_HF_CLIENT_SCO_OPEN_CL_ST:
665 switch (event) {
666 case BTA_HF_CLIENT_SCO_OPEN_E:
667 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
668 break;
669
670 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
671 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
672 break;
673
674 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
675 /* close sco connection */
676 bta_hf_client_sco_remove(TRUE);
677
678 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
679 break;
680
681 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
682 /* sco failed; create sco listen connection */
683
684 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
685 break;
686
687 default:
688 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_CL_ST: Ignoring event %d", event);
689 break;
690 }
691 break;
692
693 case BTA_HF_CLIENT_SCO_OPEN_ST:
694 switch (event) {
695 case BTA_HF_CLIENT_SCO_CLOSE_E:
696 /* close sco connection if active */
697 if (bta_hf_client_sco_remove(TRUE)) {
698 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
699 }
700 break;
701
702 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
703 /* remove all listening connections */
704 bta_hf_client_sco_remove(FALSE);
705
706 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
707 break;
708
709 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
710 /* peer closed sco; create sco listen connection */
711 bta_hf_client_sco_create(FALSE);
712 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
713 break;
714
715 default:
716 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_OPEN_ST: Ignoring event %d", event);
717 break;
718 }
719 break;
720
721 case BTA_HF_CLIENT_SCO_CLOSING_ST:
722 switch (event) {
723 case BTA_HF_CLIENT_SCO_OPEN_E:
724 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSE_OP_ST;
725 break;
726
727 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
728 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
729 break;
730
731 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
732 /* peer closed sco; create sco listen connection */
733 bta_hf_client_sco_create(FALSE);
734
735 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_LISTEN_ST;
736 break;
737
738 default:
739 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSING_ST: Ignoring event %d", event);
740 break;
741 }
742 break;
743
744 case BTA_HF_CLIENT_SCO_CLOSE_OP_ST:
745 switch (event) {
746 case BTA_HF_CLIENT_SCO_CLOSE_E:
747 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_CLOSING_ST;
748 break;
749
750 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
751 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTTING_ST;
752 break;
753
754 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
755 /* open sco connection */
756 bta_hf_client_sco_create(TRUE);
757 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_OPENING_ST;
758 break;
759
760 default:
761 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_CLOSE_OP_ST: Ignoring event %d", event);
762 break;
763 }
764 break;
765
766 case BTA_HF_CLIENT_SCO_SHUTTING_ST:
767 switch (event) {
768 case BTA_HF_CLIENT_SCO_CONN_OPEN_E:
769 /* close sco connection; wait for conn close event */
770 bta_hf_client_sco_remove(TRUE);
771 break;
772
773 case BTA_HF_CLIENT_SCO_CONN_CLOSE_E:
774 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
775 break;
776
777 case BTA_HF_CLIENT_SCO_SHUTDOWN_E:
778 bta_hf_client_cb.scb.sco_state = BTA_HF_CLIENT_SCO_SHUTDOWN_ST;
779 break;
780
781 default:
782 APPL_TRACE_WARNING("BTA_HF_CLIENT_SCO_SHUTTING_ST: Ignoring event %d", event);
783 break;
784 }
785 break;
786
787 default:
788 break;
789 }
790 }
791
792 /*******************************************************************************
793 **
794 ** Function bta_hf_client_sco_listen
795 **
796 ** Description Initialize SCO listener
797 **
798 **
799 ** Returns void
800 **
801 *******************************************************************************/
bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA * p_data)802 void bta_hf_client_sco_listen(tBTA_HF_CLIENT_DATA *p_data)
803 {
804 UNUSED(p_data);
805
806 APPL_TRACE_DEBUG("%s", __FUNCTION__);
807
808 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_LISTEN_E);
809 }
810
811 /*******************************************************************************
812 **
813 ** Function bta_hf_client_sco_shutdown
814 **
815 ** Description
816 **
817 **
818 ** Returns void
819 **
820 *******************************************************************************/
bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA * p_data)821 void bta_hf_client_sco_shutdown(tBTA_HF_CLIENT_DATA *p_data)
822 {
823 UNUSED(p_data);
824
825 APPL_TRACE_DEBUG("%s", __FUNCTION__);
826
827 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_SHUTDOWN_E);
828 }
829
830 /*******************************************************************************
831 **
832 ** Function bta_hf_client_sco_conn_open
833 **
834 ** Description
835 **
836 **
837 ** Returns void
838 **
839 *******************************************************************************/
bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA * p_data)840 void bta_hf_client_sco_conn_open(tBTA_HF_CLIENT_DATA *p_data)
841 {
842 UNUSED(p_data);
843
844 APPL_TRACE_DEBUG("%s", __FUNCTION__);
845
846 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_OPEN_E);
847
848 bta_sys_sco_open(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
849 #if (BTM_SCO_HCI_INCLUDED == TRUE)
850 bta_hf_client_co_audio_state(bta_hf_client_cb.scb.sco_idx, SCO_STATE_ON, 0);
851 /* open SCO codec if SCO is routed through transport */
852 bta_hf_client_sco_co_open(bta_hf_client_cb.scb.sco_idx, bta_hf_client_cb.scb.air_mode,
853 bta_hf_client_cb.scb.out_pkt_len, BTA_HF_CLIENT_CI_SCO_DATA_EVT);
854 #endif
855
856 if (bta_hf_client_cb.scb.negotiated_codec == BTM_SCO_CODEC_MSBC) {
857 bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_MSBC_OPEN_EVT);
858 } else {
859 bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_OPEN_EVT);
860 }
861
862 bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
863 }
864
865 /*******************************************************************************
866 **
867 ** Function bta_hf_client_sco_conn_close
868 **
869 ** Description
870 **
871 **
872 ** Returns void
873 **
874 *******************************************************************************/
bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA * p_data)875 void bta_hf_client_sco_conn_close(tBTA_HF_CLIENT_DATA *p_data)
876 {
877 APPL_TRACE_DEBUG("%s", __FUNCTION__);
878
879 /* clear current scb */
880 bta_hf_client_cb.scb.sco_idx = BTM_INVALID_SCO_INDEX;
881
882 /* retry_with_sco_only, will be set only when initiator
883 ** and HFClient is first trying to establish an eSCO connection */
884 if (bta_hf_client_cb.scb.retry_with_sco_only && bta_hf_client_cb.scb.svc_conn) {
885 bta_hf_client_sco_create(TRUE);
886 } else {
887 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CONN_CLOSE_E);
888
889 bta_sys_sco_close(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
890
891 bta_sys_sco_unuse(BTA_ID_HS, 1, bta_hf_client_cb.scb.peer_addr);
892
893 /* call app callback */
894 bta_hf_client_cback_sco(BTA_HF_CLIENT_AUDIO_CLOSE_EVT);
895
896 if (bta_hf_client_cb.scb.sco_close_rfc == TRUE) {
897 bta_hf_client_cb.scb.sco_close_rfc = FALSE;
898 bta_hf_client_rfc_do_close(p_data);
899 }
900 }
901 bta_hf_client_cb.scb.retry_with_sco_only = FALSE;
902 }
903
904 /*******************************************************************************
905 **
906 ** Function bta_hf_client_sco_open
907 **
908 ** Description
909 **
910 **
911 ** Returns void
912 **
913 *******************************************************************************/
bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA * p_data)914 void bta_hf_client_sco_open(tBTA_HF_CLIENT_DATA *p_data)
915 {
916 UNUSED(p_data);
917
918 APPL_TRACE_DEBUG("%s", __FUNCTION__);
919
920 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_OPEN_E);
921 }
922
923 /*******************************************************************************
924 **
925 ** Function bta_hf_client_sco_close
926 **
927 ** Description
928 **
929 **
930 ** Returns void
931 **
932 *******************************************************************************/
bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA * p_data)933 void bta_hf_client_sco_close(tBTA_HF_CLIENT_DATA *p_data)
934 {
935 UNUSED(p_data);
936
937 APPL_TRACE_DEBUG("%s 0x%x", __FUNCTION__, bta_hf_client_cb.scb.sco_idx);
938
939 if (bta_hf_client_cb.scb.sco_idx != BTM_INVALID_SCO_INDEX) {
940 bta_hf_client_sco_event(BTA_HF_CLIENT_SCO_CLOSE_E);
941 }
942 }
943
944 #endif /* #if (BTA_HF_INCLUDED == TRUE) */
945