void AVDT_AbortReq(UINT8 handle) { AVDT_TRACE_ERROR("%s\n", __func__); tAVDT_SCB *p_scb = avdt_scb_by_hdl(handle); if (p_scb != NULL) { avdt_scb_event(p_scb, AVDT_SCB_API_ABORT_REQ_EVT, NULL); } else { AVDT_TRACE_ERROR("%s Improper SCB, can not abort the stream\n", __func__); } }
/******************************************************************************* ** ** Function AVDT_RemoveStream ** ** Description Remove a stream endpoint. This function is called when ** the application is no longer using a stream endpoint. ** If this function is called when the endpoint is connected ** the connection is closed and then the stream endpoint ** is removed. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_RemoveStream(UINT8 handle) { UINT16 result = AVDT_SUCCESS; tAVDT_SCB *p_scb; /* look up scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } else { /* send remove event to scb */ avdt_scb_event(p_scb, AVDT_SCB_API_REMOVE_EVT, NULL); } return result; }
/******************************************************************************* ** ** Function avdt_ccb_snd_suspend_rsp ** ** Description This function is called to send a suspend response to the ** peer. It takes the stream information passed in the event ** and sends a suspend response. Then it sends a suspend event ** to the SCB for each stream. ** ** ** Returns void. ** *******************************************************************************/ void avdt_ccb_snd_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) { tAVDT_SCB *p_scb; int i; /* send response message */ avdt_msg_send_rsp(p_ccb, AVDT_SIG_SUSPEND, &p_data->msg); /* send start event to each scb */ for (i = 0; i < p_data->msg.multi.num_seps; i++) { if ((p_scb = avdt_scb_by_hdl(p_data->msg.multi.seid_list[i])) != NULL) { avdt_scb_event(p_scb, AVDT_SCB_MSG_SUSPEND_CMD_EVT, NULL); } } }
/******************************************************************************* ** ** Function AVDT_CloseReq ** ** Description Close a stream endpoint. This stops the transfer of media ** packets and closes the transport channel associated with ** this stream endpoint. When the stream is closed, an ** AVDT_CLOSE_CFM_EVT is sent to the application via the ** control callback function for this handle. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_CloseReq(UINT8 handle) { tAVDT_SCB *p_scb; UINT16 result = AVDT_SUCCESS; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } else /* send event to scb */ { avdt_scb_event(p_scb, AVDT_SCB_API_CLOSE_REQ_EVT, NULL); } return result; }
/******************************************************************************* ** ** Function AVDT_SecurityReq ** ** Description Send a security request to the peer device. When the ** security procedure is completed, an AVDT_SECURITY_CFM_EVT ** is sent to the application via the control callback function ** for this handle. (Please note that AVDTP security procedures ** are unrelated to Bluetooth link level security.) ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_SecurityReq(UINT8 handle, UINT8 *p_data, UINT16 len) { tAVDT_SCB *p_scb; UINT16 result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } /* send event to scb */ else { evt.msg.security_rsp.p_data = p_data; evt.msg.security_rsp.len = len; avdt_scb_event(p_scb, AVDT_SCB_API_SECURITY_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function avdt_ad_tc_cong_ind ** ** Description This function is called by the L2CAP interface layer when ** L2CAP calls the congestion callback. It looks up the CCB ** or SCB for the channel and sends it a congestion event. ** The is_congested parameter is the same value passed by ** the L2CAP callback function. ** ** ** Returns Nothing. ** *******************************************************************************/ void avdt_ad_tc_cong_ind(tAVDT_TC_TBL *p_tbl, BOOLEAN is_congested) { tAVDT_CCB *p_ccb; tAVDT_SCB *p_scb; /* if signaling channel, notify ccb of congestion */ if (p_tbl->tcid == 0) { p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); avdt_ccb_event(p_ccb, AVDT_CCB_LL_CONG_EVT, (tAVDT_CCB_EVT *) &is_congested); } /* if media or other channel, notify scb that channel open */ else { /* look up scb in stream routing table by ccb, tcid */ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); if (p_scb != NULL) { avdt_scb_event(p_scb, AVDT_SCB_TC_CONG_EVT, (tAVDT_SCB_EVT *) &is_congested); } } }
/******************************************************************************* ** ** Function AVDT_DelayReport ** ** Description This functions sends a Delay Report to the peer device ** that is associated with a particular SEID. ** This function is called by SNK device. ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_DelayReport(UINT8 handle, UINT8 seid, UINT16 delay) { tAVDT_SCB *p_scb; UINT16 result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } else /* send event to scb */ { evt.apidelay.hdr.seid = seid; evt.apidelay.delay = delay; avdt_scb_event(p_scb, AVDT_SCB_API_DELAY_RPT_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function AVDT_ReconfigRsp ** ** Description Respond to a reconfigure request from the peer device. ** This function must be called if the application receives ** an AVDT_RECONFIG_IND_EVT through its control callback. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_ReconfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category) { tAVDT_SCB *p_scb; tAVDT_SCB_EVT evt; UINT16 result = AVDT_SUCCESS; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } /* send event to scb */ else { evt.msg.hdr.err_code = error_code; evt.msg.hdr.err_param = category; evt.msg.hdr.label = label; avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_RSP_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function AVDT_ReconfigReq ** ** Description Reconfigure a stream endpoint. This allows the application ** to change the codec or content protection capabilities of ** a stream endpoint after it has been opened. This function ** can only be called if the stream is opened but not started ** or if the stream has been suspended. When the procedure ** is completed, an AVDT_RECONFIG_CFM_EVT is sent to the ** application via the control callback function for this handle. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_ReconfigReq(UINT8 handle, tAVDT_CFG *p_cfg) { tAVDT_SCB *p_scb; UINT16 result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } /* send event to scb */ else { /* force psc_mask to zero */ p_cfg->psc_mask = 0; evt.msg.reconfig_cmd.p_cfg = p_cfg; avdt_scb_event(p_scb, AVDT_SCB_API_RECONFIG_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function AVDT_OpenReq ** ** Description This function initiates a connection to the AVDTP service ** on the peer device, if not already present, and connects ** to a stream endpoint on a peer device. When the connection ** is completed, an AVDT_OPEN_CFM_EVT is sent to the ** application via the control callback function for this handle. ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_OpenReq(UINT8 handle, BD_ADDR bd_addr, UINT8 seid, tAVDT_CFG *p_cfg) { tAVDT_CCB *p_ccb = NULL; tAVDT_SCB *p_scb = NULL; UINT16 result = AVDT_SUCCESS; tAVDT_SCB_EVT evt; BTTRC_AVDT_API0(AVDT_TRACE_API_OPEN_REQ); /* verify SEID */ if ((seid < AVDT_SEID_MIN) || (seid > AVDT_SEID_MAX)) { result = AVDT_BAD_PARAMS; } /* map handle to scb */ else if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } /* find channel control block for this bd addr; if none, allocate one */ else 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; } } /* send event to scb */ if (result == AVDT_SUCCESS) { evt.msg.config_cmd.hdr.seid = seid; evt.msg.config_cmd.hdr.ccb_idx = avdt_ccb_to_idx(p_ccb); evt.msg.config_cmd.int_seid = handle; evt.msg.config_cmd.p_cfg = p_cfg; avdt_scb_event(p_scb, AVDT_SCB_API_SETCONFIG_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function avdt_ccb_hdl_suspend_rsp ** ** Description This function is called when a suspend response or reject ** is received from the peer. Using the SEIDs stored in the ** current command message, it sends a suspend response or ** suspend reject event to each SCB associated with the command. ** ** ** ** Returns void. ** *******************************************************************************/ void avdt_ccb_hdl_suspend_rsp(tAVDT_CCB *p_ccb, tAVDT_CCB_EVT *p_data) { UINT8 event; int i; UINT8 *p; tAVDT_SCB *p_scb; /* determine rsp or rej event */ event = (p_data->msg.hdr.err_code == 0) ? AVDT_SCB_MSG_SUSPEND_RSP_EVT : AVDT_SCB_MSG_SUSPEND_REJ_EVT; /* get to where seid's are stashed in current cmd */ p = (UINT8 *)(p_ccb->p_curr_cmd + 1); /* little trick here; length of current command equals number of streams */ for (i = 0; i < p_ccb->p_curr_cmd->len; i++) { if ((p_scb = avdt_scb_by_hdl(p[i])) != NULL) { avdt_scb_event(p_scb, event, (tAVDT_SCB_EVT *) &p_data->msg); } } }
/******************************************************************************* ** ** Function AVDT_ConfigRsp ** ** Description Respond to a configure request from the peer device. This ** function must be called if the application receives an ** AVDT_CONFIG_IND_EVT through its control callback. ** ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_ConfigRsp(UINT8 handle, UINT8 label, UINT8 error_code, UINT8 category) { tAVDT_SCB *p_scb; tAVDT_SCB_EVT evt; UINT16 result = AVDT_SUCCESS; UINT8 event_code; BTTRC_AVDT_API0(AVDT_TRACE_API_CONFIG_RSP); /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } /* handle special case when this function is called but peer has not send ** a configuration cmd; ignore and return error result */ else if (!p_scb->in_use) { result = AVDT_BAD_HANDLE; } /* send event to scb */ else { evt.msg.hdr.err_code = error_code; evt.msg.hdr.err_param = category; evt.msg.hdr.label = label; if (error_code == 0) { event_code = AVDT_SCB_API_SETCONFIG_RSP_EVT; } else { event_code = AVDT_SCB_API_SETCONFIG_REJ_EVT; } avdt_scb_event(p_scb, event_code, &evt); } return result; }
/******************************************************************************* ** ** Function AVDT_WriteReqOpt ** ** 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_WriteReq(). If the applications calls ** AVDT_WriteReq() before it receives the event the packet ** will not be sent. The application may make its first call ** to AVDT_WriteReq() after it receives an AVDT_START_CFM_EVT ** or AVDT_START_IND_EVT. ** ** The application passes the packet using the BT_HDR structure. ** This structure is described in section 2.1. The offset ** field must be equal to or greater than AVDT_MEDIA_OFFSET ** (if NO_RTP is specified, L2CAP_MIN_OFFSET can be used). ** This allows enough space in the buffer for the L2CAP and ** AVDTP headers. ** ** The memory pointed to by p_pkt must be a GKI buffer ** allocated by the application. This buffer will be freed ** by the protocol stack; the application must not free ** this buffer. ** ** The opt parameter allows passing specific options like: ** - NO_RTP : do not add the RTP header to buffer ** ** Returns AVDT_SUCCESS if successful, otherwise error. ** *******************************************************************************/ UINT16 AVDT_WriteReqOpt(UINT8 handle, BT_HDR *p_pkt, UINT32 time_stamp, UINT8 m_pt, tAVDT_DATA_OPT_MASK opt) { tAVDT_SCB *p_scb; tAVDT_SCB_EVT evt; UINT16 result = AVDT_SUCCESS; /* map handle to scb */ if ((p_scb = avdt_scb_by_hdl(handle)) == NULL) { result = AVDT_BAD_HANDLE; } else { evt.apiwrite.p_buf = p_pkt; evt.apiwrite.time_stamp = time_stamp; evt.apiwrite.m_pt = m_pt; evt.apiwrite.opt = opt; #if AVDT_MULTIPLEXING == TRUE GKI_init_q (&evt.apiwrite.frag_q); #endif avdt_scb_event(p_scb, AVDT_SCB_API_WRITE_REQ_EVT, &evt); } return result; }
/******************************************************************************* ** ** Function avdt_ad_tc_open_ind ** ** Description This function is called by the L2CAP interface when ** the L2CAP channel is opened. It looks up the CCB or SCB ** for the channel and sends it an open event. ** ** ** Returns Nothing. ** *******************************************************************************/ void avdt_ad_tc_open_ind(tAVDT_TC_TBL *p_tbl) { tAVDT_CCB *p_ccb; tAVDT_SCB *p_scb; tAVDT_OPEN open; tAVDT_EVT_HDR evt; p_tbl->state = AVDT_AD_ST_OPEN; /* if signaling channel, notify ccb that channel open */ if (p_tbl->tcid == 0) { /* set the signal channel to use high priority within the ACL link */ L2CA_SetTxPriority(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][AVDT_CHAN_SIG].lcid, L2CAP_CHNL_PRIORITY_HIGH); p_ccb = avdt_ccb_by_idx(p_tbl->ccb_idx); /* use err_param to indicate the role of connection. * AVDT_ACP, if ACP */ evt.err_param = AVDT_INT; if (p_tbl->cfg_flags & AVDT_L2C_CFG_CONN_ACP) { evt.err_param = AVDT_ACP; } avdt_ccb_event(p_ccb, AVDT_CCB_LL_OPEN_EVT, (tAVDT_CCB_EVT *)&evt); } /* if media or other channel, notify scb that channel open */ else { /* look up scb in stream routing table by ccb, tcid */ p_scb = avdt_scb_by_hdl(avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].scb_hdl); /* put lcid in event data */ if (p_scb != NULL) { open.peer_mtu = p_tbl->peer_mtu; open.lcid = avdt_cb.ad.rt_tbl[p_tbl->ccb_idx][p_tbl->tcid].lcid; open.hdr.err_code = avdt_ad_tcid_to_type(p_tbl->tcid); avdt_scb_event(p_scb, AVDT_SCB_TC_OPEN_EVT, (tAVDT_SCB_EVT *) &open); } } }
/******************************************************************************* ** ** Function avdt_process_timeout ** ** Description This function is called by BTU when an AVDTP timer ** expires. The function sends a timer event to the ** appropriate CCB or SCB state machine. ** ** This function is for use internal to the stack only. ** ** ** Returns void ** *******************************************************************************/ void avdt_process_timeout(TIMER_LIST_ENT *p_tle) { UINT8 event = 0; UINT8 err_code = AVDT_ERR_TIMEOUT; switch (p_tle->event) { case BTU_TTYPE_AVDT_CCB_RET: event = AVDT_CCB_RET_TOUT_EVT + AVDT_CCB_MKR; break; case BTU_TTYPE_AVDT_CCB_RSP: event = AVDT_CCB_RSP_TOUT_EVT + AVDT_CCB_MKR; break; case BTU_TTYPE_AVDT_CCB_IDLE: event = AVDT_CCB_IDLE_TOUT_EVT + AVDT_CCB_MKR; break; case BTU_TTYPE_AVDT_SCB_TC: event = AVDT_SCB_TC_TOUT_EVT; break; default: break; } if (event & AVDT_CCB_MKR) { avdt_ccb_event((tAVDT_CCB *) p_tle->param, (UINT8) (event & ~AVDT_CCB_MKR), (tAVDT_CCB_EVT *) &err_code); } else { avdt_scb_event((tAVDT_SCB *) p_tle->param, event, NULL); } }
/******************************************************************************* ** ** 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. ** *******************************************************************************/ AVDT_API 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; BTTRC_AVDT_API1(AVDT_TRACE_API_WRITE_DATA_REQ, BTTRC_PARAM_UINT32, data_len); 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_WARNING1("mux_tsid_media:%d", 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_WARNING4("p_scb->p_pkt=%x, p_scb->p_ccb=%x, IsQueueEmpty=%x, p_scb->frag_off=%x", 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_WARNING0("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_WARNING1("*** AVDT_WriteDataReq failed result=%d",result); } #endif return result; }