avdt_ccb_act.cc revision be8bbd7a83ec8bc900fac58a03010fbcb74956c9
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 avdt_scb_event(p_scb, AVDT_SCB_MSG_START_REJ_EVT, 510 (tAVDT_SCB_EVT*)&avdt_msg.hdr); 511 } 512 } 513 } 514} 515 516/******************************************************************************* 517 * 518 * Function avdt_ccb_snd_start_rsp 519 * 520 * Description This function is called to send a start response to the 521 * peer. It takes the stream information passed in the event 522 * and sends a start response. Then it sends a start event 523 * to the SCB for each stream. 524 * 525 * 526 * Returns void. 527 * 528 ******************************************************************************/ 529void avdt_ccb_snd_start_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 530 tAVDT_SCB* p_scb; 531 int i; 532 533 /* send response message */ 534 avdt_msg_send_rsp(p_ccb, AVDT_SIG_START, &p_data->msg); 535 536 /* send start event to each scb */ 537 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 538 p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]); 539 if (p_scb != NULL) { 540 avdt_scb_event(p_scb, AVDT_SCB_MSG_START_CMD_EVT, NULL); 541 } 542 } 543} 544 545/******************************************************************************* 546 * 547 * Function avdt_ccb_snd_suspend_cmd 548 * 549 * Description This function is called to send a suspend command to the 550 * peer. It verifies that all requested streams are in the 551 * proper state. If so, it sends a suspend command. 552 * Otherwise it calls the callback function for each requested 553 * stream and sends a suspend confirmation with failure. 554 * 555 * 556 * Returns void. 557 * 558 ******************************************************************************/ 559void avdt_ccb_snd_suspend_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 560 int i; 561 tAVDT_SCB* p_scb; 562 tAVDT_MSG avdt_msg; 563 uint8_t seid_list[AVDT_NUM_SEPS]; 564 565 /* make copy of our seid list */ 566 memcpy(seid_list, p_data->msg.multi.seid_list, p_data->msg.multi.num_seps); 567 568 /* verify all streams in the right state */ 569 avdt_msg.hdr.err_param = 570 avdt_scb_verify(p_ccb, AVDT_VERIFY_STREAMING, p_data->msg.multi.seid_list, 571 p_data->msg.multi.num_seps, &avdt_msg.hdr.err_code); 572 if (avdt_msg.hdr.err_param == 0) { 573 /* set peer seid list in messsage */ 574 avdt_scb_peer_seid_list(&p_data->msg.multi); 575 576 /* send command */ 577 avdt_msg_send_cmd(p_ccb, seid_list, AVDT_SIG_SUSPEND, &p_data->msg); 578 } else { 579 /* failed; send ourselves a reject for each stream */ 580 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 581 p_scb = avdt_scb_by_hdl(seid_list[i]); 582 if (p_scb != NULL) { 583 avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_REJ_EVT, 584 (tAVDT_SCB_EVT*)&avdt_msg.hdr); 585 } 586 } 587 } 588} 589 590/******************************************************************************* 591 * 592 * Function avdt_ccb_snd_suspend_rsp 593 * 594 * Description This function is called to send a suspend response to the 595 * peer. It takes the stream information passed in the event 596 * and sends a suspend response. Then it sends a suspend event 597 * to the SCB for each stream. 598 * 599 * 600 * Returns void. 601 * 602 ******************************************************************************/ 603void avdt_ccb_snd_suspend_rsp(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 604 tAVDT_SCB* p_scb; 605 int i; 606 607 /* send response message */ 608 avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); 609 610 /* send start event to each scb */ 611 for (i = 0; i < p_data->msg.multi.num_seps; i++) { 612 p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i]); 613 if (p_scb != NULL) { 614 avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL); 615 } 616 } 617} 618 619/******************************************************************************* 620 * 621 * Function avdt_ccb_clear_cmds 622 * 623 * Description This function is called when the signaling channel is 624 * closed to clean up any pending commands. For each pending 625 * command in the command queue, it frees the command and 626 * calls the application callback function indicating failure. 627 * Certain CCB variables are also initialized. 628 * 629 * 630 * Returns void. 631 * 632 ******************************************************************************/ 633void avdt_ccb_clear_cmds(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 634 int i; 635 tAVDT_SCB* p_scb = &avdt_cb.scb[0]; 636 uint8_t err_code = AVDT_ERR_CONNECT; 637 638 /* clear the ccb */ 639 avdt_ccb_clear_ccb(p_ccb); 640 641 /* clear out command queue; this is a little tricky here; we need 642 ** to handle the case where there is a command on deck in p_curr_cmd, 643 ** plus we need to clear out the queue 644 */ 645 do { 646 /* we know p_curr_cmd = NULL after this */ 647 avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code); 648 649 /* set up next message */ 650 p_ccb->p_curr_cmd = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q); 651 652 } while (p_ccb->p_curr_cmd != NULL); 653 654 /* send a CC_CLOSE_EVT any active scbs associated with this ccb */ 655 for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { 656 if ((p_scb->allocated) && (p_scb->p_ccb == p_ccb)) { 657 avdt_scb_event(p_scb, AVDT_SCB_CC_CLOSE_EVT, NULL); 658 } 659 } 660} 661 662/******************************************************************************* 663 * 664 * Function avdt_ccb_cmd_fail 665 * 666 * Description This function is called when there is a response timeout. 667 * The currently pending command is freed and we fake a 668 * reject message back to ourselves. 669 * 670 * 671 * Returns void. 672 * 673 ******************************************************************************/ 674void avdt_ccb_cmd_fail(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 675 tAVDT_MSG msg; 676 uint8_t evt; 677 tAVDT_SCB* p_scb; 678 679 if (p_ccb->p_curr_cmd != NULL) { 680 /* set up data */ 681 msg.hdr.err_code = p_data->err_code; 682 msg.hdr.err_param = 0; 683 msg.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); 684 685 /* pretend that we received a rej message */ 686 evt = avdt_msg_rej_2_evt[p_ccb->p_curr_cmd->event - 1]; 687 688 if (evt & AVDT_CCB_MKR) { 689 avdt_ccb_event(p_ccb, (uint8_t)(evt & ~AVDT_CCB_MKR), 690 (tAVDT_CCB_EVT*)&msg); 691 } else { 692 /* we get the scb out of the current cmd */ 693 p_scb = avdt_scb_by_hdl(*((uint8_t*)(p_ccb->p_curr_cmd + 1))); 694 if (p_scb != NULL) { 695 avdt_scb_event(p_scb, evt, (tAVDT_SCB_EVT*)&msg); 696 } 697 } 698 699 osi_free_and_reset((void**)&p_ccb->p_curr_cmd); 700 } 701} 702 703/******************************************************************************* 704 * 705 * Function avdt_ccb_free_cmd 706 * 707 * Description This function is called when a response is received for a 708 * currently pending command. The command is freed. 709 * 710 * 711 * Returns void. 712 * 713 ******************************************************************************/ 714void avdt_ccb_free_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 715 osi_free_and_reset((void**)&p_ccb->p_curr_cmd); 716} 717 718/******************************************************************************* 719 * 720 * Function avdt_ccb_cong_state 721 * 722 * Description This function is called to set the congestion state for 723 * the CCB. 724 * 725 * 726 * Returns void. 727 * 728 ******************************************************************************/ 729void avdt_ccb_cong_state(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 730 p_ccb->cong = p_data->llcong; 731} 732 733/******************************************************************************* 734 * 735 * Function avdt_ccb_ret_cmd 736 * 737 * Description This function is called to retransmit the currently 738 * pending command. The retransmission count is incremented. 739 * If the count reaches the maximum number of retransmissions, 740 * the event is treated as a response timeout. 741 * 742 * 743 * Returns void. 744 * 745 ******************************************************************************/ 746void avdt_ccb_ret_cmd(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 747 uint8_t err_code = AVDT_ERR_TIMEOUT; 748 749 p_ccb->ret_count++; 750 if (p_ccb->ret_count == AVDT_RET_MAX) { 751 /* command failed */ 752 p_ccb->ret_count = 0; 753 avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code); 754 755 /* go to next queued command */ 756 avdt_ccb_snd_cmd(p_ccb, p_data); 757 } else { 758 /* if command pending and we're not congested and not sending a fragment */ 759 if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && 760 (p_ccb->p_curr_cmd != NULL)) { 761 /* make copy of message in p_curr_cmd and send it */ 762 BT_HDR* p_msg = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE); 763 memcpy(p_msg, p_ccb->p_curr_cmd, 764 (sizeof(BT_HDR) + p_ccb->p_curr_cmd->offset + 765 p_ccb->p_curr_cmd->len)); 766 avdt_msg_send(p_ccb, p_msg); 767 } 768 769 /* restart ret timer */ 770 alarm_cancel(p_ccb->idle_ccb_timer); 771 alarm_cancel(p_ccb->rsp_ccb_timer); 772 period_ms_t interval_ms = avdt_cb.rcb.ret_tout * 1000; 773 alarm_set_on_mloop(p_ccb->ret_ccb_timer, interval_ms, 774 avdt_ccb_ret_ccb_timer_timeout, p_ccb); 775 } 776} 777 778/******************************************************************************* 779 * 780 * Function avdt_ccb_snd_cmd 781 * 782 * Description This function is called the send the next command, 783 * if any, in the command queue. 784 * 785 * 786 * Returns void. 787 * 788 ******************************************************************************/ 789void avdt_ccb_snd_cmd(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 790 BT_HDR* p_msg; 791 792 /* do we have commands to send? send next command; make sure we're clear; 793 ** not congested, not sending fragment, not waiting for response 794 */ 795 if ((!p_ccb->cong) && (p_ccb->p_curr_msg == NULL) && 796 (p_ccb->p_curr_cmd == NULL)) { 797 p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->cmd_q); 798 if (p_msg != NULL) { 799 /* make a copy of buffer in p_curr_cmd */ 800 p_ccb->p_curr_cmd = (BT_HDR*)osi_malloc(AVDT_CMD_BUF_SIZE); 801 memcpy(p_ccb->p_curr_cmd, p_msg, 802 (sizeof(BT_HDR) + p_msg->offset + p_msg->len)); 803 avdt_msg_send(p_ccb, p_msg); 804 } 805 } 806} 807 808/******************************************************************************* 809 * 810 * Function avdt_ccb_snd_msg 811 * 812 * Description 813 * 814 * 815 * Returns void. 816 * 817 ******************************************************************************/ 818void avdt_ccb_snd_msg(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 819 BT_HDR* p_msg; 820 821 /* if not congested */ 822 if (!p_ccb->cong) { 823 /* are we sending a fragmented message? continue sending fragment */ 824 if (p_ccb->p_curr_msg != NULL) { 825 avdt_msg_send(p_ccb, NULL); 826 } 827 /* do we have responses to send? send them */ 828 else if (!fixed_queue_is_empty(p_ccb->rsp_q)) { 829 while ((p_msg = (BT_HDR*)fixed_queue_try_dequeue(p_ccb->rsp_q)) != NULL) { 830 if (avdt_msg_send(p_ccb, p_msg) == true) { 831 /* break out if congested */ 832 break; 833 } 834 } 835 } 836 837 /* do we have commands to send? send next command */ 838 avdt_ccb_snd_cmd(p_ccb, NULL); 839 } 840} 841 842/******************************************************************************* 843 * 844 * Function avdt_ccb_set_reconn 845 * 846 * Description This function is called to enable a reconnect attempt when 847 * a channel transitions from closing to idle state. It sets 848 * the reconn variable to true. 849 * 850 * 851 * Returns void. 852 * 853 ******************************************************************************/ 854void avdt_ccb_set_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 855 p_ccb->reconn = true; 856} 857 858/******************************************************************************* 859 * 860 * Function avdt_ccb_clr_reconn 861 * 862 * Description This function is called to clear the reconn variable. 863 * 864 * 865 * Returns void. 866 * 867 ******************************************************************************/ 868void avdt_ccb_clr_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 869 p_ccb->reconn = false; 870} 871 872/******************************************************************************* 873 * 874 * Function avdt_ccb_chk_reconn 875 * 876 * Description This function is called to check if a reconnect attempt 877 * is enabled. If enabled, it sends an AVDT_CCB_UL_OPEN_EVT 878 * to the CCB. If disabled, the CCB is deallocated. 879 * 880 * 881 * Returns void. 882 * 883 ******************************************************************************/ 884void avdt_ccb_chk_reconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 885 uint8_t err_code = AVDT_ERR_CONNECT; 886 887 if (p_ccb->reconn) { 888 p_ccb->reconn = false; 889 890 /* clear out ccb */ 891 avdt_ccb_clear_ccb(p_ccb); 892 893 /* clear out current command, if any */ 894 avdt_ccb_cmd_fail(p_ccb, (tAVDT_CCB_EVT*)&err_code); 895 896 /* reopen the signaling channel */ 897 avdt_ccb_event(p_ccb, AVDT_CCB_UL_OPEN_EVT, NULL); 898 } else { 899 avdt_ccb_ll_closed(p_ccb, NULL); 900 } 901} 902 903/******************************************************************************* 904 * 905 * Function avdt_ccb_chk_timer 906 * 907 * Description This function stops the CCB timer if the idle timer is 908 * running. 909 * 910 * 911 * Returns void. 912 * 913 ******************************************************************************/ 914void avdt_ccb_chk_timer(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 915 alarm_cancel(p_ccb->idle_ccb_timer); 916} 917 918/******************************************************************************* 919 * 920 * Function avdt_ccb_set_conn 921 * 922 * Description Set CCB variables associated with AVDT_ConnectReq(). 923 * 924 * 925 * Returns void. 926 * 927 ******************************************************************************/ 928void avdt_ccb_set_conn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 929 /* save callback */ 930 p_ccb->p_conn_cback = p_data->connect.p_cback; 931 932 /* set security level */ 933 BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, 934 p_data->connect.sec_mask, AVDT_PSM, BTM_SEC_PROTO_AVDT, 935 AVDT_CHAN_SIG); 936} 937 938/******************************************************************************* 939 * 940 * Function avdt_ccb_set_disconn 941 * 942 * Description Set CCB variables associated with AVDT_DisconnectReq(). 943 * 944 * 945 * Returns void. 946 * 947 ******************************************************************************/ 948void avdt_ccb_set_disconn(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 949 /* 950 AVDT_TRACE_EVENT("avdt_ccb_set_disconn:conn:x%x, api:x%x", 951 p_ccb->p_conn_cback, p_data->disconnect.p_cback); 952 */ 953 /* save callback */ 954 if (p_data->disconnect.p_cback) 955 p_ccb->p_conn_cback = p_data->disconnect.p_cback; 956} 957 958/******************************************************************************* 959 * 960 * Function avdt_ccb_do_disconn 961 * 962 * Description Do action associated with AVDT_DisconnectReq(). 963 * 964 * 965 * Returns void. 966 * 967 ******************************************************************************/ 968void avdt_ccb_do_disconn(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 969 /* clear any pending commands */ 970 avdt_ccb_clear_cmds(p_ccb, NULL); 971 972 /* close channel */ 973 avdt_ccb_chan_close(p_ccb, NULL); 974} 975 976/******************************************************************************* 977 * 978 * Function avdt_ccb_ll_closed 979 * 980 * Description Clear commands from and deallocate CCB. 981 * 982 * 983 * Returns void. 984 * 985 ******************************************************************************/ 986void avdt_ccb_ll_closed(tAVDT_CCB* p_ccb, UNUSED_ATTR tAVDT_CCB_EVT* p_data) { 987 tAVDT_CTRL_CBACK* p_cback; 988 tAVDT_CTRL avdt_ctrl; 989 990 /* clear any pending commands */ 991 avdt_ccb_clear_cmds(p_ccb, NULL); 992 993 /* save callback pointer, bd addr */ 994 p_cback = p_ccb->p_conn_cback; 995 if (!p_cback) p_cback = avdt_cb.p_conn_cback; 996 RawAddress bd_addr = p_ccb->peer_addr; 997 998 /* dealloc ccb */ 999 avdt_ccb_dealloc(p_ccb, NULL); 1000 1001 /* call callback */ 1002 if (p_cback) { 1003 avdt_ctrl.hdr.err_code = 0; 1004 (*p_cback)(0, &bd_addr, AVDT_DISCONNECT_IND_EVT, &avdt_ctrl); 1005 } 1006} 1007 1008/******************************************************************************* 1009 * 1010 * Function avdt_ccb_ll_opened 1011 * 1012 * Description Call callback on open. 1013 * 1014 * 1015 * Returns void. 1016 * 1017 ******************************************************************************/ 1018void avdt_ccb_ll_opened(tAVDT_CCB* p_ccb, tAVDT_CCB_EVT* p_data) { 1019 tAVDT_CTRL avdt_ctrl; 1020 1021 p_ccb->ll_opened = true; 1022 1023 if (!p_ccb->p_conn_cback) p_ccb->p_conn_cback = avdt_cb.p_conn_cback; 1024 1025 /* call callback */ 1026 if (p_ccb->p_conn_cback) { 1027 avdt_ctrl.hdr.err_code = 0; 1028 avdt_ctrl.hdr.err_param = p_data->msg.hdr.err_param; 1029 (*p_ccb->p_conn_cback)(0, &p_ccb->peer_addr, AVDT_CONNECT_IND_EVT, 1030 &avdt_ctrl); 1031 } 1032} 1033