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