avdt_ccb_act.cc revision 8d749047a084b2d8a18fcaaac5c585e97a16f58d
1/****************************************************************************** 2 * 3 * Copyright (C) 2006-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 module contains the action functions associated with the channel 22 * control block state machine. 23 * 24 ******************************************************************************/ 25 26#include <string.h> 27#include "avdt_api.h" 28#include "avdt_int.h" 29#include "avdtc_api.h" 30#include "bt_common.h" 31#include "bt_target.h" 32#include "bt_types.h" 33#include "bt_utils.h" 34#include "btm_api.h" 35#include "btu.h" 36#include "osi/include/osi.h" 37 38/******************************************************************************* 39 * 40 * Function avdt_ccb_clear_ccb 41 * 42 * Description This function clears out certain buffers, queues, and 43 * other data elements of a ccb. 44 * 45 * 46 * Returns void. 47 * 48 ******************************************************************************/ 49static void avdt_ccb_clear_ccb(tAVDT_CCB* p_ccb) { 50 BT_HDR* p_buf; 51 52 /* clear certain ccb variables */ 53 p_ccb->cong = false; 54 p_ccb->ret_count = 0; 55 56 /* free message being fragmented */ 57 osi_free_and_reset((void**)&p_ccb->p_curr_msg); 58 59 /* free message being reassembled */ 60 osi_free_and_reset((void**)&p_ccb->p_rx_msg); 61 62 /* clear out response queue */ 63 while ((p_buf = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) 64 osi_free(p_buf); 65} 66 67/******************************************************************************* 68 * 69 * Function avdt_ccb_chan_open 70 * 71 * Description This function calls avdt_ad_open_req() to 72 * initiate a signaling channel connection. 73 * 74 * 75 * Returns void. 76 * 77 ******************************************************************************/ 78void avdt_ccb_chan_open(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 79 BTM_SetOutService(p_ccb->peer_addr, BTM_SEC_SERVICE_AVDTP, AVDT_CHAN_SIG); 80 avdt_ad_open_req(AVDT_CHAN_SIG, p_ccb, NULL, AVDT_INT); 81} 82 83/******************************************************************************* 84 * 85 * Function avdt_ccb_chan_close 86 * 87 * Description This function calls avdt_ad_close_req() to close a 88 * signaling channel connection. 89 * 90 * 91 * Returns void. 92 * 93 ******************************************************************************/ 94void avdt_ccb_chan_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 95 /* close the transport channel used by this CCB */ 96 avdt_ad_close_req(AVDT_CHAN_SIG, p_ccb, NULL); 97} 98 99/******************************************************************************* 100 * 101 * Function avdt_ccb_chk_close 102 * 103 * Description This function checks for active streams on this CCB. 104 * If there are none, it starts an idle timer. 105 * 106 * 107 * Returns void. 108 * 109 ******************************************************************************/ 110void avdt_ccb_chk_close(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 111 int i; 112 tAVDT_SCB* p_scb = &avdt_cb.scb[0]; 113 114 /* see if there are any active scbs associated with this ccb */ 115 for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { 116 if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { 117 break; 118 } 119 } 120 121 /* if no active scbs start idle timer */ 122 if (i == AVDT_NUM_SEPS) { 123 alarm_cancel(p_ccb->ret_ccb_timer); 124 alarm_cancel(p_ccb->rsp_ccb_timer); 125 period_ms_t interval_ms = avdt_cb.rcb.idle_tout * 1000; 126 alarm_set_on_mloop(p_ccb->idle_ccb_timer, interval_ms, 127 avdt_ccb_idle_ccb_timer_timeout, p_ccb); 128 } 129} 130 131/******************************************************************************* 132 * 133 * Function avdt_ccb_hdl_discover_cmd 134 * 135 * Description This function is called when a discover command is 136 * received from the peer. It gathers up the stream 137 * information for all allocated streams and initiates 138 * sending of a discover response. 139 * 140 * 141 * Returns void. 142 * 143 ******************************************************************************/ 144void avdt_ccb_hdl_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 145 tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS]; 146 tAVDT_SCB* p_scb = &avdt_cb.scb[0]; 147 int i; 148 149 p_data->msg.discover_rsp.p_sep_info = sep_info; 150 p_data->msg.discover_rsp.num_seps = 0; 151 152 /* for all allocated scbs */ 153 for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { 154 if (p_scb->allocated) { 155 /* copy sep info */ 156 sep_info[p_data->msg.discover_rsp.num_seps].in_use = p_scb->in_use; 157 sep_info[p_data->msg.discover_rsp.num_seps].seid = i + 1; 158 sep_info[p_data->msg.discover_rsp.num_seps].media_type = 159 p_scb->cs.media_type; 160 sep_info[p_data->msg.discover_rsp.num_seps].tsep = p_scb->cs.tsep; 161 162 p_data->msg.discover_rsp.num_seps++; 163 } 164 } 165 166 /* send response */ 167 avdt_ccb_event(p_ccb, AVDT_CCB_API_DISCOVER_RSP_EVT, p_data); 168} 169 170/******************************************************************************* 171 * 172 * Function avdt_ccb_hdl_discover_rsp 173 * 174 * Description This function is called when a discover response or 175 * reject is received from the peer. It calls the application 176 * callback function with the results. 177 * 178 * 179 * Returns void. 180 * 181 ******************************************************************************/ 182void avdt_ccb_hdl_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 183 /* we're done with procedure */ 184 p_ccb->proc_busy = false; 185 186 /* call app callback with results */ 187 (*p_ccb->proc_cback)(0, &p_ccb->peer_addr, AVDT_DISCOVER_CFM_EVT, 188 (tAVDT_CTRL*)(&p_data->msg.discover_rsp)); 189} 190 191/******************************************************************************* 192 * 193 * Function avdt_ccb_hdl_getcap_cmd 194 * 195 * Description This function is called when a get capabilities command 196 * is received from the peer. It retrieves the stream 197 * configuration for the requested stream and initiates 198 * sending of a get capabilities response. 199 * 200 * 201 * Returns void. 202 * 203 ******************************************************************************/ 204void avdt_ccb_hdl_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 205 tAVDT_SCB* p_scb; 206 207 /* look up scb for seid sent to us */ 208 p_scb = avdt_scb_by_hdl(p_data->msg.single.seid); 209 210 p_data->msg.svccap.p_cfg = &p_scb->cs.cfg; 211 212 avdt_ccb_event(p_ccb, AVDT_CCB_API_GETCAP_RSP_EVT, p_data); 213} 214 215/******************************************************************************* 216 * 217 * Function avdt_ccb_hdl_getcap_rsp 218 * 219 * Description This function is called with a get capabilities response 220 * or reject is received from the peer. It calls the 221 * application callback function with the results. 222 * 223 * 224 * Returns void. 225 * 226 ******************************************************************************/ 227void avdt_ccb_hdl_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 228 /* we're done with procedure */ 229 p_ccb->proc_busy = false; 230 231 /* call app callback with results */ 232 (*p_ccb->proc_cback)(0, &p_ccb->peer_addr, AVDT_GETCAP_CFM_EVT, 233 (tAVDT_CTRL*)(&p_data->msg.svccap)); 234} 235 236/******************************************************************************* 237 * 238 * Function avdt_ccb_hdl_start_cmd 239 * 240 * Description This function is called when a start command is received 241 * from the peer. It verifies that all requested streams 242 * are in the proper state. If so, it initiates sending of 243 * a start response. Otherwise it sends a start reject. 244 * 245 * 246 * Returns void. 247 * 248 ******************************************************************************/ 249void avdt_ccb_hdl_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 250 uint8_t err_code = 0; 251 252 /* verify all streams in the right state */ 253 uint8_t seid = 254 avdt_scb_verify(p_ccb, AVDT_VERIFY_START, p_data->msg.multi.seid_list, 255 p_data->msg.multi.num_seps, &err_code); 256 if (seid == 0 && err_code == 0) { 257 /* we're ok, send response */ 258 avdt_ccb_event(p_ccb, AVDT_CCB_API_START_RSP_EVT, p_data); 259 } else { 260 /* not ok, send reject */ 261 p_data->msg.hdr.err_code = err_code; 262 p_data->msg.hdr.err_param = seid; 263 avdt_msg_send_rej(p_ccb, AVDT_SIG_START, &p_data->msg); 264 } 265} 266 267/******************************************************************************* 268 * 269 * Function avdt_ccb_hdl_start_rsp 270 * 271 * Description This function is called when a start response or reject 272 * is received from the peer. Using the SEIDs stored in the 273 * current command message, it sends a start response or start 274 * reject event to each SCB associated with the command. 275 * 276 * 277 * Returns void. 278 * 279 ******************************************************************************/ 280void avdt_ccb_hdl_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 281 uint8_t event; 282 int i; 283 uint8_t* p; 284 tAVDT_SCB* p_scb; 285 286 /* determine rsp or rej event */ 287 event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_START_RSP_EVT 288 : AVDT_SCB_MSG_START_REJ_EVT; 289 290 /* get to where seid's are stashed in current cmd */ 291 p = (uint8_t*)(p_ccb->p_curr_cmd + 1); 292 293 /* little trick here; length of current command equals number of streams */ 294 for (i = 0; i < p_ccb->p_curr_cmd->len; i++) { 295 p_scb = avdt_scb_by_hdl(p[i]); 296 if (p_scb != NULL) { 297 avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT*)&p_data->msg); 298 } 299 } 300} 301 302/******************************************************************************* 303 * 304 * Function avdt_ccb_hdl_suspend_cmd 305 * 306 * Description This function is called when a suspend command is received 307 * from the peer. It verifies that all requested streams are 308 * in the proper state. If so, it initiates sending of a 309 * suspend response. Otherwise it sends a suspend reject. 310 311 * 312 * 313 * Returns void. 314 * 315 ******************************************************************************/ 316void avdt_ccb_hdl_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 317 uint8_t seid; 318 uint8_t err_code = 0; 319 320 /* verify all streams in the right state */ 321 if ((seid = avdt_scb_verify(p_ccb, AVDT_VERIFY_SUSPEND, 322 p_data->msg.multi.seid_list, 323 p_data->msg.multi.num_seps, &err_code)) == 0 && 324 err_code == 0) { 325 /* we're ok, send response */ 326 avdt_ccb_event(p_ccb, AVDT_CCB_API_SUSPEND_RSP_EVT, p_data); 327 } else { 328 /* not ok, send reject */ 329 p_data->msg.hdr.err_code = err_code; 330 p_data->msg.hdr.err_param = seid; 331 avdt_msg_send_rej(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); 332 } 333} 334 335/******************************************************************************* 336 * 337 * Function avdt_ccb_hdl_suspend_rsp 338 * 339 * Description This function is called when a suspend response or reject 340 * is received from the peer. Using the SEIDs stored in the 341 * current command message, it sends a suspend response or 342 * suspend reject event to each SCB associated with the 343 * command. 344 * 345 * 346 * 347 * Returns void. 348 * 349 ******************************************************************************/ 350void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 351 uint8_t event; 352 int i; 353 uint8_t* p; 354 tAVDT_SCB* p_scb; 355 356 /* determine rsp or rej event */ 357 event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_SUSPEND_RSP_EVT 358 : AVDT_SCB_MSG_SUSPEND_REJ_EVT; 359 360 /* get to where seid's are stashed in current cmd */ 361 p = (uint8_t*)(p_ccb->p_curr_cmd + 1); 362 363 /* little trick here; length of current command equals number of streams */ 364 for (i = 0; i < p_ccb->p_curr_cmd->len; i++) { 365 p_scb = avdt_scb_by_hdl(p[i]); 366 if (p_scb != NULL) { 367 avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT*)&p_data->msg); 368 } 369 } 370} 371 372/******************************************************************************* 373 * 374 * Function avdt_ccb_snd_discover_cmd 375 * 376 * Description This function is called to send a discover command to the 377 * peer. It copies variables needed for the procedure from 378 * the event to the CCB. It marks the CCB as busy and then 379 * sends a discover command. 380 * 381 * 382 * Returns void. 383 * 384 ******************************************************************************/ 385void avdt_ccb_snd_discover_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 386 /* store info in ccb struct */ 387 p_ccb->p_proc_data = p_data->discover.p_sep_info; 388 p_ccb->proc_cback = p_data->discover.p_cback; 389 p_ccb->proc_param = p_data->discover.num_seps; 390 391 /* we're busy */ 392 p_ccb->proc_busy = true; 393 394 /* build and queue discover req */ 395 avdt_msg_send_cmd(p_ccb, NULL, AVDT_SIG_DISCOVER, NULL); 396} 397 398/******************************************************************************* 399 * 400 * Function avdt_ccb_snd_discover_rsp 401 * 402 * Description This function is called to send a discover response to 403 * the peer. It takes the stream information passed in the 404 * event and sends a discover response. 405 * 406 * 407 * Returns void. 408 * 409 ******************************************************************************/ 410void avdt_ccb_snd_discover_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 411 /* send response */ 412 avdt_msg_send_rsp(p_ccb, AVDT_SIG_DISCOVER, &p_data->msg); 413} 414 415/******************************************************************************* 416 * 417 * Function avdt_ccb_snd_getcap_cmd 418 * 419 * Description This function is called to send a get capabilities command 420 * to the peer. It copies variables needed for the procedure 421 * from the event to the CCB. It marks the CCB as busy and 422 * then sends a get capabilities command. 423 * 424 * 425 * Returns void. 426 * 427 ******************************************************************************/ 428void avdt_ccb_snd_getcap_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 429 uint8_t sig_id = AVDT_SIG_GETCAP; 430 431 /* store info in ccb struct */ 432 p_ccb->p_proc_data = p_data->getcap.p_cfg; 433 p_ccb->proc_cback = p_data->getcap.p_cback; 434 435 /* we're busy */ 436 p_ccb->proc_busy = true; 437 438 /* build and queue discover req */ 439 if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP) 440 sig_id = AVDT_SIG_GET_ALLCAP; 441 442 avdt_msg_send_cmd(p_ccb, NULL, sig_id, (tAVDT_MSG*)&p_data->getcap.single); 443} 444 445/******************************************************************************* 446 * 447 * Function avdt_ccb_snd_getcap_rsp 448 * 449 * Description This function is called to send a get capabilities response 450 * to the peer. It takes the stream information passed in the 451 * event and sends a get capabilities response. 452 * 453 * 454 * Returns void. 455 * 456 ******************************************************************************/ 457void avdt_ccb_snd_getcap_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 458 uint8_t sig_id = AVDT_SIG_GETCAP; 459 460 if (p_data->msg.hdr.sig_id == AVDT_SIG_GET_ALLCAP) 461 sig_id = AVDT_SIG_GET_ALLCAP; 462 463 /* send response */ 464 avdt_msg_send_rsp(p_ccb, sig_id, &p_data->msg); 465} 466 467/******************************************************************************* 468 * 469 * Function avdt_ccb_snd_start_cmd 470 * 471 * Description This function is called to send a start command to the 472 * peer. It verifies that all requested streams are in the 473 * proper state. If so, it sends a start command. Otherwise 474 * send ourselves back a start reject. 475 * 476 * 477 * Returns void. 478 * 479 ******************************************************************************/ 480void avdt_ccb_snd_start_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 481 int i; 482 tAVDT_SCB* p_scb; 483 tAVDT_MSG avdt_msg; 484 uint8_t seid_list[AVDT_NUM_SEPS]; 485 486 AVDT_TRACE_DEBUG("%s", __func__); 487 488 /* make copy of our seid list */ 489 memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); 490 491 /* verify all streams in the right state */ 492 avdt_msg.hdr.err_param = 493 avdt_scb_verify(p_ccb, AVDT_VERIFY_OPEN, p_data->msg.multi.seid_list, 494 p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code); 495 if (avdt_msg.hdr.err_param == 0) { 496 AVDT_TRACE_DEBUG("%s: AVDT_SIG_START", __func__); 497 498 /* set peer seid list in messsage */ 499 avdt_scb_peer_seid_list(&p_data->msg.multi); 500 501 /* send command */ 502 avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_START, &p_data->msg); 503 } else { 504 /* failed; send ourselves a reject for each stream */ 505 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 506 p_scb = avdt_scb_by_hdl(seid_list[i]); 507 if (p_scb != NULL) { 508 AVDT_TRACE_DEBUG("%s: AVDT_SCB_MSG_START_REJ_EVT: i=%d", __func__, i); 509 tAVDT_SCB_EVT avdt_scb_evt; 510 avdt_scb_evt.msg.hdr = avdt_msg.hdr; 511 avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, &avdt_scb_evt); 512 } 513 } 514 } 515} 516 517/******************************************************************************* 518 * 519 * Function avdt_ccb_snd_start_rsp 520 * 521 * Description This function is called to send a start response to the 522 * peer. It takes the stream information passed in the event 523 * and sends a start response. Then it sends a start event 524 * to the SCB for each stream. 525 * 526 * 527 * Returns void. 528 * 529 ******************************************************************************/ 530void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 531 tAVDT_SCB* p_scb; 532 int i; 533 534 /* send response message */ 535 avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg); 536 537 /* send start event to each scb */ 538 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 539 p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]); 540 if (p_scb != NULL) { 541 avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL); 542 } 543 } 544} 545 546/******************************************************************************* 547 * 548 * Function avdt_ccb_snd_suspend_cmd 549 * 550 * Description This function is called to send a suspend command to the 551 * peer. It verifies that all requested streams are in the 552 * proper state. If so, it sends a suspend command. 553 * Otherwise it calls the callback function for each requested 554 * stream and sends a suspend confirmation with failure. 555 * 556 * 557 * Returns void. 558 * 559 ******************************************************************************/ 560void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 561 int i; 562 tAVDT_SCB* p_scb; 563 tAVDT_MSG avdt_msg; 564 uint8_t seid_list[AVDT_NUM_SEPS]; 565 566 /* make copy of our seid list */ 567 memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); 568 569 /* verify all streams in the right state */ 570 avdt_msg.hdr.err_param = 571 avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list, 572 p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code); 573 if (avdt_msg.hdr.err_param == 0) { 574 /* set peer seid list in messsage */ 575 avdt_scb_peer_seid_list(&p_data->msg.multi); 576 577 /* send command */ 578 avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg); 579 } else { 580 /* failed; send ourselves a reject for each stream */ 581 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 582 p_scb = avdt_scb_by_hdl(seid_list[i]); 583 if (p_scb != NULL) { 584 tAVDT_SCB_EVT avdt_scb_evt; 585 avdt_scb_evt.msg.hdr = avdt_msg.hdr; 586 avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, &avdt_scb_evt); 587 } 588 } 589 } 590} 591 592/******************************************************************************* 593 * 594 * Function avdt_ccb_snd_suspend_rsp 595 * 596 * Description This function is called to send a suspend response to the 597 * peer. It takes the stream information passed in the event 598 * and sends a suspend response. Then it sends a suspend event 599 * to the SCB for each stream. 600 * 601 * 602 * Returns void. 603 * 604 ******************************************************************************/ 605void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 606 tAVDT_SCB* p_scb; 607 int i; 608 609 /* send response message */ 610 avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); 611 612 /* send start event to each scb */ 613 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 614 p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]); 615 if (p_scb != NULL) { 616 avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL); 617 } 618 } 619} 620 621/******************************************************************************* 622 * 623 * Function avdt_ccb_clear_cmds 624 * 625 * Description This function is called when the signaling channel is 626 * closed to clean up any pending commands. For each pending 627 * command in the command queue, it frees the command and 628 * calls the application callback function indicating failure. 629 * Certain CCB variables are also initialized. 630 * 631 * 632 * Returns void. 633 * 634 ******************************************************************************/ 635void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 636 int i; 637 tAVDT_SCB* p_scb = &avdt_cb.scb[0]; 638 uint8_t err_code = AVDT_ERR_CONNECT; 639 640 /* clear the ccb */ 641 avdt_ccb_clear_ccb(p_ccb); 642 643 /* clear out command queue; this is a little tricky here; we need 644 ** to handle the case where there is a command on deck in p_curr_cmd, 645 ** plus we need to clear out the queue 646 */ 647 do { 648 /* we know p_curr_cmd = NULL after this */ 649 tAVDT_CCB_EVT avdt_ccb_evt; 650 avdt_ccb_evt.err_code = err_code; 651 avdt_ccb_cmd_fail(p_ccb, &avdt_ccb_evt); 652 653 /* set up next message */ 654 p_ccb->p_curr_cmd = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q); 655 656 } while (p_ccb->p_curr_cmd != NULL); 657 658 /* send a CC_CLOSE_EVT any active scbs associated with this ccb */ 659 for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { 660 if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { 661 avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL); 662 } 663 } 664} 665 666/******************************************************************************* 667 * 668 * Function avdt_ccb_cmd_fail 669 * 670 * Description This function is called when there is a response timeout. 671 * The currently pending command is freed and we fake a 672 * reject message back to ourselves. 673 * 674 * 675 * Returns void. 676 * 677 ******************************************************************************/ 678void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 679 tAVDT_MSG msg; 680 uint8_t evt; 681 tAVDT_SCB* p_scb; 682 683 if (p_ccb->p_curr_cmd != NULL) { 684 /* set up data */ 685 msg.hdr.err_code = p_data->err_code; 686 msg.hdr.err_param = 0; 687 msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); 688 689 /* pretend that we received a rej message */ 690 evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1]; 691 692 if (evt & AVDT_CCB_MKR) { 693 tAVDT_CCB_EVT avdt_ccb_evt; 694 avdt_ccb_evt.msg = msg; 695 avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR), &avdt_ccb_evt); 696 } else { 697 /* we get the scb out of the current cmd */ 698 p_scb = avdt_scb_by_hdl(*((uint8_t*)(p_ccb->p_curr_cmd + 1))); 699 if (p_scb != NULL) { 700 tAVDT_SCB_EVT avdt_scb_evt; 701 avdt_scb_evt.msg = msg; 702 avdt_scb_event(p_scb, evt, &avdt_scb_evt); 703 } 704 } 705 706 osi_free_and_reset((void**)&p_ccb->p_curr_cmd); 707 } 708} 709 710/******************************************************************************* 711 * 712 * Function avdt_ccb_free_cmd 713 * 714 * Description This function is called when a response is received for a 715 * currently pending command. The command is freed. 716 * 717 * 718 * Returns void. 719 * 720 ******************************************************************************/ 721void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 722 osi_free_and_reset((void**)&p_ccb->p_curr_cmd); 723} 724 725/******************************************************************************* 726 * 727 * Function avdt_ccb_cong_state 728 * 729 * Description This function is called to set the congestion state for 730 * the CCB. 731 * 732 * 733 * Returns void. 734 * 735 ******************************************************************************/ 736void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 737 p_ccb->cong = p_data->llcong; 738} 739 740/******************************************************************************* 741 * 742 * Function avdt_ccb_ret_cmd 743 * 744 * Description This function is called to retransmit the currently 745 * pending command. The retransmission count is incremented. 746 * If the count reaches the maximum number of retransmissions, 747 * the event is treated as a response timeout. 748 * 749 * 750 * Returns void. 751 * 752 ******************************************************************************/ 753void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 754 p_ccb->ret_count++; 755 if (p_ccb->ret_count == AVDT_RET_MAX) { 756 /* command failed */ 757 p_ccb->ret_count = 0; 758 tAVDT_CCB_EVT avdt_ccb_evt; 759 avdt_ccb_evt.err_code = AVDT_ERR_TIMEOUT; 760 avdt_ccb_cmd_fail(p_ccb, &avdt_ccb_evt); 761 762 /* go to next queued command */ 763 avdt_ccb_snd_cmd(p_ccb, p_data); 764 } else { 765 /* if command pending and we're not congested and not sending a fragment */ 766 if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && 767 (p_ccb->p_curr_cmd != NULL)) { 768 /* make copy of message in p_curr_cmd and send it */ 769 BT_HDR* p_msg = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE); 770 memcpy(p_msg, p_ccb->p_curr_cmd, 771 (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + 772 p_ccb->p_curr_cmd->len)); 773 avdt_msg_send(p_ccb, p_msg); 774 } 775 776 /* restart ret timer */ 777 alarm_cancel(p_ccb->idle_ccb_timer); 778 alarm_cancel(p_ccb->rsp_ccb_timer); 779 period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000; 780 alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms, 781 avdt_ccb_ret_ccb_timer_timeout, p_ccb); 782 } 783} 784 785/******************************************************************************* 786 * 787 * Function avdt_ccb_snd_cmd 788 * 789 * Description This function is called the send the next command, 790 * if any, in the command queue. 791 * 792 * 793 * Returns void. 794 * 795 ******************************************************************************/ 796void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 797 BT_HDR* p_msg; 798 799 /* do we have commands to send? send next command; make sure we're clear; 800 ** not congested, not sending fragment, not waiting for response 801 */ 802 if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && 803 (p_ccb->p_curr_cmd == NULL)) { 804 p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q); 805 if (p_msg != NULL) { 806 /* make a copy of buffer in p_curr_cmd */ 807 p_ccb->p_curr_cmd = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE); 808 memcpy(p_ccb->p_curr_cmd, p_msg, 809 (sizeof(BT_HDR) + p_msg->offset + p_msg->len)); 810 avdt_msg_send(p_ccb, p_msg); 811 } 812 } 813} 814 815/******************************************************************************* 816 * 817 * Function avdt_ccb_snd_msg 818 * 819 * Description 820 * 821 * 822 * Returns void. 823 * 824 ******************************************************************************/ 825void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 826 BT_HDR* p_msg; 827 828 /* if not congested */ 829 if (!p_ccb->cong) { 830 /* are we sending a fragmented message? continue sending fragment */ 831 if (p_ccb->p_curr_msg != NULL) { 832 avdt_msg_send(p_ccb, NULL); 833 } 834 /* do we have responses to send? send them */ 835 else if (!fixed_queue_is_empty(p_ccb->rsp_q)) { 836 while ((p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) { 837 if (avdt_msg_send(p_ccb, p_msg) == true) { 838 /* break out if congested */ 839 break; 840 } 841 } 842 } 843 844 /* do we have commands to send? send next command */ 845 avdt_ccb_snd_cmd(p_ccb, NULL); 846 } 847} 848 849/******************************************************************************* 850 * 851 * Function avdt_ccb_set_reconn 852 * 853 * Description This function is called to enable a reconnect attempt when 854 * a channel transitions from closing to idle state. It sets 855 * the reconn variable to true. 856 * 857 * 858 * Returns void. 859 * 860 ******************************************************************************/ 861void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 862 p_ccb->reconn = true; 863} 864 865/******************************************************************************* 866 * 867 * Function avdt_ccb_clr_reconn 868 * 869 * Description This function is called to clear the reconn variable. 870 * 871 * 872 * Returns void. 873 * 874 ******************************************************************************/ 875void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 876 p_ccb->reconn = false; 877} 878 879/******************************************************************************* 880 * 881 * Function avdt_ccb_chk_reconn 882 * 883 * Description This function is called to check if a reconnect attempt 884 * is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT 885 * to the CCB. If disabled, the CCB is deallocated. 886 * 887 * 888 * Returns void. 889 * 890 ******************************************************************************/ 891void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 892 if (p_ccb->reconn) { 893 p_ccb->reconn = false; 894 895 /* clear out ccb */ 896 avdt_ccb_clear_ccb(p_ccb); 897 898 /* clear out current command, if any */ 899 uint8_t err_code = AVDT_ERR_CONNECT; 900 tAVDT_CCB_EVT avdt_ccb_evt; 901 avdt_ccb_evt.err_code = err_code; 902 avdt_ccb_cmd_fail(p_ccb, &avdt_ccb_evt); 903 904 /* reopen the signaling channel */ 905 avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL); 906 } else { 907 avdt_ccb_ll_closed(p_ccb, NULL); 908 } 909} 910 911/******************************************************************************* 912 * 913 * Function avdt_ccb_chk_timer 914 * 915 * Description This function stops the CCB timer if the idle timer is 916 * running. 917 * 918 * 919 * Returns void. 920 * 921 ******************************************************************************/ 922void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 923 alarm_cancel(p_ccb->idle_ccb_timer); 924} 925 926/******************************************************************************* 927 * 928 * Function avdt_ccb_set_conn 929 * 930 * Description Set CCB variables associated with AVDT_ConnectReq(). 931 * 932 * 933 * Returns void. 934 * 935 ******************************************************************************/ 936void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 937 /* save callback */ 938 p_ccb->p_conn_cback = p_data->connect.p_cback; 939 940 /* set security level */ 941 BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, 942 p_data->connect.sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, 943 AVDT_CHAN_SIG); 944} 945 946/******************************************************************************* 947 * 948 * Function avdt_ccb_set_disconn 949 * 950 * Description Set CCB variables associated with AVDT_DisconnectReq(). 951 * 952 * 953 * Returns void. 954 * 955 ******************************************************************************/ 956void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 957 /* 958 AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x", 959 p_ccb->p_conn_cback, p_data->disconnect.p_cback); 960 */ 961 /* save callback */ 962 if (p_data->disconnect.p_cback) 963 p_ccb->p_conn_cback = p_data->disconnect.p_cback; 964} 965 966/******************************************************************************* 967 * 968 * Function avdt_ccb_do_disconn 969 * 970 * Description Do action associated with AVDT_DisconnectReq(). 971 * 972 * 973 * Returns void. 974 * 975 ******************************************************************************/ 976void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 977 /* clear any pending commands */ 978 avdt_ccb_clear_cmds(p_ccb, NULL); 979 980 /* close channel */ 981 avdt_ccb_chan_close(p_ccb, NULL); 982} 983 984/******************************************************************************* 985 * 986 * Function avdt_ccb_ll_closed 987 * 988 * Description Clear commands from and deallocate CCB. 989 * 990 * 991 * Returns void. 992 * 993 ******************************************************************************/ 994void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 995 tAVDT_CTRL_CBACK* p_cback; 996 tAVDT_CTRL avdt_ctrl; 997 998 /* clear any pending commands */ 999 avdt_ccb_clear_cmds(p_ccb, NULL); 1000 1001 /* save callback pointer, bd addr */ 1002 p_cback = p_ccb->p_conn_cback; 1003 if (!p_cback) p_cback = avdt_cb.p_conn_cback; 1004 RawAddress bd_addr = p_ccb->peer_addr; 1005 1006 /* dealloc ccb */ 1007 avdt_ccb_dealloc(p_ccb, NULL); 1008 1009 /* call callback */ 1010 if (p_cback) { 1011 avdt_ctrl.hdr.err_code = 0; 1012 (*p_cback)(0, &bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl); 1013 } 1014} 1015 1016/******************************************************************************* 1017 * 1018 * Function avdt_ccb_ll_opened 1019 * 1020 * Description Call callback on open. 1021 * 1022 * 1023 * Returns void. 1024 * 1025 ******************************************************************************/ 1026void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 1027 tAVDT_CTRL avdt_ctrl; 1028 1029 p_ccb->ll_opened = true; 1030 1031 if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdt_cb.p_conn_cback; 1032 1033 /* call callback */ 1034 if (p_ccb->p_conn_cback) { 1035 avdt_ctrl.hdr.err_code = 0; 1036 avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param; 1037 (*p_ccb->p_conn_cback)(0, &p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, 1038 &avdt_ctrl); 1039 } 1040} 1041