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