/******************************************************************************* ** ** Function AVDT_WriteDataReq ** ** Description Send a media packet to the peer device. The stream must ** be started before this function is called. Also, this ** function can only be called if the stream is a SRC. ** ** When AVDTP has sent the media packet and is ready for the ** next packet, an AVDT_WRITE_CFM_EVT is sent to the ** application via the control callback. The application must ** wait for the AVDT_WRITE_CFM_EVT before it makes the next ** call to AVDT_WriteDataReq(). If the applications calls ** AVDT_WriteDataReq() before it receives the event the packet ** will not be sent. The application may make its first call ** to AVDT_WriteDataReq() after it receives an ** AVDT_START_CFM_EVT or AVDT_START_IND_EVT. ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ extern UINT16 AVDT_WriteDataReq(UINT8 handle, UINT8 *p_data, UINT32 data_len, UINT32 time_stamp, UINT8 m_pt, UINT8 marker) { tAVDT_SCB *p_scb; tAVDT_SCB_EVT evt; UINT16 result = AVDT_SUCCESS; do { /* check length of media frame */ if (data_len > AVDT_MAX_MEDIA_SIZE) { result = AVDT_BAD_PARAMS; break; } /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; break; } AVDT_TRACE_WARNING("mux_tsid_media:%d\n", p_scb->curr_cfg.mux_tsid_media); if (p_scb->p_pkt != NULL || p_scb->p_ccb == NULL || !GKI_queue_is_empty(&p_scb->frag_q) || p_scb->frag_off != 0 || p_scb->curr_cfg.mux_tsid_media == 0) { result = AVDT_ERR_BAD_STATE; AVDT_TRACE_WARNING("p_scb->p_pkt=%p, p_scb->p_ccb=%p, IsQueueEmpty=%x, p_scb->frag_off=%x\n", p_scb->p_pkt, p_scb->p_ccb, GKI_queue_is_empty(&p_scb->frag_q), p_scb->frag_off); break; } evt.apiwrite.p_buf = 0; /* it will indicate using of fragments queue frag_q */ /* create queue of media fragments */ GKI_init_q (&evt.apiwrite.frag_q); /* compose fragments from media payload and put fragments into gueue */ avdt_scb_queue_frags(p_scb, &p_data, &data_len, &evt.apiwrite.frag_q); if (GKI_queue_is_empty(&evt.apiwrite.frag_q)) { AVDT_TRACE_WARNING("AVDT_WriteDataReq out of GKI buffers"); result = AVDT_ERR_RESOURCE; break; } evt.apiwrite.data_len = data_len; evt.apiwrite.p_data = p_data; /* process the fragments queue */ evt.apiwrite.time_stamp = time_stamp; evt.apiwrite.m_pt = m_pt | (marker << 7); avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); } while (0); #if (BT_USE_TRACES == TRUE) if (result != AVDT_SUCCESS) { AVDT_TRACE_WARNING("*** AVDT_WriteDataReq failed result=%d\n", result); } #endif return result; }
/******************************************************************************* ** ** Function AVDT_ConnectReq ** ** Description This function initiates an AVDTP signaling connection ** to the peer device. When the connection is completed, an ** AVDT_CONNECT_IND_EVT is sent to the application via its ** control callback function. If the connection attempt fails ** an AVDT_DISCONNECT_IND_EVT is sent. The security mask ** parameter overrides the outgoing security mask set in ** AVDT_Register(). ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_ConnectReq(BD_ADDR bd_addr, UINT8 sec_mask, tAVDT_CTRL_CBACK *p_cback) { tAVDT_CCB *p_ccb = NULL; UINT16 result = AVDT_SUCCESS; tAVDT_CCB_EVT evt; /* find channel control block for this bd addr; if none, allocate one */ if ((p_ccb = avdt_ccb_by_bd(bd_addr)) == NULL) { if ((p_ccb = avdt_ccb_alloc(bd_addr)) == NULL) { /* could not allocate channel control block */ result = AVDT_NO_RESOURCES; } } else if (p_ccb->ll_opened == FALSE) { AVDT_TRACE_WARNING("AVDT_ConnectReq: CCB LL is in the middle of opening"); /* ccb was already allocated for the incoming signalling. */ result = AVDT_BUSY; } if (result == AVDT_SUCCESS) { /* send event to ccb */ evt.connect.p_cback = p_cback; evt.connect.sec_mask = sec_mask; avdt_ccb_event(p_ccb, AVDT_CCB_API_CONNECT_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function avdt_scb_by_hdl ** ** Description Given an scb handle (or seid), return a pointer to the scb. ** ** ** Returns Pointer to scb or NULL if index is out of range or scb ** is not allocated. ** *******************************************************************************/ tAVDT_SCB *avdt_scb_by_hdl(UINT8 hdl) { tAVDT_SCB *p_scb; /* verify index */ if ((hdl > 0) && (hdl <= AVDT_NUM_SEPS)) { p_scb = &avdt_cb.scb[hdl - 1]; /* verify scb is allocated */ if (!p_scb->allocated) { p_scb = NULL; AVDT_TRACE_WARNING("scb hdl %d not allocated\n", hdl); } } else { p_scb = NULL; AVDT_TRACE_WARNING("scb hdl %d out of range\n", hdl); } return p_scb; }
/******************************************************************************* ** ** Function avdt_scb_alloc ** ** Description Allocate a stream control block. ** ** ** Returns pointer to the scb, or NULL if none could be allocated. ** *******************************************************************************/ tAVDT_SCB *avdt_scb_alloc(tAVDT_CS *p_cs) { tAVDT_SCB *p_scb = &avdt_cb.scb[0]; int i; /* find available scb */ for (i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { if (!p_scb->allocated) { memset(p_scb,0,sizeof(tAVDT_SCB)); p_scb->allocated = TRUE; p_scb->p_ccb = NULL; /* initialize sink as activated */ if (p_cs->tsep == AVDT_TSEP_SNK) { p_scb->sink_activated = TRUE; } memcpy(&p_scb->cs, p_cs, sizeof(tAVDT_CS)); #if AVDT_MULTIPLEXING == TRUE /* initialize fragments gueue */ GKI_init_q(&p_scb->frag_q); if(p_cs->cfg.psc_mask & AVDT_PSC_MUX) { p_scb->cs.cfg.mux_tcid_media = avdt_ad_type_to_tcid(AVDT_CHAN_MEDIA, p_scb); #if AVDT_REPORTING == TRUE if(p_cs->cfg.psc_mask & AVDT_PSC_REPORT) { p_scb->cs.cfg.mux_tcid_report = avdt_ad_type_to_tcid(AVDT_CHAN_REPORT, p_scb); } #endif } #endif p_scb->timer_entry.param = (UINT32) p_scb; AVDT_TRACE_DEBUG("avdt_scb_alloc hdl=%d, psc_mask:0x%x", i+1, p_cs->cfg.psc_mask); break; } } if (i == AVDT_NUM_SEPS) { /* out of ccbs */ p_scb = NULL; AVDT_TRACE_WARNING("Out of scbs"); } return p_scb; }
/******************************************************************************* ** ** Function avdt_sec_check_complete_term ** ** Description The function called when Security Manager finishes ** verification of the service side connection ** ** Returns void ** *******************************************************************************/ static void avdt_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res) { tAVDT_CCB *p_ccb = NULL; tL2CAP_CFG_INFO cfg; tAVDT_TC_TBL *p_tbl; UNUSED(p_ref_data); AVDT_TRACE_DEBUG("avdt_sec_check_complete_term res: %d\n", res); if (!bd_addr) { AVDT_TRACE_WARNING("avdt_sec_check_complete_term: NULL BD_ADDR"); return; } p_ccb = avdt_ccb_by_bd(bd_addr); p_tbl = avdt_ad_tc_tbl_by_st(AVDT_CHAN_SIG, p_ccb, AVDT_AD_ST_SEC_ACP); if (p_tbl == NULL) { return; } if (res == BTM_SUCCESS) { /* Send response to the L2CAP layer. */ L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_OK, L2CAP_CONN_OK); /* store idx in LCID table, store LCID in routing table */ avdt_cb.ad.lcid_tbl[p_tbl->lcid - L2CAP_BASE_APPL_CID] = avdt_ad_tc_tbl_to_idx(p_tbl); avdt_cb.ad.rt_tbl[avdt_ccb_to_idx(p_ccb)][p_tbl->tcid].lcid = p_tbl->lcid; /* transition to configuration state */ p_tbl->state = AVDT_AD_ST_CFG; /* Send L2CAP config req */ memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO)); cfg.mtu_present = TRUE; cfg.mtu = p_tbl->my_mtu; cfg.flush_to_present = TRUE; cfg.flush_to = p_tbl->my_flush_to; L2CA_ConfigReq(p_tbl->lcid, &cfg); } else { L2CA_ConnectRsp (bd_addr, p_tbl->id, p_tbl->lcid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK); avdt_ad_tc_close_ind(p_tbl, L2CAP_CONN_SECURITY_BLOCK); } }