1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * This file contains functions for managing the SCO connection used in AG.
22 *
23 ******************************************************************************/
24
25 #include "bta_api.h"
26 #include "bta_ag_api.h"
27 #include "bta_ag_co.h"
28 #if (BTM_SCO_HCI_INCLUDED == TRUE )
29 #include "bta_dm_co.h"
30 #endif
31 #include "bta_ag_int.h"
32 #include "btm_api.h"
33 #include "gki.h"
34 #include "utl.h"
35
36 #ifndef BTA_AG_SCO_DEBUG
37 #define BTA_AG_SCO_DEBUG FALSE
38 #endif
39
40 #ifndef BTA_AG_CODEC_NEGO_TIMEOUT
41 #define BTA_AG_CODEC_NEGO_TIMEOUT 3000
42 #endif
43
44 #if BTA_AG_SCO_DEBUG == TRUE
45 static char *bta_ag_sco_evt_str(UINT8 event);
46 static char *bta_ag_sco_state_str(UINT8 state);
47 #endif
48
49 #define BTA_AG_NO_EDR_ESCO (BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 | \
50 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 | \
51 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 | \
52 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5)
53
54 /* sco events */
55 enum
56 {
57 BTA_AG_SCO_LISTEN_E, /* listen request */
58 BTA_AG_SCO_OPEN_E, /* open request */
59 BTA_AG_SCO_XFER_E, /* transfer request */
60 #if (BTM_WBS_INCLUDED == TRUE )
61 BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */
62 BTA_AG_SCO_REOPEN_E, /* Retry with other codec when failed */
63 #endif
64 BTA_AG_SCO_CLOSE_E, /* close request */
65 BTA_AG_SCO_SHUTDOWN_E, /* shutdown request */
66 BTA_AG_SCO_CONN_OPEN_E, /* sco open */
67 BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */
68 BTA_AG_SCO_CI_DATA_E /* SCO data ready */
69 };
70
71 #if (BTM_WBS_INCLUDED == TRUE )
72 #define BTA_AG_NUM_CODECS 3
73 #define BTA_AG_ESCO_SETTING_IDX_CVSD 0 /* eSCO setting for CVSD */
74 #define BTA_AG_ESCO_SETTING_IDX_T1 1 /* eSCO setting for mSBC T1 */
75 #define BTA_AG_ESCO_SETTING_IDX_T2 2 /* eSCO setting for mSBC T2 */
76
77 static const tBTM_ESCO_PARAMS bta_ag_esco_params[BTA_AG_NUM_CODECS] =
78 {
79 /* CVSD */
80 {
81 BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
82 BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
83 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
84 BTM_VOICE_SETTING_CVSD, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
85 (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
86 BTM_SCO_PKT_TYPES_MASK_HV2 +
87 BTM_SCO_PKT_TYPES_MASK_HV3 +
88 BTM_SCO_PKT_TYPES_MASK_EV3 +
89 BTM_SCO_PKT_TYPES_MASK_EV4 +
90 BTM_SCO_PKT_TYPES_MASK_EV5 +
91 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
92 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
93 BTM_ESCO_RETRANS_POWER /* Retransmission effort */
94 },
95 /* mSBC T1 */
96 {
97 BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */
98 BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */
99 8, /* 8 ms */
100 BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */
101 (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + NO_2_EV3 */
102 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
103 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
104 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5 |
105 BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 ),
106 BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
107 },
108 /* mSBC T2*/
109 {
110 BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec), 8000 */
111 BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec), 8000 */
112 13, /* 13 ms */
113 BTM_VOICE_SETTING_TRANS, /* Inp Linear, Transparent, 2s Comp, 16bit */
114 (BTM_SCO_PKT_TYPES_MASK_EV3 | /* Packet Types : EV3 + 2-EV3 */
115 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
116 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
117 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
118 BTM_ESCO_RETRANS_QUALITY /* Retransmission effort */
119 }
120 };
121 #else
122 /* WBS not included, CVSD by default */
123 static const tBTM_ESCO_PARAMS bta_ag_esco_params =
124 {
125 BTM_64KBITS_RATE, /* TX Bandwidth (64 kbits/sec) */
126 BTM_64KBITS_RATE, /* RX Bandwidth (64 kbits/sec) */
127 0x000a, /* 10 ms (HS/HF can use EV3, 2-EV3, 3-EV3) */
128 0x0060, /* Inp Linear, Air CVSD, 2s Comp, 16bit */
129 (BTM_SCO_PKT_TYPES_MASK_HV1 + /* Packet Types */
130 BTM_SCO_PKT_TYPES_MASK_HV2 +
131 BTM_SCO_PKT_TYPES_MASK_HV3 +
132 BTM_SCO_PKT_TYPES_MASK_EV3 +
133 BTM_SCO_PKT_TYPES_MASK_EV4 +
134 BTM_SCO_PKT_TYPES_MASK_EV5 +
135 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 +
136 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5),
137 BTM_ESCO_RETRANS_POWER /* Retransmission effort */
138 };
139 #endif
140
141 /*******************************************************************************
142 **
143 ** Function bta_ag_sco_conn_cback
144 **
145 ** Description BTM SCO connection callback.
146 **
147 **
148 ** Returns void
149 **
150 *******************************************************************************/
bta_ag_sco_conn_cback(UINT16 sco_idx)151 static void bta_ag_sco_conn_cback(UINT16 sco_idx)
152 {
153 UINT16 handle;
154 BT_HDR *p_buf;
155 tBTA_AG_SCB *p_scb;
156
157 /* match callback to scb; first check current sco scb */
158 if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
159 {
160 handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
161 }
162 /* then check for scb connected to this peer */
163 else
164 {
165 /* Check if SLC is up */
166 handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_idx));
167 p_scb = bta_ag_scb_by_idx(handle);
168 if(p_scb && !p_scb->svc_conn)
169 handle = 0;
170 }
171
172 if (handle != 0)
173 {
174 if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
175 {
176 p_buf->event = BTA_AG_SCO_OPEN_EVT;
177 p_buf->layer_specific = handle;
178 bta_sys_sendmsg(p_buf);
179 }
180 }
181 /* no match found; disconnect sco, init sco variables */
182 else
183 {
184 bta_ag_cb.sco.p_curr_scb = NULL;
185 bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
186 BTM_RemoveSco(sco_idx);
187 }
188 }
189
190 /*******************************************************************************
191 **
192 ** Function bta_ag_sco_disc_cback
193 **
194 ** Description BTM SCO disconnection callback.
195 **
196 **
197 ** Returns void
198 **
199 *******************************************************************************/
bta_ag_sco_disc_cback(UINT16 sco_idx)200 static void bta_ag_sco_disc_cback(UINT16 sco_idx)
201 {
202 BT_HDR *p_buf;
203 UINT16 handle = 0;
204
205 APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): sco_idx: 0x%x p_cur_scb: 0x%08x sco.state: %d", sco_idx, bta_ag_cb.sco.p_curr_scb, bta_ag_cb.sco.state);
206
207 APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): scb[0] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
208 &bta_ag_cb.scb[0], bta_ag_cb.scb[0].in_use, bta_ag_cb.scb[0].sco_idx, bta_ag_cb.scb[0].state);
209 APPL_TRACE_DEBUG ("bta_ag_sco_disc_cback(): scb[1] addr: 0x%08x in_use: %u sco_idx: 0x%x sco state: %u",
210 &bta_ag_cb.scb[1], bta_ag_cb.scb[1].in_use, bta_ag_cb.scb[1].sco_idx, bta_ag_cb.scb[1].state);
211
212 /* match callback to scb */
213 if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb->in_use)
214 {
215 /* We only care about callbacks for the active SCO */
216 if (bta_ag_cb.sco.p_curr_scb->sco_idx != sco_idx)
217 {
218 if (bta_ag_cb.sco.p_curr_scb->sco_idx != 0xFFFF)
219 return;
220 }
221 handle = bta_ag_scb_to_idx(bta_ag_cb.sco.p_curr_scb);
222 }
223
224 if (handle != 0)
225 {
226 #if (BTM_SCO_HCI_INCLUDED == TRUE )
227 tBTM_STATUS status = BTM_ConfigScoPath(BTM_SCO_ROUTE_PCM, NULL, NULL, TRUE);
228 APPL_TRACE_DEBUG("bta_ag_sco_disc_cback sco close config status = %d", status);
229 /* SCO clean up here */
230 bta_dm_sco_co_close();
231 #endif
232
233 #if (BTM_WBS_INCLUDED == TRUE )
234 /* Restore settings */
235 if(bta_ag_cb.sco.p_curr_scb->inuse_codec == BTA_AG_CODEC_MSBC)
236 {
237 /* set_sco_codec(BTM_SCO_CODEC_NONE); we should get a close */
238 BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
239
240 /* If SCO open was initiated by AG and failed for mSBC, then attempt
241 mSBC with T1 settings i.e. 'Safe Settings'. If this fails, then switch to CVSD */
242 if (bta_ag_sco_is_opening (bta_ag_cb.sco.p_curr_scb))
243 {
244 if (bta_ag_cb.sco.p_curr_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2)
245 {
246 APPL_TRACE_DEBUG("Fallback to mSBC T1 settings");
247 bta_ag_cb.sco.p_curr_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T1;
248 }
249 else
250 {
251 APPL_TRACE_DEBUG("Fallback to CVSD settings");
252 bta_ag_cb.sco.p_curr_scb->codec_fallback = TRUE;
253 }
254 }
255 }
256
257 bta_ag_cb.sco.p_curr_scb->inuse_codec = BTA_AG_CODEC_NONE;
258 #endif
259
260 if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
261 {
262 p_buf->event = BTA_AG_SCO_CLOSE_EVT;
263 p_buf->layer_specific = handle;
264 bta_sys_sendmsg(p_buf);
265 }
266 }
267 /* no match found */
268 else
269 {
270 APPL_TRACE_DEBUG("no scb for ag_sco_disc_cback");
271
272 /* sco could be closed after scb dealloc'ed */
273 if (bta_ag_cb.sco.p_curr_scb != NULL)
274 {
275 bta_ag_cb.sco.p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
276 bta_ag_cb.sco.p_curr_scb = NULL;
277 bta_ag_cb.sco.state = BTA_AG_SCO_SHUTDOWN_ST;
278 }
279 }
280 }
281 #if (BTM_SCO_HCI_INCLUDED == TRUE )
282 /*******************************************************************************
283 **
284 ** Function bta_ag_sco_read_cback
285 **
286 ** Description Callback function is the callback function for incoming
287 ** SCO data over HCI.
288 **
289 ** Returns void
290 **
291 *******************************************************************************/
bta_ag_sco_read_cback(UINT16 sco_inx,BT_HDR * p_data,tBTM_SCO_DATA_FLAG status)292 static void bta_ag_sco_read_cback (UINT16 sco_inx, BT_HDR *p_data, tBTM_SCO_DATA_FLAG status)
293 {
294 if (status != BTM_SCO_DATA_CORRECT)
295 {
296 APPL_TRACE_DEBUG("bta_ag_sco_read_cback: status(%d)", status);
297 }
298
299 /* Callout function must free the data. */
300 bta_dm_sco_co_in_data (p_data, status);
301 }
302 #endif
303 /*******************************************************************************
304 **
305 ** Function bta_ag_remove_sco
306 **
307 ** Description Removes the specified SCO from the system.
308 ** If only_active is TRUE, then SCO is only removed if connected
309 **
310 ** Returns BOOLEAN - TRUE if Sco removal was started
311 **
312 *******************************************************************************/
bta_ag_remove_sco(tBTA_AG_SCB * p_scb,BOOLEAN only_active)313 static BOOLEAN bta_ag_remove_sco(tBTA_AG_SCB *p_scb, BOOLEAN only_active)
314 {
315 BOOLEAN removed_started = FALSE;
316 tBTM_STATUS status;
317
318 if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
319 {
320 if (!only_active || p_scb->sco_idx == bta_ag_cb.sco.cur_idx)
321 {
322 status = BTM_RemoveSco(p_scb->sco_idx);
323
324 APPL_TRACE_DEBUG("ag remove sco: inx 0x%04x, status:0x%x", p_scb->sco_idx, status);
325
326 if (status == BTM_CMD_STARTED)
327 {
328 /* Sco is connected; set current control block */
329 bta_ag_cb.sco.p_curr_scb = p_scb;
330
331 removed_started = TRUE;
332 }
333 /* If no connection reset the sco handle */
334 else if ( (status == BTM_SUCCESS) || (status == BTM_UNKNOWN_ADDR) )
335 {
336 p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
337 }
338 }
339 }
340 return removed_started;
341 }
342
343
344 /*******************************************************************************
345 **
346 ** Function bta_ag_esco_connreq_cback
347 **
348 ** Description BTM eSCO connection requests and eSCO change requests
349 ** Only the connection requests are processed by BTA.
350 **
351 ** Returns void
352 **
353 *******************************************************************************/
bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event,tBTM_ESCO_EVT_DATA * p_data)354 static void bta_ag_esco_connreq_cback(tBTM_ESCO_EVT event, tBTM_ESCO_EVT_DATA *p_data)
355 {
356 tBTA_AG_SCB *p_scb;
357 UINT16 handle;
358 UINT16 sco_inx = p_data->conn_evt.sco_inx;
359
360 /* Only process connection requests */
361 if (event == BTM_ESCO_CONN_REQ_EVT)
362 {
363 if ((handle = bta_ag_idx_by_bdaddr(BTM_ReadScoBdAddr(sco_inx))) != 0 &&
364 ((p_scb = bta_ag_scb_by_idx(handle)) != NULL) && p_scb->svc_conn)
365 {
366 p_scb->sco_idx = sco_inx;
367
368 /* If no other SCO active, allow this one */
369 if (!bta_ag_cb.sco.p_curr_scb)
370 {
371 APPL_TRACE_EVENT("bta_ag_esco_connreq_cback: Accept Conn Request (sco_inx 0x%04x)", sco_inx);
372 bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
373
374 bta_ag_cb.sco.state = BTA_AG_SCO_OPENING_ST;
375 bta_ag_cb.sco.p_curr_scb = p_scb;
376 bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
377 }
378 else /* Begin a transfer: Close current SCO before responding */
379 {
380 APPL_TRACE_DEBUG("bta_ag_esco_connreq_cback: Begin XFER");
381 bta_ag_cb.sco.p_xfer_scb = p_scb;
382 bta_ag_cb.sco.conn_data = p_data->conn_evt;
383 bta_ag_cb.sco.state = BTA_AG_SCO_OPEN_XFER_ST;
384
385 if (!bta_ag_remove_sco(bta_ag_cb.sco.p_curr_scb, TRUE))
386 {
387 APPL_TRACE_ERROR("bta_ag_esco_connreq_cback: Nothing to remove so accept Conn Request (sco_inx 0x%04x)", sco_inx);
388 bta_ag_cb.sco.p_xfer_scb = NULL;
389 bta_ag_cb.sco.state = BTA_AG_SCO_LISTEN_ST;
390
391 bta_ag_sco_conn_rsp(p_scb, &p_data->conn_evt);
392 }
393 }
394 }
395 /* If error occurred send reject response immediately */
396 else
397 {
398 APPL_TRACE_WARNING("no scb for bta_ag_esco_connreq_cback or no resources");
399 BTM_EScoConnRsp(p_data->conn_evt.sco_inx, HCI_ERR_HOST_REJECT_RESOURCES, NULL);
400 }
401 }
402 /* Received a change in the esco link */
403 else if (event == BTM_ESCO_CHG_EVT)
404 {
405 APPL_TRACE_EVENT("eSCO change event (inx %d): rtrans %d, rxlen %d, txlen %d, txint %d",
406 p_data->chg_evt.sco_inx,
407 p_data->chg_evt.retrans_window, p_data->chg_evt.rx_pkt_len,
408 p_data->chg_evt.tx_pkt_len, p_data->chg_evt.tx_interval);
409 }
410 }
411
412 /*******************************************************************************
413 **
414 ** Function bta_ag_cback_sco
415 **
416 ** Description Call application callback function with SCO event.
417 **
418 **
419 ** Returns void
420 **
421 *******************************************************************************/
bta_ag_cback_sco(tBTA_AG_SCB * p_scb,UINT8 event)422 static void bta_ag_cback_sco(tBTA_AG_SCB *p_scb, UINT8 event)
423 {
424 tBTA_AG_HDR sco;
425
426 sco.handle = bta_ag_scb_to_idx(p_scb);
427 sco.app_id = p_scb->app_id;
428
429 /* call close cback */
430 (*bta_ag_cb.p_cback)(event, (tBTA_AG *) &sco);
431 }
432
433 /*******************************************************************************
434 **
435 ** Function bta_ag_create_sco
436 **
437 ** Description
438 **
439 **
440 ** Returns void
441 **
442 *******************************************************************************/
bta_ag_create_sco(tBTA_AG_SCB * p_scb,BOOLEAN is_orig)443 static void bta_ag_create_sco(tBTA_AG_SCB *p_scb, BOOLEAN is_orig)
444 {
445 tBTM_STATUS status;
446 UINT8 *p_bd_addr = NULL;
447 tBTM_ESCO_PARAMS params;
448 #if (BTM_WBS_INCLUDED == TRUE )
449 tBTA_AG_PEER_CODEC esco_codec = BTM_SCO_CODEC_CVSD;
450 int codec_index = 0;
451 #endif
452 #if (BTM_SCO_HCI_INCLUDED == TRUE )
453 tBTM_SCO_ROUTE_TYPE sco_route;
454 tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
455 UINT32 pcm_sample_rate;
456 #endif
457
458 /* Make sure this sco handle is not already in use */
459 if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
460 {
461 APPL_TRACE_WARNING("bta_ag_create_sco: Index 0x%04x Already In Use!",
462 p_scb->sco_idx);
463 return;
464 }
465
466 #if (BTM_WBS_INCLUDED == TRUE )
467 if ((p_scb->sco_codec == BTM_SCO_CODEC_MSBC) &&
468 !p_scb->codec_fallback &&
469 !p_scb->retry_with_sco_only)
470 esco_codec = BTM_SCO_CODEC_MSBC;
471
472 if (p_scb->codec_fallback)
473 {
474 p_scb->codec_fallback = FALSE;
475
476 /* Force AG to send +BCS for the next audio connection. */
477 p_scb->codec_updated = TRUE;
478 }
479
480 /* If WBS included, use CVSD by default, index is 0 for CVSD by initialization */
481 /* If eSCO codec is mSBC, index is T2 or T1 */
482 if (esco_codec == BTM_SCO_CODEC_MSBC)
483 {
484 if (p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T2)
485 {
486 codec_index = BTA_AG_ESCO_SETTING_IDX_T2;
487 }
488 else
489 {
490 codec_index = BTA_AG_ESCO_SETTING_IDX_T1;
491 }
492 }
493
494 params = bta_ag_esco_params[codec_index];
495 #else
496 /* When WBS is not included, use CVSD by default */
497 params = bta_ag_esco_params;
498 #endif
499
500 if(bta_ag_cb.sco.param_updated) /* If we do not use the default parameters */
501 params = bta_ag_cb.sco.params;
502
503 if(!bta_ag_cb.sco.param_updated)
504 {
505 #if (BTM_WBS_INCLUDED == TRUE)
506 if (esco_codec == BTM_SCO_CODEC_CVSD) /* For CVSD */
507 #endif
508 {
509 /* Use the application packet types (5 slot EV packets not allowed) */
510 params.packet_types = p_bta_ag_cfg->sco_pkt_types |
511 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
512 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5;
513 }
514 }
515
516 /* if initiating set current scb and peer bd addr */
517 if (is_orig)
518 {
519 /* Attempt to use eSCO if remote host supports HFP >= 1.5 */
520 /* Need to find out from SIG if HSP can use eSCO; for now use SCO */
521 if (p_scb->conn_service == BTA_AG_HFP && p_scb->peer_version >= HFP_VERSION_1_5 && !p_scb->retry_with_sco_only)
522 {
523
524 BTM_SetEScoMode(BTM_LINK_TYPE_ESCO, ¶ms);
525 /* If ESCO or EDR ESCO, retry with SCO only in case of failure */
526 if((params.packet_types & BTM_ESCO_LINK_ONLY_MASK)
527 ||!((params.packet_types & ~(BTM_ESCO_LINK_ONLY_MASK | BTM_SCO_LINK_ONLY_MASK)) ^ BTA_AG_NO_EDR_ESCO))
528 {
529 #if (BTM_WBS_INCLUDED == TRUE )
530 if (esco_codec != BTA_AG_CODEC_MSBC)
531 {
532 p_scb->retry_with_sco_only = TRUE;
533 APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
534 }
535 else /* Do not use SCO when using mSBC */
536 {
537 p_scb->retry_with_sco_only = FALSE;
538 APPL_TRACE_API("Setting retry_with_sco_only to FALSE");
539 }
540 #else
541 p_scb->retry_with_sco_only = TRUE;
542 APPL_TRACE_API("Setting retry_with_sco_only to TRUE");
543 #endif
544 }
545 }
546 else
547 {
548 if(p_scb->retry_with_sco_only)
549 APPL_TRACE_API("retrying with SCO only");
550 p_scb->retry_with_sco_only = FALSE;
551
552 BTM_SetEScoMode(BTM_LINK_TYPE_SCO, ¶ms);
553 }
554
555 bta_ag_cb.sco.p_curr_scb = p_scb;
556
557 /* tell sys to stop av if any */
558 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
559
560 #if (BTM_WBS_INCLUDED == TRUE )
561 /* Allow any platform specific pre-SCO set up to take place */
562 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP,\
563 esco_codec);
564
565 /* This setting may not be necessary */
566 /* To be verified with stable 2049 boards */
567 if (esco_codec == BTA_AG_CODEC_MSBC)
568 BTM_WriteVoiceSettings (BTM_VOICE_SETTING_TRANS);
569 else
570 BTM_WriteVoiceSettings (BTM_VOICE_SETTING_CVSD);
571 /* save the current codec because sco_codec can be updated while SCO is open. */
572 p_scb->inuse_codec = esco_codec;
573 #else
574 /* Allow any platform specific pre-SCO set up to take place */
575 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
576 #endif
577
578 #if (BTM_SCO_HCI_INCLUDED == TRUE )
579 #if (BTM_WBS_INCLUDED == TRUE)
580 if (esco_codec == BTA_AG_CODEC_MSBC)
581 pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_16K;
582 else
583 #endif
584 pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
585
586 sco_route = bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id);
587 #endif
588
589
590 #if (BTM_SCO_HCI_INCLUDED == TRUE )
591 /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
592 BTM_ConfigScoPath(sco_route, bta_ag_sco_read_cback, NULL, TRUE);
593 #endif
594 bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
595 }
596 else
597 p_scb->retry_with_sco_only = FALSE;
598
599 p_bd_addr = p_scb->peer_addr;
600
601 status = BTM_CreateSco(p_bd_addr, is_orig, params.packet_types,
602 &p_scb->sco_idx, bta_ag_sco_conn_cback,
603 bta_ag_sco_disc_cback);
604 if (status == BTM_CMD_STARTED)
605 {
606 if (!is_orig)
607 {
608 BTM_RegForEScoEvts(p_scb->sco_idx, bta_ag_esco_connreq_cback);
609 }
610 else /* Initiating the connection, set the current sco handle */
611 {
612 bta_ag_cb.sco.cur_idx = p_scb->sco_idx;
613 }
614 }
615
616 APPL_TRACE_API("ag create sco: orig %d, inx 0x%04x, status 0x%x, pkt types 0x%04x",
617 is_orig, p_scb->sco_idx, status, params.packet_types);
618 }
619
620 #if (BTM_WBS_INCLUDED == TRUE )
621 /*******************************************************************************
622 **
623 ** Function bta_ag_attempt_msbc_safe_settings
624 **
625 ** Description Checks if ESCO connection needs to be attempted using mSBC T1(safe) settings
626 **
627 **
628 ** Returns TRUE if T1 settings has to be used, FALSE otherwise
629 **
630 *******************************************************************************/
bta_ag_attempt_msbc_safe_settings(tBTA_AG_SCB * p_scb)631 BOOLEAN bta_ag_attempt_msbc_safe_settings(tBTA_AG_SCB *p_scb)
632 {
633 if (p_scb->svc_conn && p_scb->sco_codec == BTM_SCO_CODEC_MSBC &&
634 p_scb->codec_msbc_settings == BTA_AG_SCO_MSBC_SETTINGS_T1)
635 return TRUE;
636 else
637 return FALSE;
638 }
639
640 /*******************************************************************************
641 **
642 ** Function bta_ag_cn_timer_cback
643 **
644 ** Description
645 **
646 **
647 ** Returns void
648 **
649 *******************************************************************************/
bta_ag_cn_timer_cback(TIMER_LIST_ENT * p_tle)650 static void bta_ag_cn_timer_cback (TIMER_LIST_ENT *p_tle)
651 {
652 tBTA_AG_SCB *p_scb;
653
654 if (p_tle)
655 {
656 p_scb = (tBTA_AG_SCB *)p_tle->param;
657
658 if (p_scb)
659 {
660 /* Announce that codec negotiation failed. */
661 bta_ag_sco_codec_nego(p_scb, FALSE);
662
663 /* call app callback */
664 bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
665 }
666 }
667 }
668
669 /*******************************************************************************
670 **
671 ** Function bta_ag_codec_negotiate
672 **
673 ** Description Initiate codec negotiation by sending AT command.
674 ** If not necessary, skip negotiation.
675 **
676 ** Returns void
677 **
678 *******************************************************************************/
bta_ag_codec_negotiate(tBTA_AG_SCB * p_scb)679 void bta_ag_codec_negotiate(tBTA_AG_SCB *p_scb)
680 {
681 bta_ag_cb.sco.p_curr_scb = p_scb;
682
683 if ((p_scb->codec_updated || p_scb->codec_fallback ||
684 bta_ag_attempt_msbc_safe_settings(p_scb)) &&
685 (p_scb->peer_features & BTA_AG_PEER_FEAT_CODEC))
686 {
687 /* Change the power mode to Active until sco open is completed. */
688 bta_sys_busy(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
689
690 /* Send +BCS to the peer */
691 bta_ag_send_bcs(p_scb, NULL);
692
693 /* Start timer to handle timeout */
694 p_scb->cn_timer.p_cback = (TIMER_CBACK*)&bta_ag_cn_timer_cback;
695 p_scb->cn_timer.param = (INT32)p_scb;
696 bta_sys_start_timer(&p_scb->cn_timer, 0, BTA_AG_CODEC_NEGO_TIMEOUT);
697 }
698 else
699 {
700 /* use same codec type as previous SCO connection, skip codec negotiation */
701 APPL_TRACE_DEBUG("use same codec type as previous SCO connection,skip codec negotiation");
702 bta_ag_sco_codec_nego(p_scb, TRUE);
703 }
704 }
705 #endif /* (BTM_WBS_INCLUDED == TRUE ) */
706
707 /*******************************************************************************
708 **
709 ** Function bta_ag_sco_event
710 **
711 ** Description
712 **
713 **
714 ** Returns void
715 **
716 *******************************************************************************/
bta_ag_sco_event(tBTA_AG_SCB * p_scb,UINT8 event)717 static void bta_ag_sco_event(tBTA_AG_SCB *p_scb, UINT8 event)
718 {
719 tBTA_AG_SCO_CB *p_sco = &bta_ag_cb.sco;
720 #if (BTM_WBS_INCLUDED == TRUE )
721 tBTA_AG_SCB *p_cn_scb = NULL; /* For codec negotiation */
722 #endif
723 #if (BTM_SCO_HCI_INCLUDED == TRUE )
724 BT_HDR *p_buf;
725 #endif
726 #if BTA_AG_SCO_DEBUG == TRUE
727 UINT8 in_state = p_sco->state;
728
729 APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d (%s), Event %d (%s)",
730 p_scb->sco_idx,
731 p_sco->state, bta_ag_sco_state_str(p_sco->state),
732 event, bta_ag_sco_evt_str(event));
733 #else
734 APPL_TRACE_EVENT("BTA ag sco evt (hdl 0x%04x): State %d, Event %d",
735 p_scb->sco_idx, p_sco->state, event);
736 #endif
737
738 #if (BTM_SCO_HCI_INCLUDED == TRUE )
739 if (event == BTA_AG_SCO_CI_DATA_E)
740 {
741 while (TRUE)
742 {
743 bta_dm_sco_co_out_data(&p_buf);
744 if (p_buf)
745 {
746 if (p_sco->state == BTA_AG_SCO_OPEN_ST)
747 BTM_WriteScoData(p_sco->p_curr_scb->sco_idx, p_buf);
748 else
749 GKI_freebuf(p_buf);
750 }
751 else
752 break;
753 }
754
755 return;
756 }
757 #endif
758
759 switch (p_sco->state)
760 {
761 case BTA_AG_SCO_SHUTDOWN_ST:
762 switch (event)
763 {
764 case BTA_AG_SCO_LISTEN_E:
765 /* create sco listen connection */
766 bta_ag_create_sco(p_scb, FALSE);
767 p_sco->state = BTA_AG_SCO_LISTEN_ST;
768 break;
769
770 default:
771 APPL_TRACE_WARNING("BTA_AG_SCO_SHUTDOWN_ST: Ignoring event %d", event);
772 break;
773 }
774 break;
775
776 case BTA_AG_SCO_LISTEN_ST:
777 switch (event)
778 {
779 case BTA_AG_SCO_LISTEN_E:
780 /* create sco listen connection (Additional channel) */
781 bta_ag_create_sco(p_scb, FALSE);
782 break;
783
784 case BTA_AG_SCO_OPEN_E:
785 /* remove listening connection */
786 bta_ag_remove_sco(p_scb, FALSE);
787
788 #if (BTM_WBS_INCLUDED == TRUE )
789 /* start codec negotiation */
790 p_sco->state = BTA_AG_SCO_CODEC_ST;
791 p_cn_scb = p_scb;
792 #else
793 /* create sco connection to peer */
794 bta_ag_create_sco(p_scb, TRUE);
795 p_sco->state = BTA_AG_SCO_OPENING_ST;
796 #endif
797 break;
798
799 case BTA_AG_SCO_SHUTDOWN_E:
800 /* remove listening connection */
801 bta_ag_remove_sco(p_scb, FALSE);
802
803 if (p_scb == p_sco->p_curr_scb)
804 p_sco->p_curr_scb = NULL;
805
806 /* If last SCO instance then finish shutting down */
807 if (!bta_ag_other_scb_open(p_scb))
808 {
809 p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
810 }
811 break;
812
813 case BTA_AG_SCO_CLOSE_E:
814 /* remove listening connection */
815 /* Ignore the event. We need to keep listening SCO for the active SLC */
816 APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
817 break;
818
819 case BTA_AG_SCO_CONN_CLOSE_E:
820 /* sco failed; create sco listen connection */
821 bta_ag_create_sco(p_scb, FALSE);
822 p_sco->state = BTA_AG_SCO_LISTEN_ST;
823 break;
824
825 default:
826 APPL_TRACE_WARNING("BTA_AG_SCO_LISTEN_ST: Ignoring event %d", event);
827 break;
828 }
829 break;
830
831 #if (BTM_WBS_INCLUDED == TRUE )
832 case BTA_AG_SCO_CODEC_ST:
833 switch (event)
834 {
835 case BTA_AG_SCO_LISTEN_E:
836 /* create sco listen connection (Additional channel) */
837 bta_ag_create_sco(p_scb, FALSE);
838 break;
839
840 case BTA_AG_SCO_CN_DONE_E:
841 /* create sco connection to peer */
842 bta_ag_create_sco(p_scb, TRUE);
843 p_sco->state = BTA_AG_SCO_OPENING_ST;
844 break;
845
846 case BTA_AG_SCO_XFER_E:
847 /* save xfer scb */
848 p_sco->p_xfer_scb = p_scb;
849 p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
850 break;
851
852 case BTA_AG_SCO_SHUTDOWN_E:
853 /* remove listening connection */
854 bta_ag_remove_sco(p_scb, FALSE);
855
856 if (p_scb == p_sco->p_curr_scb)
857 p_sco->p_curr_scb = NULL;
858
859 /* If last SCO instance then finish shutting down */
860 if (!bta_ag_other_scb_open(p_scb))
861 {
862 p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
863 }
864 break;
865
866 case BTA_AG_SCO_CLOSE_E:
867 /* sco open is not started yet. just go back to listening */
868 p_sco->state = BTA_AG_SCO_LISTEN_ST;
869 break;
870
871 case BTA_AG_SCO_CONN_CLOSE_E:
872 /* sco failed; create sco listen connection */
873 bta_ag_create_sco(p_scb, FALSE);
874 p_sco->state = BTA_AG_SCO_LISTEN_ST;
875 break;
876
877 default:
878 APPL_TRACE_WARNING("BTA_AG_SCO_CODEC_ST: Ignoring event %d", event);
879 break;
880 }
881 break;
882 #endif
883
884 case BTA_AG_SCO_OPENING_ST:
885 switch (event)
886 {
887 case BTA_AG_SCO_LISTEN_E:
888 /* second headset has now joined */
889 /* create sco listen connection (Additional channel) */
890 if (p_scb != p_sco->p_curr_scb)
891 {
892 bta_ag_create_sco(p_scb, FALSE);
893 }
894 break;
895
896 #if (BTM_WBS_INCLUDED == TRUE)
897 case BTA_AG_SCO_REOPEN_E:
898 /* start codec negotiation */
899 p_sco->state = BTA_AG_SCO_CODEC_ST;
900 p_cn_scb = p_scb;
901 break;
902 #endif
903
904 case BTA_AG_SCO_XFER_E:
905 /* save xfer scb */
906 p_sco->p_xfer_scb = p_scb;
907 p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
908 break;
909
910 case BTA_AG_SCO_CLOSE_E:
911 p_sco->state = BTA_AG_SCO_OPEN_CL_ST;
912 break;
913
914 case BTA_AG_SCO_SHUTDOWN_E:
915 /* If not opening scb, just close it */
916 if (p_scb != p_sco->p_curr_scb)
917 {
918 /* remove listening connection */
919 bta_ag_remove_sco(p_scb, FALSE);
920 }
921 else
922 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
923
924 break;
925
926 case BTA_AG_SCO_CONN_OPEN_E:
927 p_sco->state = BTA_AG_SCO_OPEN_ST;
928 break;
929
930 case BTA_AG_SCO_CONN_CLOSE_E:
931 /* sco failed; create sco listen connection */
932 bta_ag_create_sco(p_scb, FALSE);
933 p_sco->state = BTA_AG_SCO_LISTEN_ST;
934 break;
935
936 default:
937 APPL_TRACE_WARNING("BTA_AG_SCO_OPENING_ST: Ignoring event %d", event);
938 break;
939 }
940 break;
941
942 case BTA_AG_SCO_OPEN_CL_ST:
943 switch (event)
944 {
945 case BTA_AG_SCO_XFER_E:
946 /* save xfer scb */
947 p_sco->p_xfer_scb = p_scb;
948
949 p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
950 break;
951
952 case BTA_AG_SCO_OPEN_E:
953 p_sco->state = BTA_AG_SCO_OPENING_ST;
954 break;
955
956 case BTA_AG_SCO_SHUTDOWN_E:
957 /* If not opening scb, just close it */
958 if (p_scb != p_sco->p_curr_scb)
959 {
960 /* remove listening connection */
961 bta_ag_remove_sco(p_scb, FALSE);
962 }
963 else
964 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
965
966 break;
967
968 case BTA_AG_SCO_CONN_OPEN_E:
969 /* close sco connection */
970 bta_ag_remove_sco(p_scb, TRUE);
971
972 p_sco->state = BTA_AG_SCO_CLOSING_ST;
973 break;
974
975 case BTA_AG_SCO_CONN_CLOSE_E:
976 /* sco failed; create sco listen connection */
977
978 p_sco->state = BTA_AG_SCO_LISTEN_ST;
979 break;
980
981 default:
982 APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_CL_ST: Ignoring event %d", event);
983 break;
984 }
985 break;
986
987 case BTA_AG_SCO_OPEN_XFER_ST:
988 switch (event)
989 {
990 case BTA_AG_SCO_CLOSE_E:
991 /* close sco connection */
992 bta_ag_remove_sco(p_scb, TRUE);
993
994 p_sco->state = BTA_AG_SCO_CLOSING_ST;
995 break;
996
997 case BTA_AG_SCO_SHUTDOWN_E:
998 /* remove all connection */
999 bta_ag_remove_sco(p_scb, FALSE);
1000 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
1001
1002 break;
1003
1004 case BTA_AG_SCO_CONN_CLOSE_E:
1005 /* closed sco; place in listen mode and
1006 accept the transferred connection */
1007 bta_ag_create_sco(p_scb, FALSE); /* Back into listen mode */
1008
1009 /* Accept sco connection with xfer scb */
1010 bta_ag_sco_conn_rsp(p_sco->p_xfer_scb, &p_sco->conn_data);
1011 p_sco->state = BTA_AG_SCO_OPENING_ST;
1012 p_sco->p_curr_scb = p_sco->p_xfer_scb;
1013 p_sco->cur_idx = p_sco->p_xfer_scb->sco_idx;
1014 p_sco->p_xfer_scb = NULL;
1015 break;
1016
1017 default:
1018 APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_XFER_ST: Ignoring event %d", event);
1019 break;
1020 }
1021 break;
1022
1023 case BTA_AG_SCO_OPEN_ST:
1024 switch (event)
1025 {
1026 case BTA_AG_SCO_LISTEN_E:
1027 /* second headset has now joined */
1028 /* create sco listen connection (Additional channel) */
1029 if (p_scb != p_sco->p_curr_scb)
1030 {
1031 bta_ag_create_sco(p_scb, FALSE);
1032 }
1033 break;
1034
1035 case BTA_AG_SCO_XFER_E:
1036 /* close current sco connection */
1037 bta_ag_remove_sco(p_sco->p_curr_scb, TRUE);
1038
1039 /* save xfer scb */
1040 p_sco->p_xfer_scb = p_scb;
1041
1042 p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
1043 break;
1044
1045 case BTA_AG_SCO_CLOSE_E:
1046 /* close sco connection if active */
1047 if (bta_ag_remove_sco(p_scb, TRUE))
1048 {
1049 p_sco->state = BTA_AG_SCO_CLOSING_ST;
1050 }
1051 break;
1052
1053 case BTA_AG_SCO_SHUTDOWN_E:
1054 /* remove all listening connections */
1055 bta_ag_remove_sco(p_scb, FALSE);
1056
1057 /* If SCO was active on this scb, close it */
1058 if (p_scb == p_sco->p_curr_scb)
1059 {
1060 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
1061 }
1062 break;
1063
1064 case BTA_AG_SCO_CONN_CLOSE_E:
1065 /* peer closed sco; create sco listen connection */
1066 bta_ag_create_sco(p_scb, FALSE);
1067 p_sco->state = BTA_AG_SCO_LISTEN_ST;
1068 break;
1069
1070 default:
1071 APPL_TRACE_WARNING("BTA_AG_SCO_OPEN_ST: Ignoring event %d", event);
1072 break;
1073 }
1074 break;
1075
1076 case BTA_AG_SCO_CLOSING_ST:
1077 switch (event)
1078 {
1079 case BTA_AG_SCO_LISTEN_E:
1080 /* create sco listen connection (Additional channel) */
1081 if (p_scb != p_sco->p_curr_scb)
1082 {
1083 bta_ag_create_sco(p_scb, FALSE);
1084 }
1085 break;
1086
1087 case BTA_AG_SCO_OPEN_E:
1088 p_sco->state = BTA_AG_SCO_CLOSE_OP_ST;
1089 break;
1090
1091 case BTA_AG_SCO_XFER_E:
1092 /* save xfer scb */
1093 p_sco->p_xfer_scb = p_scb;
1094
1095 p_sco->state = BTA_AG_SCO_CLOSE_XFER_ST;
1096 break;
1097
1098 case BTA_AG_SCO_SHUTDOWN_E:
1099 /* If not closing scb, just close it */
1100 if (p_scb != p_sco->p_curr_scb)
1101 {
1102 /* remove listening connection */
1103 bta_ag_remove_sco(p_scb, FALSE);
1104 }
1105 else
1106 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
1107
1108 break;
1109
1110 case BTA_AG_SCO_CONN_CLOSE_E:
1111 /* peer closed sco; create sco listen connection */
1112 bta_ag_create_sco(p_scb, FALSE);
1113
1114 p_sco->state = BTA_AG_SCO_LISTEN_ST;
1115 break;
1116
1117 default:
1118 APPL_TRACE_WARNING("BTA_AG_SCO_CLOSING_ST: Ignoring event %d", event);
1119 break;
1120 }
1121 break;
1122
1123 case BTA_AG_SCO_CLOSE_OP_ST:
1124 switch (event)
1125 {
1126 case BTA_AG_SCO_CLOSE_E:
1127 p_sco->state = BTA_AG_SCO_CLOSING_ST;
1128 break;
1129
1130 case BTA_AG_SCO_SHUTDOWN_E:
1131 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
1132 break;
1133
1134 case BTA_AG_SCO_CONN_CLOSE_E:
1135 #if (BTM_WBS_INCLUDED == TRUE )
1136 /* start codec negotiation */
1137 p_sco->state = BTA_AG_SCO_CODEC_ST;
1138 p_cn_scb = p_scb;
1139 #else
1140 /* open sco connection */
1141 bta_ag_create_sco(p_scb, TRUE);
1142 p_sco->state = BTA_AG_SCO_OPENING_ST;
1143 #endif
1144 break;
1145
1146 case BTA_AG_SCO_LISTEN_E:
1147 /* create sco listen connection (Additional channel) */
1148 if (p_scb != p_sco->p_curr_scb)
1149 {
1150 bta_ag_create_sco(p_scb, FALSE);
1151 }
1152 break;
1153
1154 default:
1155 APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_OP_ST: Ignoring event %d", event);
1156 break;
1157 }
1158 break;
1159
1160 case BTA_AG_SCO_CLOSE_XFER_ST:
1161 switch (event)
1162 {
1163 case BTA_AG_SCO_CONN_OPEN_E:
1164 /* close sco connection so headset can be transferred
1165 Probably entered this state from "opening state" */
1166 bta_ag_remove_sco(p_scb, TRUE);
1167 break;
1168
1169 case BTA_AG_SCO_CLOSE_E:
1170 /* clear xfer scb */
1171 p_sco->p_xfer_scb = NULL;
1172
1173 p_sco->state = BTA_AG_SCO_CLOSING_ST;
1174 break;
1175
1176 case BTA_AG_SCO_SHUTDOWN_E:
1177 /* clear xfer scb */
1178 p_sco->p_xfer_scb = NULL;
1179
1180 p_sco->state = BTA_AG_SCO_SHUTTING_ST;
1181 break;
1182
1183 case BTA_AG_SCO_CONN_CLOSE_E:
1184 /* closed sco; place old sco in listen mode,
1185 take current sco out of listen, and
1186 create originating sco for current */
1187 bta_ag_create_sco(p_scb, FALSE);
1188 bta_ag_remove_sco(p_sco->p_xfer_scb, FALSE);
1189
1190 #if (BTM_WBS_INCLUDED == TRUE )
1191 /* start codec negotiation */
1192 p_sco->state = BTA_AG_SCO_CODEC_ST;
1193 p_cn_scb = p_sco->p_xfer_scb;
1194 p_sco->p_xfer_scb = NULL;
1195 #else
1196 /* create sco connection to peer */
1197 bta_ag_create_sco(p_sco->p_xfer_scb, TRUE);
1198 p_sco->p_xfer_scb = NULL;
1199 p_sco->state = BTA_AG_SCO_OPENING_ST;
1200 #endif
1201 break;
1202
1203 default:
1204 APPL_TRACE_WARNING("BTA_AG_SCO_CLOSE_XFER_ST: Ignoring event %d", event);
1205 break;
1206 }
1207 break;
1208
1209 case BTA_AG_SCO_SHUTTING_ST:
1210 switch (event)
1211 {
1212 case BTA_AG_SCO_CONN_OPEN_E:
1213 /* close sco connection; wait for conn close event */
1214 bta_ag_remove_sco(p_scb, TRUE);
1215 break;
1216
1217 case BTA_AG_SCO_CONN_CLOSE_E:
1218 /* If last SCO instance then finish shutting down */
1219 if (!bta_ag_other_scb_open(p_scb))
1220 {
1221 p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
1222 }
1223 else /* Other instance is still listening */
1224 {
1225 p_sco->state = BTA_AG_SCO_LISTEN_ST;
1226 }
1227
1228 if (p_scb == p_sco->p_curr_scb)
1229 {
1230 p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
1231 p_sco->p_curr_scb = NULL;
1232 }
1233 break;
1234
1235 case BTA_AG_SCO_LISTEN_E:
1236 /* create sco listen connection (Additional channel) */
1237 if (p_scb != p_sco->p_curr_scb)
1238 {
1239 bta_ag_create_sco(p_scb, FALSE);
1240 }
1241 break;
1242
1243 case BTA_AG_SCO_SHUTDOWN_E:
1244 if (!bta_ag_other_scb_open(p_scb))
1245 {
1246 p_sco->state = BTA_AG_SCO_SHUTDOWN_ST;
1247 }
1248 else /* Other instance is still listening */
1249 {
1250 p_sco->state = BTA_AG_SCO_LISTEN_ST;
1251 }
1252
1253 if (p_scb == p_sco->p_curr_scb)
1254 {
1255 p_sco->p_curr_scb->sco_idx = BTM_INVALID_SCO_INDEX;
1256 p_sco->p_curr_scb = NULL;
1257 }
1258 break;
1259
1260 default:
1261 APPL_TRACE_WARNING("BTA_AG_SCO_SHUTTING_ST: Ignoring event %d", event);
1262 break;
1263 }
1264 break;
1265
1266 default:
1267 break;
1268 }
1269 #if BTA_AG_SCO_DEBUG == TRUE
1270 if (p_sco->state != in_state)
1271 {
1272 APPL_TRACE_EVENT("BTA AG SCO State Change: [%s] -> [%s] after Event [%s]",
1273 bta_ag_sco_state_str(in_state),
1274 bta_ag_sco_state_str(p_sco->state),
1275 bta_ag_sco_evt_str(event));
1276 }
1277 #endif
1278
1279 #if (BTM_WBS_INCLUDED == TRUE )
1280 if (p_cn_scb)
1281 {
1282 bta_ag_codec_negotiate(p_cn_scb);
1283 }
1284 #endif
1285 }
1286
1287 /*******************************************************************************
1288 **
1289 ** Function bta_ag_sco_is_open
1290 **
1291 ** Description Check if sco is open for this scb.
1292 **
1293 **
1294 ** Returns TRUE if sco open for this scb, FALSE otherwise.
1295 **
1296 *******************************************************************************/
bta_ag_sco_is_open(tBTA_AG_SCB * p_scb)1297 BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb)
1298 {
1299 return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_ST) &&
1300 (bta_ag_cb.sco.p_curr_scb == p_scb));
1301 }
1302
1303 /*******************************************************************************
1304 **
1305 ** Function bta_ag_sco_is_opening
1306 **
1307 ** Description Check if sco is in Opening state.
1308 **
1309 **
1310 ** Returns TRUE if sco is in Opening state for this scb, FALSE otherwise.
1311 **
1312 *******************************************************************************/
bta_ag_sco_is_opening(tBTA_AG_SCB * p_scb)1313 BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb)
1314 {
1315 #if (BTM_WBS_INCLUDED == TRUE )
1316 return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) ||
1317 (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) &&
1318 (bta_ag_cb.sco.p_curr_scb == p_scb));
1319 #else
1320 return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) &&
1321 (bta_ag_cb.sco.p_curr_scb == p_scb));
1322 #endif
1323 }
1324
1325 /*******************************************************************************
1326 **
1327 ** Function bta_ag_sco_listen
1328 **
1329 ** Description
1330 **
1331 **
1332 ** Returns void
1333 **
1334 *******************************************************************************/
bta_ag_sco_listen(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1335 void bta_ag_sco_listen(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1336 {
1337 UNUSED(p_data);
1338 bta_ag_sco_event(p_scb, BTA_AG_SCO_LISTEN_E);
1339 }
1340
1341 /*******************************************************************************
1342 **
1343 ** Function bta_ag_sco_open
1344 **
1345 ** Description
1346 **
1347 **
1348 ** Returns void
1349 **
1350 *******************************************************************************/
bta_ag_sco_open(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1351 void bta_ag_sco_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1352 {
1353 UINT8 event;
1354 UNUSED(p_data);
1355
1356 /* if another scb using sco, this is a transfer */
1357 if (bta_ag_cb.sco.p_curr_scb != NULL && bta_ag_cb.sco.p_curr_scb != p_scb)
1358 {
1359 event = BTA_AG_SCO_XFER_E;
1360 }
1361 /* else it is an open */
1362 else
1363 {
1364 event = BTA_AG_SCO_OPEN_E;
1365 }
1366
1367 bta_ag_sco_event(p_scb, event);
1368 }
1369
1370 /*******************************************************************************
1371 **
1372 ** Function bta_ag_sco_close
1373 **
1374 ** Description
1375 **
1376 **
1377 ** Returns void
1378 **
1379 *******************************************************************************/
bta_ag_sco_close(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1380 void bta_ag_sco_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1381 {
1382 UNUSED(p_data);
1383
1384 /* if scb is in use */
1385 #if (BTM_WBS_INCLUDED == TRUE )
1386 /* sco_idx is not allocated in SCO_CODEC_ST, we still need to move to listening state. */
1387 if ((p_scb->sco_idx != BTM_INVALID_SCO_INDEX) || (bta_ag_cb.sco.state == BTA_AG_SCO_CODEC_ST))
1388 #else
1389 if (p_scb->sco_idx != BTM_INVALID_SCO_INDEX)
1390 #endif
1391 {
1392 APPL_TRACE_DEBUG("bta_ag_sco_close: sco_inx = %d", p_scb->sco_idx);
1393 bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
1394 }
1395 }
1396
1397 #if (BTM_WBS_INCLUDED == TRUE )
1398
1399 /*******************************************************************************
1400 **
1401 ** Function bta_ag_sco_codec_nego
1402 **
1403 ** Description
1404 **
1405 **
1406 ** Returns void
1407 **
1408 *******************************************************************************/
bta_ag_sco_codec_nego(tBTA_AG_SCB * p_scb,BOOLEAN result)1409 void bta_ag_sco_codec_nego(tBTA_AG_SCB *p_scb, BOOLEAN result)
1410 {
1411 if(result == TRUE)
1412 {
1413 /* Subsequent sco connection will skip codec negotiation */
1414 p_scb->codec_updated = FALSE;
1415
1416 bta_ag_sco_event(p_scb, BTA_AG_SCO_CN_DONE_E);
1417 }
1418 else /* codec negotiation failed */
1419 bta_ag_sco_event(p_scb, BTA_AG_SCO_CLOSE_E);
1420 }
1421 #endif
1422
1423 /*******************************************************************************
1424 **
1425 ** Function bta_ag_sco_shutdown
1426 **
1427 ** Description
1428 **
1429 **
1430 ** Returns void
1431 **
1432 *******************************************************************************/
bta_ag_sco_shutdown(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1433 void bta_ag_sco_shutdown(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1434 {
1435 UNUSED(p_data);
1436
1437 bta_ag_sco_event(p_scb, BTA_AG_SCO_SHUTDOWN_E);
1438 }
1439
1440 /*******************************************************************************
1441 **
1442 ** Function bta_ag_sco_conn_open
1443 **
1444 ** Description
1445 **
1446 **
1447 ** Returns void
1448 **
1449 *******************************************************************************/
bta_ag_sco_conn_open(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1450 void bta_ag_sco_conn_open(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1451 {
1452 UNUSED(p_data);
1453
1454 bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_OPEN_E);
1455
1456 bta_sys_sco_open(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1457
1458 #if (BTM_WBS_INCLUDED == TRUE)
1459 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON,
1460 p_scb->inuse_codec);
1461 #else
1462 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_ON);
1463 #endif
1464
1465 #if (BTM_SCO_HCI_INCLUDED == TRUE )
1466 /* open SCO codec if SCO is routed through transport */
1467 bta_dm_sco_co_open(bta_ag_scb_to_idx(p_scb), BTA_SCO_OUT_PKT_SIZE, BTA_AG_CI_SCO_DATA_EVT);
1468 #endif
1469
1470 /* call app callback */
1471 bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_OPEN_EVT);
1472
1473 p_scb->retry_with_sco_only = FALSE;
1474 #if (BTM_WBS_INCLUDED == TRUE)
1475 /* reset to mSBC T2 settings as the preferred */
1476 p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
1477 #endif
1478 }
1479
1480 /*******************************************************************************
1481 **
1482 ** Function bta_ag_sco_conn_close
1483 **
1484 ** Description
1485 **
1486 **
1487 ** Returns void
1488 **
1489 *******************************************************************************/
bta_ag_sco_conn_close(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1490 void bta_ag_sco_conn_close(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1491 {
1492 UINT16 handle = bta_ag_scb_to_idx(p_scb);
1493 UNUSED(p_data);
1494
1495 /* clear current scb */
1496 bta_ag_cb.sco.p_curr_scb = NULL;
1497 p_scb->sco_idx = BTM_INVALID_SCO_INDEX;
1498
1499 #if (BTM_WBS_INCLUDED == TRUE)
1500 /* codec_fallback is set when AG is initiator and connection failed for mSBC. */
1501 /* OR if codec is msbc and T2 settings failed, then retry Safe T1 settings */
1502 if ((p_scb->codec_fallback && p_scb->svc_conn) ||
1503 bta_ag_attempt_msbc_safe_settings(p_scb))
1504 {
1505 bta_ag_sco_event(p_scb, BTA_AG_SCO_REOPEN_E);
1506 }
1507 else if (p_scb->retry_with_sco_only && p_scb->svc_conn)
1508 {
1509 /* retry_with_sco_only is set when AG is initiator and connection failed for eSCO */
1510 bta_ag_create_sco(p_scb, TRUE);
1511 }
1512 #else
1513 /* retry_with_sco_only, will be set only when AG is initiator
1514 ** and AG is first trying to establish an eSCO connection */
1515 if (p_scb->retry_with_sco_only && p_scb->svc_conn)
1516 {
1517 bta_ag_create_sco(p_scb, TRUE);
1518 }
1519 #endif
1520 else
1521 {
1522 #if (BTM_WBS_INCLUDED == TRUE)
1523 /* Indicate if the closing of audio is because of transfer */
1524 bta_ag_co_audio_state(handle, p_scb->app_id,(bta_ag_cb.sco.p_xfer_scb)?\
1525 BTA_AG_CO_AUD_STATE_OFF_XFER:BTA_AG_CO_AUD_STATE_OFF,p_scb->inuse_codec);
1526 #else
1527 /* Indicate if the closing of audio is because of transfer */
1528 bta_ag_co_audio_state(handle, p_scb->app_id,(bta_ag_cb.sco.p_xfer_scb)?\
1529 BTA_AG_CO_AUD_STATE_OFF_XFER:BTA_AG_CO_AUD_STATE_OFF);
1530 #endif
1531 bta_ag_sco_event(p_scb, BTA_AG_SCO_CONN_CLOSE_E);
1532
1533 bta_sys_sco_close(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1534
1535 /* if av got suspended by this call, let it resume. */
1536 /* In case call stays alive regardless of sco, av should not be affected. */
1537 if(((p_scb->call_ind == BTA_AG_CALL_INACTIVE) && (p_scb->callsetup_ind == BTA_AG_CALLSETUP_NONE))
1538 || (p_scb->post_sco == BTA_AG_POST_SCO_CALL_END))
1539 {
1540 bta_sys_sco_unuse(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1541 }
1542
1543 /* call app callback */
1544 bta_ag_cback_sco(p_scb, BTA_AG_AUDIO_CLOSE_EVT);
1545 #if (BTM_WBS_INCLUDED == TRUE)
1546 p_scb->codec_msbc_settings = BTA_AG_SCO_MSBC_SETTINGS_T2;
1547 #endif
1548 }
1549 p_scb->retry_with_sco_only = FALSE;
1550 }
1551
1552 /*******************************************************************************
1553 **
1554 ** Function bta_ag_sco_conn_rsp
1555 **
1556 ** Description Process the SCO connection request
1557 **
1558 **
1559 ** Returns void
1560 **
1561 *******************************************************************************/
bta_ag_sco_conn_rsp(tBTA_AG_SCB * p_scb,tBTM_ESCO_CONN_REQ_EVT_DATA * p_data)1562 void bta_ag_sco_conn_rsp(tBTA_AG_SCB *p_scb, tBTM_ESCO_CONN_REQ_EVT_DATA *p_data)
1563 {
1564 tBTM_ESCO_PARAMS resp;
1565 UINT8 hci_status = HCI_SUCCESS;
1566 #if (BTM_SCO_HCI_INCLUDED == TRUE )
1567 tBTA_CODEC_INFO codec_info = {BTA_SCO_CODEC_PCM};
1568 UINT32 pcm_sample_rate;
1569 #endif
1570
1571 if (bta_ag_cb.sco.state == BTA_AG_SCO_LISTEN_ST ||
1572 bta_ag_cb.sco.state == BTA_AG_SCO_CLOSE_XFER_ST ||
1573 bta_ag_cb.sco.state == BTA_AG_SCO_OPEN_XFER_ST)
1574 {
1575 /* If script overrided sco parameter by BTA_CMD_SET_ESCO_PARAM */
1576 if (bta_ag_cb.sco.param_updated)
1577 {
1578 resp = bta_ag_cb.sco.params;
1579 }
1580 else
1581 {
1582 resp.rx_bw = BTM_64KBITS_RATE;
1583 resp.tx_bw = BTM_64KBITS_RATE;
1584 resp.max_latency = 10;
1585 resp.voice_contfmt = 0x60;
1586 resp.retrans_effort = BTM_ESCO_RETRANS_POWER;
1587
1588 if (p_data->link_type == BTM_LINK_TYPE_SCO)
1589 {
1590 resp.packet_types = (BTM_SCO_LINK_ONLY_MASK |
1591 BTM_SCO_PKT_TYPES_MASK_NO_2_EV3 |
1592 BTM_SCO_PKT_TYPES_MASK_NO_3_EV3 |
1593 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
1594 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
1595 }
1596 else /* Allow controller to use all types available except 5-slot EDR */
1597 {
1598 resp.packet_types = (BTM_SCO_LINK_ALL_PKT_MASK |
1599 BTM_SCO_PKT_TYPES_MASK_NO_2_EV5 |
1600 BTM_SCO_PKT_TYPES_MASK_NO_3_EV5);
1601 }
1602 }
1603
1604 /* tell sys to stop av if any */
1605 bta_sys_sco_use(BTA_ID_AG, p_scb->app_id, p_scb->peer_addr);
1606
1607 #if (BTM_WBS_INCLUDED == FALSE )
1608 /* Allow any platform specific pre-SCO set up to take place */
1609 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP);
1610 #else
1611 /* When HS initiated SCO, it cannot be WBS. */
1612 /* Allow any platform specific pre-SCO set up to take place */
1613 bta_ag_co_audio_state(bta_ag_scb_to_idx(p_scb), p_scb->app_id, BTA_AG_CO_AUD_STATE_SETUP,
1614 BTA_AG_CODEC_CVSD);
1615 #endif
1616
1617 #if (BTM_SCO_HCI_INCLUDED == TRUE )
1618 pcm_sample_rate = BTA_DM_SCO_SAMP_RATE_8K;
1619
1620 /* initialize SCO setup, no voice setting for AG, data rate <==> sample rate */
1621 BTM_ConfigScoPath(bta_dm_sco_co_init(pcm_sample_rate, pcm_sample_rate, &codec_info, p_scb->app_id),
1622 bta_ag_sco_read_cback, NULL, TRUE);
1623 #endif
1624 }
1625 else
1626 hci_status = HCI_ERR_HOST_REJECT_DEVICE;
1627
1628 #if (BTM_WBS_INCLUDED == TRUE )
1629 /* If SCO open was initiated from HS, it must be CVSD */
1630 p_scb->inuse_codec = BTA_AG_CODEC_NONE;
1631 #endif
1632
1633 BTM_EScoConnRsp(p_data->sco_inx, hci_status, &resp);
1634 }
1635
1636 /*******************************************************************************
1637 **
1638 ** Function bta_ag_ci_sco_data
1639 **
1640 ** Description Process the SCO data ready callin event
1641 **
1642 **
1643 ** Returns void
1644 **
1645 *******************************************************************************/
bta_ag_ci_sco_data(tBTA_AG_SCB * p_scb,tBTA_AG_DATA * p_data)1646 void bta_ag_ci_sco_data(tBTA_AG_SCB *p_scb, tBTA_AG_DATA *p_data)
1647 {
1648 UNUSED(p_scb);
1649 UNUSED(p_data);
1650
1651 #if (BTM_SCO_HCI_INCLUDED == TRUE )
1652 bta_ag_sco_event(p_scb, BTA_AG_SCO_CI_DATA_E);
1653 #endif
1654 }
1655
1656 /*******************************************************************************
1657 **
1658 ** Function bta_ag_set_esco_param
1659 **
1660 ** Description Update esco parameters from script wrapper.
1661 **
1662 **
1663 ** Returns void
1664 **
1665 *******************************************************************************/
bta_ag_set_esco_param(BOOLEAN set_reset,tBTM_ESCO_PARAMS * param)1666 void bta_ag_set_esco_param(BOOLEAN set_reset, tBTM_ESCO_PARAMS *param)
1667 {
1668 if(set_reset == FALSE) /* reset the parameters to default */
1669 {
1670 bta_ag_cb.sco.param_updated = FALSE;
1671 APPL_TRACE_DEBUG("bta_ag_set_esco_param : Resetting ESCO parameters to default");
1672 }
1673 else
1674 {
1675 bta_ag_cb.sco.param_updated = TRUE;
1676 bta_ag_cb.sco.params = *param;
1677 APPL_TRACE_DEBUG("bta_ag_set_esco_param : Setting ESCO parameters");
1678 }
1679 }
1680
1681 /*******************************************************************************
1682 ** Debugging functions
1683 *******************************************************************************/
1684
1685 #if BTA_AG_SCO_DEBUG == TRUE
bta_ag_sco_evt_str(UINT8 event)1686 static char *bta_ag_sco_evt_str(UINT8 event)
1687 {
1688 switch (event)
1689 {
1690 case BTA_AG_SCO_LISTEN_E:
1691 return "Listen Request";
1692 case BTA_AG_SCO_OPEN_E:
1693 return "Open Request";
1694 case BTA_AG_SCO_XFER_E:
1695 return "Transfer Request";
1696 #if (BTM_WBS_INCLUDED == TRUE )
1697 case BTA_AG_SCO_CN_DONE_E:
1698 return "Codec Negotiation Done";
1699 case BTA_AG_SCO_REOPEN_E:
1700 return "Reopen Request";
1701 #endif
1702 case BTA_AG_SCO_CLOSE_E:
1703 return "Close Request";
1704 case BTA_AG_SCO_SHUTDOWN_E:
1705 return "Shutdown Request";
1706 case BTA_AG_SCO_CONN_OPEN_E:
1707 return "Opened";
1708 case BTA_AG_SCO_CONN_CLOSE_E:
1709 return "Closed";
1710 case BTA_AG_SCO_CI_DATA_E :
1711 return "Sco Data";
1712 default:
1713 return "Unknown SCO Event";
1714 }
1715 }
1716
bta_ag_sco_state_str(UINT8 state)1717 static char *bta_ag_sco_state_str(UINT8 state)
1718 {
1719 switch (state)
1720 {
1721 case BTA_AG_SCO_SHUTDOWN_ST:
1722 return "Shutdown";
1723 case BTA_AG_SCO_LISTEN_ST:
1724 return "Listening";
1725 #if (BTM_WBS_INCLUDED == TRUE )
1726 case BTA_AG_SCO_CODEC_ST:
1727 return "Codec Negotiation";
1728 #endif
1729 case BTA_AG_SCO_OPENING_ST:
1730 return "Opening";
1731 case BTA_AG_SCO_OPEN_CL_ST:
1732 return "Open while closing";
1733 case BTA_AG_SCO_OPEN_XFER_ST:
1734 return "Opening while Transferring";
1735 case BTA_AG_SCO_OPEN_ST:
1736 return "Open";
1737 case BTA_AG_SCO_CLOSING_ST:
1738 return "Closing";
1739 case BTA_AG_SCO_CLOSE_OP_ST:
1740 return "Close while Opening";
1741 case BTA_AG_SCO_CLOSE_XFER_ST:
1742 return "Close while Transferring";
1743 case BTA_AG_SCO_SHUTTING_ST:
1744 return "Shutting Down";
1745 default:
1746 return "Unknown SCO State";
1747 }
1748 }
1749
1750 #endif
1751